TweetFollow Us on Twitter

Kolorize
Volume Number:7
Issue Number:6
Column Tag:C Workshop

Related Info: Color Quickdraw

Kolorize Your B&W Application

By Kirk Chase, Anaheim, CA

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

Introduction

The introduction of the Mac II brought color to release the user from the shackles of boring black and white displays. Now the user could use color to hilight, to draw, and to entertain. His spreadsheets could now show that he was in the “red”; his text could be hilighted in yellow; and his desktop could be blue as the sky.

What color brought to the developer was headaches. Palettes, color tables, and PixMaps were new structures to be learned and manipulated. Color images brought a tremendous increase in file and application sizes. Toolbox calls separated between color and non-color interfaces and had to be dealt with. Calibration of color between monitors and other output devices was, and still is, a great issue. And add to this the problem/feature of allowing the user to set the number of colors of the screen on the fly, and developers have their hands full. To deal with this problem, some developers have published a color and non-color version of their product rather than try to deal with the issues at the same time.

Dealing with color for most applications is not a great problem. Most applications do not need “animating palettes” or “32-bit Color QuickDraw”. Most applications need just a smidgen of color to liven up their displays (and sales) and to remove the stain of being “non-color” in the Mac world. Most applications are not paint or drawing programs. In fact, some applications require no user-interface at all and run “quietly” in the background.

Still, it would be nice to have a little color. For those who remain in the black & white world of programming, you may be asking yourself, “Is there something between the mouse of B&W coding and the elephant of color coding?” There is. You don’t have to eat the whole elephant at once. There is a middle ground to be found. It adds minimal code to your application, but it is not without its limitations.

The Macintosh Has ALWAYS Had Color

The word “classic” has been used to name the newest low-cost, low-end Macintosh computer line. The original “classic” QuickDraw has always had color ability. Within the Grafport are two fields, fgColor and bkColor, that controls the foreground color and background color through the toolbox calls ForeColor() and BackColor(), respectively. Also defined are eight colors (black, white, red, green, blue, cyan, magenta, and yellow).

The foreground color is initially set to black and the background color is initially set to white. By setting these colors before doing your drawing, you will get color drawing on all Macintoshes; the pen’s characteristics including pattern and mode work as they always do.

Drawback or Feature?

One thing to remember while drawing using the classic QuickDraw color model is the different monitor modes you will be in. The first instance is the black and white monitor; in this instance, all colors, except white, are drawn in black. This means that you should have white as either the background or foreground color; otherwise on B&W monitors you will have black on black drawing (great for displaying top secret information, but terrible otherwise).

A similar problem exists with color/monochrome monitors set to shallow color depths. For example, on my color monitor set at four colors (less than the eight colors of QuickDraw), green and blue appeared black; magenta and red were the same color; yellow appeared white, and cyan remained the same. In grayscale, the same problem existed with minor color variations due to the interpretation of color luminosity.

On top of this, there are a number of applications that change the color look-up table that describes the various RGB percentages which in turn change the color’s intensity. Also, different monitors have different values for colors. What this all means is that you can not depend on being able to distinguish, say, black from blue and yellow from white all the time.

I suppose you could check for the depth of the screen and values of the current colors. But this would mean going into all the things that you didn’t want to go into in the first place; you might as well use Color QuickDraw and its associated Toolbox managers. A better way to go is to do your drawing with black and white monitors in mind. This means keeping white as either the foreground or background colors when using the other colors. Then, you should not depend on any color other than black and white being present; you should give consideration to the fact that black and white might be the only colors seen.

For example, let’s consider we are drawing a pair of dice for a game. We make the die green, the dots blue, the die’s outline black, and the dots’ outlines red. Regardless of whether you think this color combination is great, in black and white, it looks like a black blob. So you change the dots’ outlines to white so you can distinguish between the die and the dots. You may still have a problem because there may not be enough white outline to quickly distinguish the dots on a B&W monitor. You need to leave enough “white” space between colors to look okay in B&W. Another problem is the “colorful” screen that is chock full of colors. Neat, but in B&W it looks like a black hole.

These are the basics to classic Quickdraw. You only have eight colors. Make white either the foreground or background color. Plan for black and white displays.

Kolorize

Now that you’ve got the basics down of ol’ classic QuickDraw. There are a few things that you can do to step beyond this. I will talk about three things. The first is getting more colors than the standard eight. The second involves colorizing areas of the screen such as text. And the third involves colorizing controls. All these routines are found in the source listing Kolorize.c and .h.

More Colors

When you are on a black and white Mac, the only colors you get are black and white. Yet the desktop is gray and the scroll bars have a light-gray page region. Okay, they are not true colors but dithering patterns to make them appear to be a certain color (mainly a shade of gray).

Well, you can do the same thing with colors. The routine, PaintMixedRect(), takes a rectangle and a palette of four colors and paints a multi-color rectangle on the screen. If done correctly you can get gray using black and white, light green using green and yellow, turquoise using green and blue, brown using green and red, and many other colors using the standard colors.

PaintMixedRect() creates this illusion of many colors by using an array of four dithering patterns, oqdMask4[]. Each bit in each pattern is unique within the four patterns. If you were to stack the patterns on top of each other, combining them, you would get a solid, black pattern, and no bit would be used twice.

To paint a pattern, you pass an array of four colors and the rectangle to PaintMixedRect(). This routine sets the pen transfer mode to patOr. Then PaintMixedRect() loops through the four colors painting the rectangle using the i-th color and the i-th mask pattern. The first pass paints one quarter of the rectangle in the first color and then loops back to do the rest in the other colors and patterns. The reason the pen mode is set to patOr is so we don’t erase any of the pixels we previously drew.

The dithering pattern used has been created to put up a gray pattern if you pass black/white/black/white. If you pass black/white combinations in other orders you can get different patterns such as vertical stripes (black/black/white/white) or horizontal stripes (black/white/white/black). My pattern was hard coded, but you could create a different set of dithering patterns.

Colorizing a Rectangle

The routine Kolorize() turns all the black pixels in a rectangle to a single color. It does this by setting the forecolor to the color you pass in and then performing a CopyMask() call using the same rectangle as the mask for CopyMask(). What this does is re-paint that rectangle in the color you specify. By using the same rectangle as the mask, you assure that only the original, black pixels are redrawn and the original, white pixels are left alone.

Another routine, KolorizeMix(), takes Kolorize() and PaintMixRect() and combines them. It uses the dithering pattern to draw only portions of the black pixels in one of the colors you pass and then again for other colors and dithering patterns.

KolorizeMix() is a little trickier than Kolorize() and PaintMixedRect(). KolorizeMix() needs a couple of offscreen ports to do its job. Since the dithering, mask patterns may clear some bits, we need a copy of the original area, copyPort, we are working on and a work area, offPort. These port and bitmap manipulation routines are fairly standard and you can get the source for them almost anywhere.

KolorizeMix() first makes a copy of the area we wish to colorize. Then it enters a loop. First, it copies the copy onto the offscreen area. Second, with the i-th dithering mask and proper pen mode, it clears out all bits that are not in the i-th color. Finally, it sets the foreground color to the i-th color and does a CopyBits() call to transfer the bits to the screen; CopyBits() automatically does the colorizing for you!

Color in Control

With Kolorize(), you should be able to colorize any rectangular area--including controls. KolorizeCDEF() does just this for the standard button, checkbox, and radio control. Simply pass in the control handle, the control type, and the button and indicator color.

KolorizeCDEF() will first colorize the whole control in the button color using the control’s rectangle. Then depending on the type of control it is and whether the button and indicator colors are different, this routine will then kolorize the inside “x” of the checkbox or the “•” of the radio button.

Controls are different than normal areas on the screen. They are active, and respond to mouse clicks by hilighting themselves. The standard controls know nothing of your colorizing attempts. They simply draw and hilight the controls in black and white on a black and white screen. Therefore you need to re-colorize them in your screen update routine and after the control receives a mouse click. When the control is tracking the mouse (on a mouse click in a control), the control automatically is drawn/hilighted in black until the mouse button is released and you re-colorize. I do not find this “reverting to black” so terrible; it gives additional information on color screens that a mouse down was detected in a control and tracking is being done.

Conclusion

Kolorize.c and the techniques given in this article will allow anyone to add color to there interface. If you simply need a few colors, classic QuickDraw provides eight for you, and this article explains how to “squeeze” out a few more without too much extra work. Possible future enhancements would be differing dithering masks-perhaps eight instead of four, colorizing scroll bars or other control types, extending color tracking to controls, drawing TextEdit’s hilight in color, and there are a number of other directions you could take.

Remember, color using classic QuickDraw is very rudimentary. There are severe limitations such as the “any color on white or white on any color” problem and the “white space” problem. In no way am I suggesting you never use Color QuickDraw. Color QuickDraw provides a much richer environment for working with color. But, if your application is not “color intensive”, you can add that little bit of color without too many hassles with good, ol’ QuickDraw.

Listing:  OQDKolorize.h

/************************************/
/* OQDKolorize.h
 Prototypes for Offscreen.c */
/************************************/

extern Ptr NewBitMap(BitMap *bm, Rect *r);
extern void DisposBitMap(BitMap *bm);
extern GrafPtr NewOffScreen(Rect *theBounds);
extern void DisposOffScreen(GrafPtr offPort);
extern void KolorizeMix(Rect *theRect, int *pallete);
extern void Kolorize(Rect *theRect, int theColor);
extern void KolorizeCDEF(ControlHandle theControl, int type,
 int buttonColor, int indicatorColor);
extern void PaintMixedRect(Rect *theRect, int *pallete);
Listing:  OQDKolorize.c

/**************************
OQDKolorize.c
created by Kirk Chase 3/29/91
***************************/
#include "OQDKolorize.h"

#define NIL 0L

#pragma mark Information
/************************************/
/* routines:
 • Ptr NewBitMap(BitMap *bm, Rect *r);
 • void DisposBitMap(BitMap *bm);
 • GrafPtr NewOffScreen(Rect *theBounds);
 • void DisposOffScreen(GrafPtr offPort);
 • void KolorizeMix(Rect *theRect,int *pallete);
 • void Kolorize(Rect *theRect, int theColor);
 • void KolorizeCDEF(ControlHandle theControl, int type,
 int buttonColor, int indicatorColor);
 • void void PaintMixedRect(Rect *theRect, int *pallete);
 */
/************************************/

/************************************/
/* OQDKolorize Variables */
Pattern oqdMask4[4] = 
 { 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00,
 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA, 0x00, 0xAA,
 0x00, 0x55, 0x00, 0x55, 0x00, 0x55, 0x00, 0x55,
 0x55, 0x00, 0x55, 0x00, 0x55, 0x00, 0x55, 0x00 };
/************************************/

/************************************/
/* Routines */
/************************************/

Ptr NewBitMap(bm, r)
BitMap *bm;
Rect *r;
/************************************/
/* Ptr NewBitMap()
 creates a bitmap */
/************************************/
{ /* NewBitMap() */
bm->rowBytes = ((r->right - r->left + 15) / 16) * 2;
bm->bounds = *r;
 /*  see note below */
bm->baseAddr = NewPtr(bm->rowBytes * (long) (r->right - r->left));
if (MemError() != noErr) return (0L);
else return (bm->baseAddr);
} /* NewBitMap() */

void DisposBitMap(bm)
BitMap *bm;
/************************************/
/* void DisposBitMap()
 disposes of a bitmap */
/************************************/
{ /* DisposBitMap() */
DisposPtr(bm->baseAddr);
SetRect(&bm->bounds,0,0,0,0);
bm->rowBytes=0;
bm->baseAddr=0L;
} /* DisposBitMap() */

GrafPtr NewOffScreen(theBounds)
Rect *theBounds;
/************************************/
/* GrafPtr NewOffScreen()
 creates an offscreen grafport */
/************************************/
{ /* NewOffScreen() */
GrafPtr oldPort, offPort;

/* allocate port memory */
offPort = (GrafPtr) NewPtr(sizeof(GrafPort));
if (MemError() != noErr)
 return (0L);

/* open port and set port variables */
GetPort(&oldPort);
OpenPort(offPort);
offPort->portRect = *theBounds;

/* create bitmap to store port's bits */
if (NewBitMap(&(offPort->portBits), theBounds) == (0L)) {
 ClosePort(offPort);
 SetPort(oldPort);
 DisposPtr((Ptr) offPort);
 return(0L);
 }

/* create necessary regions */
RectRgn(offPort->clipRgn, theBounds);
RectRgn(offPort->visRgn, theBounds);

/* clear bits to white */
EraseRect(theBounds);

/* reset back to original port */
SetPort(oldPort);

/* return offscreen port */
return(offPort);
} /* NewOffScreen() */

void DisposOffScreen(offPort)
GrafPtr offPort;
/************************************/
/* void DisposOffScreen()
 destroys an offscreen grafport */
/************************************/
{ /* DisposOffScreen() */
ClosePort(offPort);
DisposBitMap(&(offPort->portBits));
DisposPtr((Ptr) offPort);
} /* DisposOffScreen() */

void KolorizeMix(theRect, pallete)
Rect *theRect;
int *pallete;
/************************************/
/* void KolorizeMix(theRect, pallete)
 given a rectangle and pallete of  
 4 OQD colors, colorize rectangle */
/************************************/
{
GrafPtr offScreen, oldPort, copyPort;
int i;
PenState oldPen;

/* save old values */
GetPenState(&oldPen);
GetPort(&oldPort);

/* create offscreen ports for kolorizing */
offScreen = NewOffScreen(theRect);
if (offScreen == NIL) return;
copyPort = NewOffScreen(theRect);
if (copyPort == NIL) return;

SetPort(offScreen); /* do work on offscreen */

/* Copy only significant bits (black pixels)
 by using the same bits we wish to copy
 as the mask to the copyPort to work with later */
CopyMask(&(oldPort->portBits), &(oldPort->portBits), &(copyPort->portBits),
 theRect, theRect, theRect);

EraseRect(theRect);
/* Set Proper Pen Mode to clear bits */
for (i=0; i<4; i++) { /* loop through colors/masks */
 CopyMask(&(copyPort->portBits), &(copyPort->portBits), &(offScreen->portBits),
 theRect, theRect, theRect); /* place original copy in off screen */
 
 PenMode(notPatBic);  /* paint with ith pattern */
 PenPat(&(oqdMask4[i]));
 PaintRect(theRect);
 
 PenMode(patCopy);
 ForeColor(pallete[i]); /* kolorize with ith color */
 CopyBits (&(offScreen->portBits),&(oldPort->portBits), theRect,theRect, 
srcOr, 0L);
 ForeColor(blackColor);
 }

/* reset old values */  
SetPort(oldPort);
ForeColor(blackColor);
SetPenState(&oldPen);

/* dispose of memory */
DisposOffScreen(offScreen);
DisposOffScreen(copyPort);
} /* KolorizeMix() */

void Kolorize(theRect, theColor)
Rect *theRect;
int theColor;
/************************************/
/* void Kolorize()
 given a rectangle and an OQDcolor  
 colorize a rectangle */
/************************************/
{
/* set forecolor to color selected */
ForeColor(theColor);

/* kolorize */
CopyMask(&(thePort->portBits), &(thePort->portBits), &(thePort->portBits), 
theRect, theRect, theRect);
ForeColor(blackColor); /* reset */
} /* Kolorize() */

void KolorizeCDEF(theControl, type, buttonColor, indicatorColor)
ControlHandle theControl;
int type;
int buttonColor, indicatorColor;
/************************************/
/* void KolorizeCDEF()
 given a standard control (button,
 radio, or checkbox determined by
 proc type in type parameter) this
 will colorize the button and the
 indicator */
/************************************/
{
Rect tempRect;
PenState oldPen;

/* get old values and set up normal pen */
GetPenState(&oldPen);
PenNormal();

/* colorize whole control with button color */
ForeColor(buttonColor);
CopyMask(&(thePort->portBits), &(thePort->portBits), &(thePort->portBits), 

 &(**theControl).contrlRect,
 &(**theControl).contrlRect,
 &(**theControl).contrlRect);
ForeColor(blackColor);

/* if indicator color is the same
 as the button color, or it's a button
 or it's not set, then we're done */
if ((buttonColor == indicatorColor) 
 || (!type)
 || (!GetCtlValue(theControl))) { /* simple colorizing */
 SetPenState(&oldPen);
 return;
 }

/* not done, need to draw indicator */
/* get initial indicator rect */
tempRect = (**theControl).contrlRect;
tempRect.bottom = tempRect.bottom - ((tempRect.bottom - tempRect.top 
- 12) / 2);
tempRect.top = tempRect.bottom - 12;
tempRect.left +=2;
tempRect.right = tempRect.left + 12;

ForeColor(indicatorColor);
/* colorize checkbox or radio button */
if (type == checkBoxProc) {
 InsetRect(&tempRect, 1, 1);
 MoveTo(tempRect.left, tempRect.top);
 LineTo(tempRect.right, tempRect.bottom);
 MoveTo(tempRect.left , tempRect.bottom);
 LineTo(tempRect.right, tempRect.top - 1);
 }
else if (type == radioButProc) {
 InsetRect(&tempRect, 3, 3);
 PaintOval(&tempRect);
 }

/* reset old values */
SetPenState(&oldPen);
ForeColor(blackColor);
} /* KolorizeCDEF() */

void PaintMixedRect(theRect, pallete)
Rect *theRect;
int *pallete;
/************************************/
/* void PaintMixedRect()
 given a rectangle and a pallete of
 4 OQD colors, it paints a mixed
 rectangle to give the illusion
 of another color */
/************************************/
{
int i;
PenState oldPen;

/* get old states and set up pen */
GetPenState(&oldPen);
PenNormal();
PenMode(patOr);

/* paint ith pattern with ith color */
for (i=0; i<4; i++) {
 PenPat(&(oqdMask4[i]));
 ForeColor(pallete[i]);
 PaintRect(theRect);
 }

/* reset old values */
ForeColor(blackColor);
SetPenState(&oldPen);
} /* PaintMixedRect() */
Listing:  HandleTheMenus

/****************************************
File: HandleTheMenus
Function: Create and Handle any menus.
****************************************/
#define TRUE 1
#define FALSE 0

#define AppleMenuID 1001
#define FileMenuID 1002
 #define QuitItem 1
#define MixedMenuID 1003
 #define ThreeOneItem 1
 #define TwoTwoItem 2
 #define TwoOneOne 3
 #define OneOneOneOneItem 4
 #define MixColorItem 6

MenuHandle AppleMenu, FileMenu, MixedMenu;
int checkmark = 1;

/* External routines that are called */
extern int checkmark;
extern WindowPtr MyWindow;
extern void   D_Mixed_Colors();

void InitMyMenus(void);
void HandleMenu(char *doneFlag, short   theMenu, short   theItem);

void InitMyMenus()
/* InitMyMenus() gets the menu resources
 and creates the menu bar */
{
ClearMenuBar();
 
/* Apple menu */
AppleMenu = GetMenu(AppleMenuID);
InsertMenu (AppleMenu,0);
AddResMenu(AppleMenu,'DRVR');
 
/* File menu */
FileMenu = GetMenu(FileMenuID);
InsertMenu (FileMenu,0);
 
/* Mixed menu */
MixedMenu = GetMenu(MixedMenuID);
InsertMenu (MixedMenu,0);

DrawMenuBar();
}

void HandleMenu(doneFlag,theMenu,theItem)
char     *doneFlag; 
short   theMenu,theItem;
{
GrafPtr SavePort;
Str255 DAName;
short DNA;

switch (theMenu) {
 case AppleMenuID:
 GetPort(&SavePort);
 GetItem(AppleMenu, theItem, &DAName);
 DNA = OpenDeskAcc(DAName);
 SetPort(SavePort);
 break;

 case FileMenuID:
 if (theItem == QuitItem)
 *doneFlag = TRUE;
 break;
 
 case MixedMenuID:
 switch (theItem) {
 case ThreeOneItem:
 case TwoTwoItem:
 case TwoOneOne:
 case OneOneOneOneItem:
 CheckItem(MixedMenu, checkmark, 0);
 checkmark = theItem;
 CheckItem(MixedMenu, checkmark, 1);
 SetPort(MyWindow);
 InvalRect(&(MyWindow->portRect));
 break;
 case MixColorItem:
 D_Mixed_Colors();
 break;
 }
 break;
 }
 
HiliteMenu(0);
}
Listing: Mixed_Colors.c

/* *******************************
File: Mixed_Colors.c
 Handles color selection dialog
******************************* */

static pascal char MyFilter(DialogPtr theDialog
 ,EventRecord *theEvent,short *itemHit);

#define TRUE   1
#define FALSE  0
#define NIL 0L

#define  I_OK   1
#define  I_Cancel   2
#define  Item1stColor   3
#define  Item2ndColor   4
#define  Item3rdColor   5
#define  Item4thColor   6

extern int colorSelection[4];
extern WindowPtr MyWindow;

static char   ExitDialog; 

int oqdColors[9] = {0, 33, 30, 205, 341, 409, 273, 137, 69};

static int OQDIndex2Color(theIndex)
int theIndex;
/* convert menu selection to color */
{
return(oqdColors[theIndex]);
}

static int OQDColor2Index(theColor)
int theColor;
/* convert color to menu selection */
{
int i;

for (i=0; i<9; i++)
 if (oqdColors[i] == theColor) return(i);

return(0);
}

static pascal char  MyFilter (theDialog, theEvent, itemHit)
/* filter for drawing bold button */
DialogPtr   theDialog; 
EventRecord   *theEvent;
short  *itemHit; 
{
Rect    tempRect;
short    DType;
Handle    DItem;
PenState oldPen;

if (theEvent->what == updateEvt) { /* draw bold button */
 GetDItem(theDialog,I_OK, &DType, &DItem, &tempRect);
 GetPenState(&oldPen);
 PenSize(3, 3);
 InsetRect(&tempRect, -4, -4);
 FrameRoundRect(&tempRect, 16, 16); 
 SetPenState(&oldPen);
 }
return (FALSE);
} 
 
void   D_Mixed_Colors()
/* allows selection of colors for mixing */
{
DialogPtr    GetSelection;
Rect    tempRect;
short    DType;
Handle    DItem;
ControlHandle    CItem;
short    itemHit;

/* place dialog */
GetSelection = GetNewDialog(2, NIL, (WindowPtr)-1);
tempRect.top = GetSelection->portRect.top;
tempRect.left = GetSelection->portRect.left;
tempRect.bottom = GetSelection->portRect.bottom;
tempRect.right = GetSelection->portRect.right;
tempRect.top = ((screenBits.bounds.bottom - screenBits.bounds.top) - 
(tempRect.bottom - tempRect.top)) / 2;
tempRect.left = ((screenBits.bounds.right - screenBits.bounds.left) - 
(tempRect.right - tempRect.left)) / 2;
MoveWindow(GetSelection, tempRect.left, tempRect.top, TRUE);

/* set Pop-Up menus to color, uses Chris Faigle's PopUp CDEF */
GetDItem(GetSelection,Item1stColor, &DType,(Handle) &CItem, &tempRect);
SetCtlValue (CItem, OQDColor2Index(colorSelection[0]));
SetDItem(GetSelection,Item1stColor, DType,(Handle) CItem, &tempRect);

GetDItem(GetSelection,Item2ndColor, &DType,(Handle) &CItem, &tempRect);
SetCtlValue (CItem, OQDColor2Index(colorSelection[1]));
SetDItem(GetSelection,Item2ndColor, DType,(Handle) CItem, &tempRect);

GetDItem(GetSelection,Item3rdColor, &DType,(Handle) &CItem, &tempRect);
SetCtlValue (CItem, OQDColor2Index(colorSelection[2]));
SetDItem(GetSelection,Item3rdColor, DType,(Handle) CItem, &tempRect);

GetDItem(GetSelection,Item4thColor, &DType,(Handle) &CItem, &tempRect);
SetCtlValue (CItem, OQDColor2Index(colorSelection[3]));
SetDItem(GetSelection,Item4thColor, DType,(Handle) CItem, &tempRect);

ShowWindow(GetSelection);
SelectWindow(GetSelection);
SetPort(GetSelection);
  
ExitDialog = FALSE; 
 
do { /* dialog loop */
 ModalDialog(&MyFilter, &itemHit);
  
 if (itemHit == I_OK ) { /* get colors and quit */
 GetDItem(GetSelection,Item1stColor, &DType,(Handle) &CItem, &tempRect);
 colorSelection[0] = OQDIndex2Color(GetCtlValue(CItem));
 GetDItem(GetSelection,Item2ndColor, &DType,(Handle) &CItem, &tempRect);
 colorSelection[1] = OQDIndex2Color(GetCtlValue(CItem));
 GetDItem(GetSelection,Item3rdColor, &DType,(Handle) &CItem, &tempRect);
 colorSelection[2] = OQDIndex2Color(GetCtlValue(CItem));
 GetDItem(GetSelection,Item4thColor, &DType,(Handle) &CItem, &tempRect);
 colorSelection[3] = OQDIndex2Color(GetCtlValue(CItem));
 ExitDialog =TRUE;
 }
 
 if (itemHit == I_Cancel)
 ExitDialog =TRUE;
} while (ExitDialog == FALSE);
 
DisposDialog(GetSelection); 
SetPort(MyWindow);
InvalRect(&(MyWindow->portRect));
}
Listing: OQD_Test.h

/****************************************
File: OQD_Test.h
Function: Header for OQD_Test window.
History: 10/3/90 Original by Prototyper.  
****************************************/

extern  void  Init_OQD_Test(void);
extern  void  Close_OQD_Test(WindowPtr  whichWindow);
extern  void  Open_OQD_Test(void);
extern  void  UpDate_OQD_Test(WindowPtr  whichWindow);
extern  void  Do_OQD_Test(EventRecord  *myEvent);
Listing: OQD_Test.c

/*******************************
File: OQD_Test.c
Function: Handle OQD_Test window
*******************************/
#include "OQD_Test.h"
#include "OQDKolorize.h"
#include "String.h"

#define      TRUE   1
#define      FALSE  0
#define      NIL    0

static void  ClearRadioGroup(void);
static  void  DoCheckbox(ControlHandle theControl);
 
 /* *********************************** */
extern int checkmark;
extern int colorSelection[4];

/* Control IDs */
#define ButtonID 28
#define CheckboxID 30
#define Radio1ID 29
#define Radio2ID 31

WindowPtr MyWindow;
static ControlHandle theButton;
static ControlHandle theCheckbox;
static ControlHandle theRadio[3];
 
void  Init_OQD_Test()
/* initialize OQD_Test window */
{
MyWindow = NIL;
}

void  Close_OQD_Test(whichWindow)
/* dispose of OQD_Test window */
WindowPtr  whichWindow;
{
  
if ((MyWindow != NIL) && 
 ((MyWindow == whichWindow) || (whichWindow == (WindowPtr)-1))) {
 DisposeWindow(MyWindow); 
 MyWindow = NIL; 
 } 
}

void DrawTheRect(theRect, theColor)
Rect *theRect;
int theColor;
/* draws & frames rectangle with color */
{
FrameRect(theRect);
InsetRect(theRect, 1, 1);
ForeColor(theColor);
PaintRect(theRect);
ForeColor(blackColor);
}
void  UpDate_OQD_Test(whichWindow)
WindowPtr  whichWindow;
/* update window */
{
WindowPtr   SavePort;
Str255   sTemp;
Rect tempRect;
int pallete[4];
 
if ((MyWindow != NIL)  &&  (MyWindow == whichWindow)) {
 GetPort(&SavePort);
 SetPort(MyWindow);
 
 /* Draw solid color rectangles */
 SetRect(&tempRect, 20,40,80,100);
 DrawTheRect(&tempRect, blackColor);
 SetRect(&tempRect, 100,40,160,100);
 DrawTheRect(&tempRect, whiteColor);
 SetRect(&tempRect, 260,40,320,100);
 DrawTheRect(&tempRect, greenColor);
 SetRect(&tempRect, 180,40,240,100);
 DrawTheRect(&tempRect, redColor);
 SetRect(&tempRect, 260,140,320,200);
 DrawTheRect(&tempRect, yellowColor);
 SetRect(&tempRect, 180,140,240,200);
 DrawTheRect(&tempRect, magentaColor);
 SetRect(&tempRect, 100,140,160,200);
 DrawTheRect(&tempRect, cyanColor);
 SetRect(&tempRect, 20,140,80,200);
 DrawTheRect(&tempRect, blueColor);
 
 /* Draw Mixed rectangle according to percentages */
 SetRect(&tempRect, 360,100,420,160);
 FrameRect(&tempRect);
 InsetRect(&tempRect, 1, 1);
 switch (checkmark) {
 case 1: /* 75-25-0-0% of colorSelection */
 pallete[0] = pallete[1] = pallete[2] = colorSelection[0];
 pallete[3] = colorSelection[1];
 break;
 case 2: /* 50-50-0-0% of colorSelection */
 pallete[0] = pallete[1] = colorSelection[0];
 pallete[2] = pallete[3] = colorSelection[1];
 break;
 case 3: /* 50-25-25-0% of colorSelection */
 pallete[0] = pallete[1] = colorSelection[0];
 pallete[2] = colorSelection[1];
 pallete[3] = colorSelection[2];
 break;
 case 4: /* 25-25-25-25% of colorSelection */
 pallete[0] = colorSelection[0];
 pallete[1] = colorSelection[1];
 pallete[2] = colorSelection[2];
 pallete[3] = colorSelection[3];
 break;
 }
 PaintMixedRect(&tempRect, pallete);
 
 TextFont(systemFont);
 /* Draw titles */
 SetRect(&tempRect, 20,20,80,40);
 strcpy((char *)&sTemp,"\pBlack");
 TextBox(&sTemp[1], sTemp[0], &tempRect, teJustLeft);
 
 SetRect(&tempRect, 100,20,160,40);
 strcpy((char *)&sTemp,"\pWhite");
 TextBox(&sTemp[1], sTemp[0], &tempRect, teJustLeft);
 
 SetRect(&tempRect, 180,20,240,40);
 strcpy((char *)&sTemp,"\pRed");
 TextBox(&sTemp[1], sTemp[0], &tempRect, teJustLeft);
 
 SetRect(&tempRect, 20,120,80,140);
 strcpy((char *)&sTemp,"\pBlue");
 TextBox(&sTemp[1], sTemp[0], &tempRect, teJustLeft);
 
 SetRect(&tempRect, 260,20,320,40);
 strcpy((char *)&sTemp,"\pGreen");
 TextBox(&sTemp[1], sTemp[0], &tempRect, teJustLeft);
 
 SetRect(&tempRect, 100,120,160,140);
 strcpy((char *)&sTemp,"\pCyan");
 TextBox(&sTemp[1], sTemp[0], &tempRect, teJustLeft);
 
 SetRect(&tempRect, 180,120,240,140);
 strcpy((char *)&sTemp,"\pMagenta");
 TextBox(&sTemp[1], sTemp[0], &tempRect, teJustLeft);
 
 SetRect(&tempRect, 260,120,320,140);
 strcpy((char *)&sTemp,"\pYellow");
 TextBox(&sTemp[1], sTemp[0], &tempRect, teJustLeft);
 
 SetRect(&tempRect, 360,80,420,100);
 strcpy((char *)&sTemp,"\pMixed");
 TextBox(&sTemp[1], sTemp[0], &tempRect, teJustLeft);
 KolorizeMix(&tempRect, pallete);
 TextFont(applFont);
 
 DrawControls(MyWindow);
 
 KolorizeCDEF(theButton, pushButProc, cyanColor, cyanColor);
 
 if (GetCtlValue(theRadio[0]))
 KolorizeCDEF(theRadio[0], radioButProc, cyanColor, redColor);
 else
 KolorizeCDEF(theRadio[0], radioButProc, magentaColor, redColor);
 
 if (GetCtlValue(theRadio[1]))
 KolorizeCDEF(theRadio[1], radioButProc, cyanColor, redColor);
 else
 KolorizeCDEF(theRadio[1], radioButProc, magentaColor, redColor);
 
 KolorizeCDEF(theCheckbox, checkBoxProc, greenColor, redColor);
 SetPort(SavePort);
 }
}

void Open_OQD_Test(void)
/* open OQD_Test window */
{
Rect tempRect;

if (MyWindow == NIL) {
 MyWindow = GetNewWindow(1,NIL, (WindowPtr)-1);
 tempRect = MyWindow->portRect;
 tempRect.top = ((screenBits.bounds.bottom - screenBits.bounds.top) 
 - (tempRect.bottom - tempRect.top)) / 2 + 20;
 tempRect.left = ((screenBits.bounds.right - screenBits.bounds.left) 

 - (tempRect.right - tempRect.left)) / 2;
 
 MoveWindow(MyWindow, tempRect.left, tempRect.top, TRUE);
 SetPort(MyWindow);
 
 /* Make buttons */
 theButton = GetNewControl(ButtonID,MyWindow);
 theCheckbox = GetNewControl(CheckboxID,MyWindow);
 theRadio[0] = GetNewControl (Radio1ID, MyWindow);
 theRadio[1] = GetNewControl (Radio2ID, MyWindow);
 
 ShowWindow(MyWindow);
 SelectWindow(MyWindow);
 UpDate_OQD_Test(MyWindow);
 }
else
 SelectWindow(MyWindow);
}

static  void  DoCheckbox(theControl)
ControlHandle theControl;
/* handle setting and kolorizing push and radio buttons */
{
short theValue;

if (theControl == theCheckbox) { /* pushbutton */
 theValue = GetCtlValue(theControl);
 theValue = (theValue + 1) & 1;
 SetCtlValue(theControl, theValue);
 }
else { /* radio buttons */
 SetCtlValue(theRadio[0],0);
 SetCtlValue(theRadio[1],0);
 SetCtlValue(theControl, 1);
 }
}

void  Do_OQD_Test(myEvent)
/* handle mouse downs in controls */
EventRecord *myEvent;
{
short code;
WindowPtr whichWindow;
Point myPt;
ControlHandle theControl;

if (MyWindow != NIL) { /* make sure our window */
 code = FindWindow(myEvent->where, &whichWindow);
 
 /* see if mouse down */
 if ((myEvent->what == mouseDown)  &&  (MyWindow == whichWindow)) {
 myPt = myEvent->where;
 GlobalToLocal(&myPt);
 }
 
 /* see if control */
 if ((MyWindow == whichWindow) &&  (code == inContent)) {
 code = FindControl(myPt, whichWindow, &theControl);
 if (code != 0) 
 code = TrackControl(theControl,myPt, NIL);
 if (code == inButton) /* only 1 button - Kolorize */
 KolorizeCDEF(theButton, pushButProc, cyanColor, cyanColor);
 if (code == inCheckBox) /* handle pushbutton and radios */
 DoCheckbox(theControl);
 KolorizeCDEF(theButton, pushButProc, cyanColor, cyanColor);
 
 /* Kolorize radios and checkbox */
 if (GetCtlValue(theRadio[0]))
 KolorizeCDEF(theRadio[0], radioButProc, cyanColor, redColor);
 else
 KolorizeCDEF(theRadio[0], radioButProc, magentaColor, redColor);
 
 if (GetCtlValue(theRadio[1]))
 KolorizeCDEF(theRadio[1], radioButProc, cyanColor, redColor);
 else
 KolorizeCDEF(theRadio[1], radioButProc, magentaColor, redColor);
 
 KolorizeCDEF(theCheckbox, checkBoxProc, greenColor, redColor);
 }
 }
}
 Listing: OQD.c

/************************************
Program name:  OQD.c
Function:  Demos Old QuickDraw Color Tricks. 
************************************/

#include "OQD_Test.h"

#define      TRUE   1
#define      FALSE  0
#define      NIL    0

/* initial color selection */
int colorSelection[4] = { whiteColor, blackColor, whiteColor, blackColor};

/* external functions */
extern void InitMyMenus(void);
extern void HandleMenu(char *doneFlag, short theMenu, short theItem);

void main(void);

void main()
{
char doneFlag, ch;
short code, theMenu, theItem, chCode;
long mResult;
WindowPtr whichWindow;
EventRecord myEvent;
Rect tempRect;
GrafPtr SavePort;

/* initialize everything */
InitGraf(&thePort);
InitFonts();
FlushEvents(everyEvent,0);
InitWindows();
InitMenus();
TEInit();
InitDialogs(NIL);
InitCursor();
 
/* initialize my own stuff */
doneFlag = FALSE;
InitMyMenus();
Init_OQD_Test();
Open_OQD_Test();
 
do {
 SystemTask();
 
 if (GetNextEvent(everyEvent, &myEvent)) {
 code = FindWindow(myEvent.where, &whichWindow);   
 
 switch (myEvent.what) {
 case mouseDown:
 if (code == inMenuBar) {
 mResult = MenuSelect(myEvent.where);
 theMenu = HiWord(mResult);
 theItem = LoWord(mResult);
 HandleMenu(&doneFlag,theMenu,theItem);
 }
 
  if ((code == inDrag)&&(whichWindow != NIL)) {
 tempRect = screenBits.bounds;
 SetRect(&tempRect, tempRect.left + 10, tempRect.top + 25, tempRect.right 
- 10, tempRect.bottom - 10);
 DragWindow(whichWindow, myEvent.where, &tempRect);
 }
  
 if (code == inContent) {
 if (whichWindow != FrontWindow()) {
 SelectWindow(whichWindow);
 }
 else {
 SetPort(whichWindow);
 Do_OQD_Test (&myEvent);
 }
 }
 
 if (code == inSysWindow) {
 SystemClick(&myEvent, whichWindow);
 }
 
 break;
 
 case keyDown: 
 case autoKey: 
 ch = myEvent.message &  charCodeMask;
 if (myEvent.modifiers & cmdKey) {
 mResult = MenuKey(ch);
 theMenu = HiWord(mResult);
 theItem = LoWord(mResult);
 if (theMenu != 0) 
 HandleMenu(&doneFlag, theMenu, theItem); 
 }
 break;
 
 case updateEvt:
 whichWindow = (WindowPtr)myEvent.message;
 GetPort(&SavePort);
 BeginUpdate(whichWindow);
 SetPort(whichWindow);
 UpDate_OQD_Test(whichWindow);
 EndUpdate(whichWindow);
 SetPort(SavePort);
 break;
 
 case activateEvt:
 if ((whichWindow != NIL) && (myEvent.modifiers & activeFlag)) { 
 SelectWindow(whichWindow);
 }
 break;
 }
 
 }
 } while (doneFlag ==  FALSE);
}
Listing:  OQD.r

resource 'WIND' (1, "OQD Test") {
 {91, 66, 378, 511},
 noGrowDocProc,
 invisible,
 noGoAway,
 0x1,
 "OQD Test"
};

resource 'CNTL' (28, "Button") {
 {220, 20, 240, 100},
 0,
 16,
 1,
 0,
 pushButProc,
 28,
 "Button"
};

resource 'CNTL' (30, "Checkbox") {
 {220, 240, 235, 320},
 0,
 16,
 1,
 0,
 checkBoxProc,
 30,
 "Checkbox"
};

resource 'CNTL' (29, "Radio") {
 {220, 140, 235, 220},
 1,
 16,
 1,
 0,
 radioButProc,
 29,
 "Radio "
};

resource 'CNTL' (31, "Radio") {
 {240, 140, 255, 220},
 0,
 16,
 1,
 0,
 radioButProc,
 31,
 "Radio "
};

resource 'CNTL' (128, "Color:") {
 {20, 20, 40, 170},
 5,
 visible,
 8,
 1,
 81,
 51,
 "1st Color:"
};

resource 'CNTL' (129) {
 {50, 20, 70, 170},
 5,
 visible,
 8,
 1,
 81,
 52,
 "2nd Color:"
};

resource 'CNTL' (130) {
 {80, 20, 100, 170},
 8,
 visible,
 8,
 1,
 81,
 53,
 "3rd Color:"
};

resource 'CNTL' (131) {
 {110, 20, 130, 170},
 8,
 visible,
 8,
 1,
 81,
 54,
 "4th Color:"
};

resource 'MENU' (1001, "Std Menu - \0x14") {
 1001,
 textMenuProc,
 allEnabled,
 enabled,
 apple,
 { /* array: 0 elements */
 }
};

resource 'MENU' (1002, "Std Menu - File") {
 1002,
 textMenuProc,
 allEnabled,
 enabled,
 "File",
 { /* array: 1 elements */
 /* [1] */
 "Quit", noIcon, "Q", noMark, plain
 }
};

resource 'MENU' (1003, "Std Menu - Mixed") {
 1003,
 textMenuProc,
 0x7FFFFFEF,
 enabled,
 "Mixed",
 { /* array: 6 elements */
 /* [1] */
 "75-25%", noIcon, noKey, check, plain,
 /* [2] */
 "50-50%", noIcon, noKey, noMark, plain,
 /* [3] */
 "50-25-25%", noIcon, noKey, noMark, plain,
 /* [4] */
 "25-25-25-25%", noIcon, noKey, noMark, plain,
 /* [5] */
 "-", noIcon, noKey, noMark, plain,
 /* [6] */
 "Colors Mixed ", noIcon, noKey, noMark, plain
 }
};

resource 'MENU' (51, "Popup - Popup") {
 51,
 textMenuProc,
 allEnabled,
 enabled,
 "Color",
 { /* array: 8 elements */
 /* [1] */
 "Black", noIcon, noKey, noMark, plain,
 /* [2] */
 "White", noIcon, noKey, noMark, plain,
 /* [3] */
 "Red", noIcon, noKey, noMark, plain,
 /* [4] */
 "Green", noIcon, noKey, noMark, plain,
 /* [5] */
 "Blue", noIcon, noKey, noMark, plain,
 /* [6] */
 "Cyan", noIcon, noKey, noMark, plain,
 /* [7] */
 "Magenta", noIcon, noKey, noMark, plain,
 /* [8] */
 "Yellow", noIcon, noKey, noMark, plain
 }
};

resource 'MENU' (52, "Popup - Popup") {
 52,
 textMenuProc,
 allEnabled,
 enabled,
 "Popup",
 { /* array: 8 elements */
 /* [1] */
 "Black", noIcon, noKey, noMark, plain,
 /* [2] */
 "White", noIcon, noKey, noMark, plain,
 /* [3] */
 "Red", noIcon, noKey, noMark, plain,
 /* [4] */
 "Green", noIcon, noKey, noMark, plain,
 /* [5] */
 "Blue", noIcon, noKey, noMark, plain,
 /* [6] */
 "Cyan", noIcon, noKey, noMark, plain,
 /* [7] */
 "Magenta", noIcon, noKey, noMark, plain,
 /* [8] */
 "Yellow", noIcon, noKey, noMark, plain
 }
};

resource 'MENU' (53, "Popup - Popup") {
 53,
 textMenuProc,
 allEnabled,
 enabled,
 "Popup",
 { /* array: 8 elements */
 /* [1] */
 "Black", noIcon, noKey, noMark, plain,
 /* [2] */
 "White", noIcon, noKey, noMark, plain,
 /* [3] */
 "Red", noIcon, noKey, noMark, plain,
 /* [4] */
 "Green", noIcon, noKey, noMark, plain,
 /* [5] */
 "Blue", noIcon, noKey, noMark, plain,
 /* [6] */
 "Cyan", noIcon, noKey, noMark, plain,
 /* [7] */
 "Magenta", noIcon, noKey, noMark, plain,
 /* [8] */
 "Yellow", noIcon, noKey, noMark, plain
 }
};

resource 'MENU' (54, "Popup - Popup") {
 54,
 textMenuProc,
 allEnabled,
 enabled,
 "Popup",
 { /* array: 8 elements */
 /* [1] */
 "Black", noIcon, noKey, noMark, plain,
 /* [2] */
 "White", noIcon, noKey, noMark, plain,
 /* [3] */
 "Red", noIcon, noKey, noMark, plain,
 /* [4] */
 "Green", noIcon, noKey, noMark, plain,
 /* [5] */
 "Blue", noIcon, noKey, noMark, plain,
 /* [6] */
 "Cyan", noIcon, noKey, noMark, plain,
 /* [7] */
 "Magenta", noIcon, noKey, noMark, plain,
 /* [8] */
 "Yellow", noIcon, noKey, noMark, plain
 }
};

resource 'DLOG' (2, "Mixed Colors") {
 {139, 144, 321, 496},
 dBoxProc,
 invisible,
 noGoAway,
 0x2,
 2,
 "Mixed Colors"
};

resource 'DITL' (2, "Mixed Colors") {
 { /* array DITLarray: 6 elements */
 /* [1] */
 {140, 240, 166, 317},
 Button {
 enabled,
 "OK"
 },
 /* [2] */
 {20, 240, 46, 317},
 Button {
 enabled,
 "Cancel"
 },
 /* [3] */
 {20, 30, 40, 180},
 Control {
 enabled,
 128
 },
 /* [4] */
 {60, 30, 80, 180},
 Control {
 enabled,
 129
 },
 /* [5] */
 {100, 30, 120, 180},
 Control {
 enabled,
 130
 },
 /* [6] */
 {140, 30, 160, 180},
 Control {
 enabled,
 131
 }
 }
};

From Nov 91 Letters:

BitMap Error

Kirk Chase

MacTutor

I would like to point out an error in some code published in MacTutor, November 1990 ("Special Effect") and June 1991 ("Kolorize Your B&W Application"). Basically the code in question is the offscreen bitmap allocation function used in both articles. The offending line in the procedure NewBitMap is

bm->baseAddr=NewPtr(bm->rowBytes *(long (r->right - r->left));

This assumes a height the same size as the width. Correct it to the following:

bm->baseAddr=NewPtr(bm->rowBytes *(long (r->bottom - r->top));

Thanks to Randy Frank for pointing this out.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Tweetbot 2.5.3 - Popular Twitter client.
Tweetbot is a full-featured OS X Twitter client with a lot of personality. Whether it's the meticulously-crafted interface, sounds and animation, or features like multiple timelines and column views... Read more
Hopper Disassembler 4.2.19- - Binary dis...
Hopper Disassembler is a binary disassembler, decompiler, and debugger for 32- and 64-bit executables. It will let you disassemble any binary you want, and provide you all the information about its... Read more
Monosnap 3.4.0 - Versatile screenshot ut...
Monosnap lets you capture screenshots, share files, and record video and .gifs! Capture Capture full screen, just part of the screen, or a selected window Make your crop area pixel perfect with our... Read more
Duet 1.6.5.5 - Use your iPad as an exter...
Duet is the first app that allows you to use your iDevice as an extra display for your Mac using the Lightning or 30-pin cable. Note: This app requires a $14.99 iOS companion app. Version 1.6.5.5:... Read more
Hopper Disassembler 4.2.19- - Binary dis...
Hopper Disassembler is a binary disassembler, decompiler, and debugger for 32- and 64-bit executables. It will let you disassemble any binary you want, and provide you all the information about its... Read more
Duet 1.6.5.5 - Use your iPad as an exter...
Duet is the first app that allows you to use your iDevice as an extra display for your Mac using the Lightning or 30-pin cable. Note: This app requires a $14.99 iOS companion app. Version 1.6.5.5:... Read more
Monosnap 3.4.0 - Versatile screenshot ut...
Monosnap lets you capture screenshots, share files, and record video and .gifs! Capture Capture full screen, just part of the screen, or a selected window Make your crop area pixel perfect with our... Read more
Tweetbot 2.5.3 - Popular Twitter client.
Tweetbot is a full-featured OS X Twitter client with a lot of personality. Whether it's the meticulously-crafted interface, sounds and animation, or features like multiple timelines and column views... Read more
Default Folder X 5.1.6 - Enhances Open a...
Default Folder X attaches a toolbar to the right side of the Open and Save dialogs in any OS X-native application. The toolbar gives you fast access to various folders and commands. You just click on... Read more
Evernote 6.12.3 - Create searchable note...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more

The best new games we played this week -...
It's pretty much been one big release after another. We were privy to a bunch of surprises this week, with a lot of games we'd been waiting for quite some time dropping unexpectedly. We hope you're free this weekend, because there is a lot for... | Read more »
Stormbound: Kingdom Wars guide - how to...
Stormbound: Kingdom Wars is an excellent new RTS turned card battler out now on iOS and Android. Lovers of strategy will get a lot of enjoyment out of Stormbound's chess-like mechanics, and it's cardbased units are perfect for anyone who loves the... | Read more »
The best AR apps and games on iOS right...
iOS 11 has officially launched, and with it comes Apple's ARKit, a helpful framework that makes it easier than ever for developers to create mobile AR experiences. To celebrate the occassion, we're featuring some of the best AR apps and games on... | Read more »
Phoenix Wright: Ace Attorney - Spirit of...
Phoenix Wright: Ace Attorney - Spirit of Justice 1.00.00 Device: iOS Universal Category: Games Price: $.99, Version: 1.00.00 (iTunes) Description: ************************************************※IMPORTANT※・Please read the “When... | Read more »
Kpressor (Utilities)
Kpressor 1.0.0 Device: iOS Universal Category: Utilities Price: $4.99, Version: 1.0.0 (iTunes) Description: The ultimate ZIP compression application for iPhone and iPad. - Full integration of iOS 11 with support for multitasking.-... | Read more »
Find out how you can save £35 and win a...
Nothing raises excitement like a good competition, and we’re thrilled to announce our latest contest. We’ll be sending one lucky reader and a friend to the Summoners War World Arena Championship at Le Comedia in Paris on October 7th. It’s the... | Read more »
Another Lost Phone: Laura's Story...
Another Lost Phone: Laura's Story 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: Another Lost Phone is a game about exploring the social life of a young woman whose phone you have just... | Read more »
The Witness (Games)
The Witness 1.0 Device: iOS Universal Category: Games Price: $9.99, Version: 1.0 (iTunes) Description: You wake up, alone, on a strange island full of puzzles that will challenge and surprise you. You don't remember who you are, and... | Read more »
Egg, Inc. guide - how to build your gold...
Egg, Inc.'s been around for some time now, but don't you believe for one second that this quirky clicker game has gone out of style. The game keeps popping up on Reddit and other community forums thanks to the outlandish gameplay (plus, the... | Read more »
The best deals on the App Store this wee...
Good news, everyone! Your favorite day of the week has arrived at last -- it's discount roundup day! This fine Wednesday evening we're gathering up the hottest deals on the App Store. We've got action platformers, we've got puzzle games, we've got... | Read more »

Price Scanner via MacPrices.net

Looking for a 2017 12″ Retina MacBook? Save $...
Apple has Certified Refurbished 2017 12″ Retina MacBooks available for $200-$240 off the cost of new models. Apple will include a standard one-year warranty with each MacBook, and shipping is free.... Read more
Apple Offering Up To $455 Credit Toward iPhon...
iPhone 8 and 8 Plus are now available at the Apple Store, and you can receive up to $375 credit toward a new iPhone purchase when you trade in your eligible smartphone. Photo Courtesy Apple Just... Read more
AnyTrans Offers iOS Users Three Ways For Movi...
iMobie Inc. today announceed AnyTrans v6.0.1, which now can help iOS users move all data to iPhone 8/8 Plus seamlessly. The software is available both on Mac and Windows and fully able to move all... Read more
Snag a 13-inch 2.3GHz MacBook Pro for $100 of...
B&H Photo has 2017 13″ 2.3GHz MacBook Pros in stock today and on sale for $100 off MSRP, each including free shipping plus NY & NJ sales tax only: – 13-inch 2.3GHz/128GB Space Gray MacBook... Read more
Verizon offers new iPhone 8 for $100-$300 off...
Verizon is offering the new iPhone 8 for up to $300 off MSRP with an eligible trade-in: • $300 off: iPhone 6S/6S Plus/7/7 Plus, Google Pixel XL, LG G6, Moto Z2 Force, Samsung Galaxy S7/S7 edge/S8/S8... Read more
Apple Refurbished 2017 13-inch MacBook Pros a...
Apple has Certified Refurbished 2017 13″ Touch Bar MacBook Pros in stock today and available for $200-$300 off MSRP. A standard Apple one-year warranty is included with each MacBook, and shipping is... Read more
OWC USB-C Travel Dock with 5 Ports Connectivi...
OWC have announced the new OWC USB-C Travel Dock, the latest addition to their line of connectivity solutions. The USB-C Travel Dock lets you connect its integrated USB-C cable to a Mac or PC laptop... Read more
Pelican Products, Inc. Unveils Cases For All...
Pelican Products, Inc. has announced the launch of its full line of cases including Voyager, Adventurer, Protector, Ambassador, Interceptor (for the Apple iPhone 8 and 8 Plus backwards compatible... Read more
$100 off new 2017 13-inch MacBook Airs
B&H Photo has 2017 13″ MacBook Airs on sale today for $100 off MSRP including free shipping. B&H charges NY & NJ sales tax only: – 13″ 1.8GHz/128GB MacBook Air (MQD32LL/A): $899, $100 off... Read more
Apple restocks Certified Refurbished 13-inch...
Apple has Certified Refurbished 2015 13″ MacBook Airs available starting at $719 and 2016 models available starting at $809. An Apple one-year warranty is included with each MacBook, and shipping is... Read more

Jobs Board

Instructional Designer, *Apple* Product Doc...
Job Summary The Apple Product Documentation team is looking for an instructional designer or a video editor to write user documentation for its professional video Read more
*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
Development Operations and Site Reliability E...
Development Operations and Site Reliability Engineer, Apple Payment Gateway Job Number: 57572631 Santa Clara Valley, California, United States Posted: Jul. 27, 2017 Read more
Specialist - Retail Customer Services and Sal...
The position listed below is not with Tennessee Interviews but with Apple , Inc. Tennessee Interviews is a private organization that works in collaboration with Read more
Specialist - Retail Customer Services and Sal...
The position listed below is not with South Carolina Interviews but with Apple , Inc. South Carolina Interviews is a private organization that works in collaboration Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.