TweetFollow Us on Twitter

Designer CDEF
Volume Number:5
Issue Number:4
Column Tag:ABC's of Macintosh

Related Info: Control Manager

Designer CDEFs

By Kirk Chase, Assistant Editor, MacTutor

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

Designer CDEFs

I was hunting around the office for software goodies a while back when I came across Prototyper™. I stuck the disk in to see what it was and was pleasantly surprised. Those hours spent getting the interface just right seemed over. Here was an environment where I could draw my windows, set up my menus and controls, and then let it generate the code for the interface.

Prototyper™ wasn’t everything I wanted it to be, though. For example, it would generate code for things I didn’t need. But it served my purpose of getting an interface/shell running quickly. (I hear version 2.0 is a lot better, but they haven’t sent MacTutor an upgrade yet.) Anyway, I decided to test Prototyper™ out on graphic research question--Yahtzee (relaxation is important to mental health).

Well, after a bit, I had it up and running. I took it home and stuck it in my Mac for my recently married bride to look at. She took the mouse and started playing the game. Not as skilled in the mouse as I, whenever she went to click the checkbox beside each die to re-roll, she kept on missing or resetting it.

She asked me why she couldn’t just click on the dice themselves instead of those little, tiny boxes. I was about to say that they weren’t controls when I thought, “Why not? The user is always right.” And so I went on thinking about the problem. CDEFs sounded like a lot of work, but they weren’t for what I wanted. I just wanted a variation of the checkboxes. I decided just to alter the drawing routine of my checkboxes so that they just put a rounded rectangle around the die picture when selected. I found that this was quite easy to do and wrote up a small demonstration.

Figure 1. Designer CDEF

The Demo

The demo puts up five altered buttons (figure 1). The one in the middle is an altered checkbox made to look like a light switch. It is used to deactivate the controls on the left or right side. There are three radio buttons on the left which take on the appearance of a traffic light. The last button on the right is an altered button that cycles through the faces on a die (pictures taken from my Yahtzee application).

The CDEF

A CDEF is called through a function of the form:

{1}

function myCDEFProc(varCode : integer;
 theControl : ControlHandle;
 message : integer;
 param : longint) : longint;

It returns a longint telling what part of the control was pressed or zero if not pressed. The parameter varCode contains the variation code of the control. It lets you write one CDEF for a variety of controls. I chose though to use the RefCon field of the control, theControl, to switch between routines. The message parameter tells the CDEF function what it needs to do. The last parameter, param, varies in meaning depending on message.

The unit that held my designer CDEF is called “myCDEF”. A CDEF is supposed to handle a lot of tasks. It must take care of drawing the control according to it’s value and hilighting, as well as determining if the control was actually pressed. Therefore the main routine of our CDEF function is one where we check the message parameter that was passed, and do one of three routines: drawing, testing for a hit, and calculating the region. Other routines such as initializing or dragging the indicator are either done for us or not needed.

calcRgns

One message our altered CDEF needs to handle is calculating the region of the control. Param for this message is interpreted as a handle to a region. This is quite simple to do if your control is rectangular, you just make a call to RectRgn passing the region handle and the control’s rectangle. To be honest, a rounded button is not really a strict rectangle, but the corners are generally too small to really matter.

testCntl

The next message we need to handle is whether or not the user pressed the mouse button while in our control. We first check to see if our control is active and then whether or not it was in the indicator (we have none). Finally we call PtinRect on param, typecasted now to be a point, to see if we are actually in the control.

If we are in the control’s rectangle, we switch on contrlRfCon to see which type of control was pressed. Then we might want to do some further testing to see what part of the control was pressed, such as the page up or page down regions. Our CDEF has only one region so we send back the message inButton, if it is an altered button, or inCheckbox, if it was an altered checkbox or radio button.

drawCntl

I saved the largest routine for last. When we respond to a drawCntl message, we must draw the control with the appropriate value and hilighting. When we come in, we first check to see if the control is visible (no need to draw something that is invisible). Then we switch off the contrlRfCon field to handle each control type separately.

The Button

A normal button only shows it’s state when pressed, i.e. hilighted. Then is goes back to normal. In my demo, I alter the button to not draw the title and draw a dark or light border around the control depending on whether it was hilighted or not. Then I dim the control if it is deactivated.

You may ask yourself, where are the faces of the die? They are not handled by the CDEF. I did this for two reasons. The first was to make a semi-generic control that put up a dark outline when pressed and a lighter one when not. The second reason was to show the effects of the picture when the control is deactivated.

The Checkbox

This simple drawing routine puts up the control’s title and the On/Off title, in my case Left/Right. I might want to mention a nice routine, TextBox. If TextEdit is initialized, this routine saves the hastle of left/center/right justifying by passing it the title, the rectangle the title is to be drawn in, and the justification (teJustLeft, teJustCenter, teJustRight). Next, I see if the checkbox is on or off and draw the switch in that position with a thick pen or thin depending whether or not it is hilighted.

The Radio Controls

Although the radio controls are one type of control, each is drawn in a slightly different way. I first put up the title and then switch on contrlRfCon again to draw the traffic light box and set up the shade of the light. Then I draw the light according to the shade or override it with white if the control is not set. Then I dim the control if inactive.

You will notice that there is not a hilighted state, other than inactive. You do not need to put one in if you do not feel it is necessary. For that matter, there is no reason why you need to deactivate your control by dimming it. You could dim just part, dim it with a different pattern, or even draw something entirely different. Just remember not to go overboard and try to stick to the standard interface (I might have drawn a thicker circle). But if it seems natural to draw it in a nonstandard way, go ahead; that is after all the purpose to this article and all those little hooks.

Attaching Your Routine

The code to override the standard definition with yours is quite simple. Make sure your window is invisible to start off with so that you can attach your drawing routine before QuickDraw draws something. Then follow the example:

{2}

MyWindow := GetNewWindow(WindowID, NIL, Pointer(-1);
CDEFHandle := NewHandle(0); {Get temporary control handle}
CDEFHandle := Ptr(@myCDEFProc); {Point it to our routine}
CtrlHdl := GetNewControl(ButtonID, MyWindow);
HLock(Handle(CtrlHdl));
CtrlHdl^^.contrlDefProc := CDEFHandle; {Set to our proc}
HUnLock(Handle(CtrlHdl));
Show(MyWindow); {make it visible}
SelectWindow(MyWindow); {bring to front}
SetPort(MyWindow); {set the port to our window}

Further Notes

The die pictures are done by changing the min/max of the button to 0/5. When the button is pressed, the value is set accordingly, and the button’s rectangle is invalidated. Then during the update event, the appropriate picture is retrieved according to the button’s value and drawn. Then the controls are drawn, dimming the die face if inactive.

There are a couple notes of warning that you should be aware of. The first is that you must call DisposeWindow to dispose of your controls. Don’t just quit, or you’ll crash. The second has to do with debugging.

I worked this out in Lightspeed Pascal 2.0. Now I usually like to put a few writeln statements to the text window while developing. And I did so in my CDEF to trace it being called. Nothing appeared in my window. My tracing showed that I was indeed going where I should be with all the right values. What was wrong? Well it was those debugging statements. I figured that the writeln statements were setting the port to the text window and not resetting the port. Therefore my control drawing routines were being directed to the wrong port.

That’s about it. Good luck!

Figure 2. LSP Project


UNIT myCDEF;

INTERFACE

 FUNCTION DesignerButtonProc (varCode : integer;
 theControl : ControlHandle;
 message : integer;
 param : longint) : longint;

IMPLEMENTATION

 FUNCTION DesignerButtonProc; {}
{Custom controls for our controls}
 CONST
 inactive = 255;
 indicator = 254;
 regbutton = 3;
 regcheck = 4;
 rStop = 5;
 rCaution = 6;
 rGo = 7;

 PROCEDURE DodrawCntl (theButton : integer;
 ControlHdl : ControlHandle;
 thePart : longint);
 VAR
 cRect, titleRect, designRect, tempRect, dimRect
 onBox, offBox : Rect;
 height, width, curve, start,
 titlewidth : integer;
 titlestr, tempstr : str255;

 PROCEDURE DeactiveButton (theRect : rect);
 {dim the button}
 BEGIN
 PenPat(Gray);
 PenMode(PatBic);
 PaintRect(theRect);
 PenNormal;
 END;

 BEGIN {of main drawing routines}
 IF ControlHdl^^.contrlVis <> 0 THEN {visible?}
 BEGIN
 HLock(Handle(ControlHdl));
 cRect := ControlHdl^^.contrlRect; 
 {get the rectangle of control}
 CASE ControlHdl^^.contrlRfCon OF 
 {switch on button type}
 regbutton :  {regular button}
 BEGIN
 PenSize(2, 2);
 curve := (cRect.bottom - cRect.top) DIV 2;
 IF ControlHdl^^.contrlHilite > 0 THEN
 {hilight button?}
 PenPat(black)
 ELSE
 PenPat(dkgray);
 FrameRoundRect(cRect, curve, curve);
 {draw button}
 PenNormal;
 IF ControlHdl^^.contrlHilite = inactive
 THEN {inactive?}
 BEGIN
 tempRect := cRect;
 InsetRect(tempRect, 2, 2);
 DeactiveButton(tempRect);
 END;
 END;

 regcheck : {checkbox}
 BEGIN
 EraseRect(cRect);
 titleRect := cRect;
 titleRect.top := titleRect.bottom - 12;
 designRect := cRect;
 designRect.bottom := designRect.bottom - 12;
 width := titleRect.right -
 titleRect.left;
 height := designRect.bottom -
 designRect.top;

 {draw control title}
 TextFont(systemFont); 
 titlewidth := StringWidth(ControlHdl^^
 .contrlTitle);
 titlestr := ControlHdl^^.contrlTitle;
 TextBox(Pointer(ord(@titlestr) + 1),
 length(titlestr), titleRect,
 teJustLeft);

 {draw ON/OFF, or LEFT/RIGHT, titles}
 tempRect := designRect;
 tempRect.left := tempRect.left + 20;
 tempRect.bottom := tempRect.top + 12;
 tempstr := ‘LEFT’;
 TextBox(Pointer(ord(@tempstr) + 1),
 length(tempstr), tempRect,
 teJustRight);
 tempRect.bottom := designRect.bottom;
 tempRect.top := tempRect.bottom - 12;
 tempstr := ‘RIGHT’;
 TextBox(Pointer(ord(@tempstr) + 1),
 length(tempstr), tempRect, 
 teJustRight);
 TextFont(applFont);     

 {start drawing switch}
 tempRect := designRect;
 tempRect.right := tempRect.left + 40;
 WITH tempRect DO {draw Switch}
 BEGIN
 width := right - left;
 height := bottom - top;
 onBox.top := top + (height DIV 2) - 10;
 onBox.bottom := onBox.top + 20;
 onBox.left := left + (width DIV 2) - 10;
 onBox.right := onBox.left + 20;

 IF ControlHdl^^.contrlHilite > 0
 THEN {Hilite?}
 PenSize(2, 2)
 ELSE
 PenSize(1, 1);
 IF ControlHdl^^.contrlValue > 0
 THEN
 BEGIN {draw on}
 FrameArc(onBox, 0, -270);
 MoveTo(left + (width DIV 2),
 onBox.top);
 Line(20, -20);
 Line(10, 10);
 LineTo(onBox.right, top +
 (height DIV 2));
 END
 ELSE
 BEGIN {draw off}
 FrameArc(onBox, 90, -270);
 MoveTo(onBox.right, top +
 (height DIV 2));
 Line(20, 20);
 Line(-10, 10);
 LineTo(left + (width DIV 2),
 onBox.bottom);
 END;
 END; { of with}
 END;

 rStop, rCaution, rGo : {radio button}
 BEGIN
 designRect := cRect;
 titleRect := designRect;
 titleRect.left := titleRect.left + 25;
 titleRect.top := titleRect.top + 3;
 designRect.right := designRect.left + 20;

 {draw title of control}
 TextFont(systemFont);        
 titlestr := ControlHdl^^.contrlTitle;
 TextBox(Pointer(ord(@titlestr) + 1),
 length(titlestr), titleRect, 
 teJustLeft);
 TextFont(applFont);               
 height := designRect.bottom - 
 designRect.top;

{switch on RefCon for radio button: stop, caution, and go  this is for 
radio button specific stuff}

 CASE ControlHdl^^.contrlRfCon OF
 rStop : 
 BEGIN
 {draw box}
 PenSize(2, 2);
 MoveTo(designRect.left,
 designRect.bottom);
 LineTo(designRect.left,
 designRect.top);
 LineTo(designRect.right,
 designRect.top);
 LineTo(designRect.right,
 designRect.bottom);
 PenNormal;
 PenPat(dkgray); {light color}
 END;
 rCaution : 
 BEGIN
 {draw box}
 PenSize(2, 2);
 MoveTo(designRect.left,
 designRect.bottom);
 LineTo(designRect.left,
 designRect.top);
 MoveTo(designRect.right,
 designRect.top);
 LineTo(designRect.right,
 designRect.bottom);
 PenNormal;
 PenPat(ltgray); {light color}
 END;
 rGo : 
 BEGIN
 {draw box}
 PenSize(2, 2);
 MoveTo(designRect.left,
 designRect.top);
 LineTo(designRect.left,
 designRect.bottom);
 LineTo(designRect.right,
 designRect.bottom);
 LineTo(designRect.right,
 designRect.top);
 PenNormal;
 PenPat(gray); {light color}
 END;

 OTHERWISE
 ;
 END; { of case }

 {draw light}
 onBox := designRect;
 InsetRect(onBox, 4, 4);
 onBox.left := onBox.left + 1;
 onBox.right := onBox.right + 1;
 IF ControlHdl^^.contrlValue = 0 THEN
 {override pattern if off}
 PenPat(white);
 PaintOval(onBox);
 PenNormal;
 FrameOval(onBox);

 IF ControlHdl^^.contrlHilite = inactive
 THEN {deactivate control}
 BEGIN
 tempRect := cRect;
 DeactiveButton(tempRect);
 END;
 END;
 END; {of button}

 HUnLock(Handle(ControlHdl));
 END; {of a visible control}
 END;

 FUNCTION DotestCntl (theButton : integer;
 ControlHdl : ControlHandle;
 thePoint : point) : longint;
 {Test what part of control}
 BEGIN
 DotestCntl := 0; {initial value}
 IF ControlHdl^^.contrlHilite <> inactive THEN
 {active control?}
 BEGIN
 IF ControlHdl^^.contrlHilite <> indicator
 THEN {indicator?}
 BEGIN
 IF PtInRect(thePoint, ControlHdl^^
 .contrlRect) THEN {in control’s rect}
 BEGIN
 CASE ControlHdl^^.contrlRfCon OF
 {switch on control type  here is where
  you send a code back as to what type
  of control and what part of that
  control was  pressed.  We only have
  controls with one part, so no further
  testing is needed}
 regbutton : 
 DotestCntl := inButton;
 regcheck, rStop, rCaution, rGo : 
 DotestCntl := inCheckBox;
 OTHERWISE
 ;
 END;
 END;
 END
 ELSE
 DotestCntl := indicator;
 END;
 END;

 PROCEDURE DocalcCRgns (theButton : integer;
 ControlHdl : ControlHandle;
 RegionHdl : RgnHandle);
 {calculate region of control}
 BEGIN
 {easy as pie if rectangular}
 RectRgn(RegionHdl, ControlHdl^^.contrlRect);
 END;

 BEGIN {main proc routine}
 DesignerButtonProc := 0; {initialize the result}

 {switch on what we are to do}
 CASE message OF
 drawCntl : 
 DodrawCntl(varCode, theControl, param); {draw}
 testCntl : 
 DesignerButtonProc := DotestCntl(varCode, 
 theControl, Point(param)); {test}
 calcCRgns : 
 DocalcCRgns(varCode, theControl, 
 RgnHandle(param)); {region}
 OTHERWISE
 ;
 END; {of case}
 END;

END.


PROGRAM DesignerButtons;
{Program name:DesignerButtons.Pas   }
{Function:  This is the main module for this program.  }
{History: 12/19/88 Original by Prototyper.   }
{  Modified 1/6/89                     }

 USES
 AboutDialog, ExampleWindow, InitTheMenus,
 HandleTheMenus;

 CONST
 sleep = 10;
 mBarHeightGlobal = $BAA;
 sBarWidth = 16;
 SuspendEvt = 15;

 VAR    {Main variables}
 myEvent: EventRecord;    {Event record for all events}
 doneFlag: boolean;  {Exit program flag}
 code: integer;    {Determine event type}
 whichWindow, MainWindow: WindowPtr;
 mResult: longint;        
 theMenu, theItem: integer;   
 chCode: integer;    {Key code}
 ch: char;       {Key pressed in Ascii}
 doIt: Boolean;  {Event Loop bolean}
 tempPort: GrafPtr;
 DragArea, screen: rect;
 mBarHeight: integer;
 MemoryPtr: ^Integer;
 HiByte: byte;
 bit0: LongInt;
 sysresult: boolean;
 ResumePeek: WindowPeek;
 SuspendPeek: WindowPeek;

 PROCEDURE crash;
 BEGIN
 ExitToShell;
 END;

BEGIN    {main }
 MoreMasters;            
 InitGraf(@thePort);    {Quickdraw Init}
 InitFonts;             {Font manager init}
 InitWindows;           {Window manager init}
 InitMenus;             {Menu manager init}
 TEInit;                {Text edit init}
 InitDialogs(@crash);   {Dialog manager}
 FlushEvents(everyEvent, 0);         
 InitCursor;             {Make an arrow cursor}
 doneFlag := FALSE;      {Do not exit program yet}

 MemoryPtr := pointer(mBarHeightGlobal); 
 mBarHeight := MemoryPtr^;
 screen := ScreenBits.Bounds; {current screen device}
 SetRect(DragArea, Screen.left + 4, Screen.top +
 mBarHeight + 4, Screen.right - 4, Screen.bottom - 4);

 Init_My_Menus;  {Initialize menu bar}
 Init_ExampleWindow;  {Initialize the window }
 Open_ExampleWindow(MainWindow);  {Open the window }

 REPEAT     {main event loop}
 DoIt := WaitNextEvent(EveryEvent, myEvent, sleep,
  NIL); {no mouse tracking}
 IF DoIt THEN
 BEGIN
 code := FindWindow(myEvent.where, whichWindow); {Get which window the 
event happened in}
 CASE myEvent.what OF

 MouseDown: {Mouse button pressed}
 BEGIN  {Handle the pressed button}
 IF (code = inMenuBar) THEN 
 BEGIN  {Get menu selection }
 mResult := MenuSelect(myEvent.Where);
 theMenu := HiWord(mResult); { menu}
 theItem := LoWord(mResult); {item}
 Handle_My_Menu(doneFlag, theMenu,
  theItem);
 END; {End of inMenuBar}

 IF (code = inContent) THEN 
 BEGIN   {Handle hit inside a window}
 IF (whichWindow <> FrontWindow) THEN
 SelectWindow(whichWindow)
 ELSE   
 BEGIN   {Handle the button}
 SetPort(whichWindow);
 Do_ExampleWindow(myEvent);
 END; {End of else}
 END;  {End of inContent}

 IF (code = inSysWindow) THEN 
 {See if a DA selection}
 SystemClick(myEvent, whichWindow); 

 IF (code = inDrag) THEN
 DragWindow(whichWindow, myEvent.Where,
  DragArea);

 IF (code = inGoAway) THEN
 IF TrackGoAway(whichWindow,
  myEvent.Where) THEN
 BEGIN
 HideWindow(whichWindow);
 doneFlag := true;
 END;
 END;  {End of MouseDown}

 KeyDown, AutoKey:  {Handle key inputs}
 BEGIN   {Get the key and handle it}
 WITH myevent DO  
 BEGIN                   {}
 chCode := BitAnd(message,
  CharCodeMask); {Get character}
 ch := CHR(chCode);    
 {Change to ASCII}
 IF (Odd(modifiers DIV CmdKey)) THEN
 BEGIN               {}
 mResult := MenuKey(ch);
 theMenu := HiWord(mResult);
 theItem := LoWord(mResult);
 IF (theMenu <> 0) THEN 
 {See if a list was selected}
 Handle_My_Menu(doneFlag,
  theMenu, theItem);
 END;                 {}
 END;    {End for with}
 END;        {End for KeyDown,AutoKey}

 UpDateEvt:  {Update event for a window}
 BEGIN     {Handle the update}
 GetPort(tempPort);
 whichWindow := WindowPtr(myEvent.message);
 {Get the window the update is for}
 SetPort(whichWindow);
 BeginUpdate(whichWindow); 
 {Set the clipping to the update area}
 Update_ExampleWindow(whichWindow); 
 {Update this window}
 EndUpdate(whichWindow);   
 {Return to normal clipping area}
 SetPort(tempPort);
 END;   {End of UpDateEvt}

 ActivateEvt:   {Window activated event}
 BEGIN        {Handle the activation}
 whichWindow := WindowPtr(myevent.message);
 {Get the window to be activated}
 IF odd(myEvent.modifiers) THEN 
 {Activate and not DeActivate}
 SelectWindow(whichWindow); 
 {Activate the window by selecting it}
 END;     {End of ActivateEvt}

 SuspendEvt: 
 BEGIN
 bit0 := 31; {convert 68000 to toolbox}
 {check for resume event }
 IF Odd(myEvent.message) THEN
 BEGIN  {resume}
 whichWindow := FrontWindow;
 IF whichWindow = MainWindow THEN
 BEGIN
 Setport(whichWindow);
 InvalRect(whichWindow^.portRect);
 SelectWindow(whichWindow);
 END;
 IF FrontWindow <> NIL THEN
 BEGIN {DA check}
 ResumePeek :=
  WindowPeek(FrontWindow);
 IF ResumePeek^.windowKind < 0
  THEN {DA}
 BEGIN {da}
 myEvent.what := activateEvt;
 BitSet(@myEvent.modifiers,
  bit0);
 sysresult :=
  SystemEvent(myEvent);
 END; {da}
 END; {DA check}
 { end of activate Event}
 END {of resume}
 ELSE
 BEGIN  {suspend}
 {de-activate Event}
 whichWindow := FrontWindow;
 IF whichWindow = MainWindow THEN
 BEGIN
 SetPort(whichWindow);
 InvalRect(whichWindow^.portRect);
 END;
 IF FrontWindow <> NIL THEN
 BEGIN {DA check}
 SuspendPeek :=
  WindowPeek(FrontWindow);
 IF SuspendPeek^.windowKind < 0
  THEN
 BEGIN {da}
 myEvent.what := activateEvt;
 BitClr(@myEvent.modifiers,
  bit0);
 sysresult :=
  SystemEvent(myEvent);
 END; {da}
 END; {DA check}
 END; {suspend}
 END;

 OTHERWISE
 BEGIN
 END;       {End of otherwise}
 END;   {End of case}
 END;   {end of waitNextEvent}
 UNTIL doneFlag;   {End of the event loop}
 DisposeWindow(MainWindow); 
END.    {End of the program}

UNIT InitTheMenus;

INTERFACE

 PROCEDURE Init_My_Menus;

 VAR
 AppleMenu: MenuHandle;
 FileMenu: MenuHandle;

IMPLEMENTATION

 PROCEDURE Init_My_Menus; {Initialize the menus}
 CONST
 Menu1 = 201;   {Apple Menu resource ID}
 Menu2 = 202;   {File Menu resource ID}
 BEGIN              {Start of Init_My_Menus}
 ClearMenuBar;    {Clear any old menu bars}
 AppleMenu := GetMenu(Menu1);  {Get apple menu}
 AddResMenu(AppleMenu, ‘DRVR’); {Add in DAs}
 InsertMenu(AppleMenu, 0); 
 FileMenu := GetMenu(Menu2);      {File menu}
 InsertMenu(FileMenu, 0);   
 DrawMenuBar;   {Draw the menu bar}
 END;      {End of procedure Init_My_Menus}
END.    {End of Unit}

UNIT AboutDialog;

{File name:AboutDialog.Pas   }
{Function: Handle a dialog}

INTERFACE

 PROCEDURE D_AboutDialog;

IMPLEMENTATION

 CONST   {item numbers for controls in Dialog}
 I_OK = 1;
 VAR
 ExitDialog: boolean;  {Flag used to exit Dialog}

 PROCEDURE D_AboutDialog;
 VAR
 GetSelection: DialogPtr; {Name of dialog}
 itemHit: Integer;   {Get selection}
 BEGIN     {Start of dialog handler}
 GetSelection := GetNewDialog(2, NIL, Pointer(-1));
 {Bring in the dialog resource}
 ShowWindow(GetSelection);    {Open a dialog box}
 SelectWindow(GetSelection);  {Lets see it}
 SetPort(GetSelection); 

 ExitDialog := FALSE;   {Do not exit loop yet}
 REPEAT          {Start of dialog handle loop}
 ModalDialog(NIL, itemHit);  
 IF (ItemHit = I_OK) THEN {Handle Button}
 BEGIN
 ExitDialog := TRUE;      {Exit the dialog}
 END;      {End for this item selected}
 UNTIL ExitDialog; {Handle until exit selected}
 DisposDialog(GetSelection);       
 END;    {End of procedure}
END.   {End of unit}

UNIT ExampleWindow;

{File name: ExampleWindow.Pas}
{Function: Handle a Window}

INTERFACE
 USES
 myCDEF;

 PROCEDURE Init_ExampleWindow;
 PROCEDURE Open_ExampleWindow (VAR theWindow: WindowPtr);
 PROCEDURE Update_ExampleWindow (whichWindow: WindowPtr);
 PROCEDURE Do_ExampleWindow (myEvent: EventRecord);

IMPLEMENTATION

 CONST
 I_Buttonx1 = 3;    {Button ID}
 I_Checkboxx2 = 4;  {Checkbox ID}
 I_Radio2 = 6;      {Radio ID}
 I_Radio3 = 7;      {Radio ID}
 I_Radio1 = 5;      {Radio ID}

 VAR
 MyWindow: WindowPtr;     {Window pointer}
 tempRect: Rect; {Temporary rectangle}
 CtrlHandle, buttonHdl: controlhandle;
 sTemp: Str255;  {Get text entered, temp holding}
 R1Control: ARRAY[1..3] OF ControlHandle; 
 { Radio button handles for group 1}

 PROCEDURE Init_ExampleWindow;
 BEGIN
 MyWindow := NIL;  {we are not valid yet}
 END;

  {Update our window, someone uncovered a part of us}
 PROCEDURE UpDate_ExampleWindow;
 CONST
 picBaseID = 144;
 VAR
 SavePort: WindowPtr;  {Place to save the last port}
 pictRect: rect;
 Pic_Handle: PicHandle;
 pictindex: integer;

 BEGIN     {Start of Window update routine}
 IF (MyWindow <> NIL) AND (MyWindow = whichWindow)
  THEN 
 BEGIN
 TextFont(systemFont); 
          {Draw a string of text, Static Text }
 SetRect(tempRect, 266, 100, 312, 116);
 sTemp := ‘Button’;
 TextBox(Pointer(ord(@sTemp) + 1), length(sTemp),
  tempRect, teJustLeft);

        {Draw a string of text, Static Text }
 SetRect(tempRect, 151, 100, 217, 116);
 sTemp := ‘CheckBox’;
 TextBox(Pointer(ord(@sTemp) + 1), length(sTemp),
  tempRect, teJustLeft);

         {Draw a string of text, Static Text }
 SetRect(tempRect, 36, 100, 77, 116);
 sTemp := ‘Radio’;
 TextBox(Pointer(ord(@sTemp) + 1), length(sTemp),
  tempRect, teJustLeft);

        {Draw a string of text, Static Text }
 SetRect(tempRect, 76, 125, 287, 141);
 sTemp := ‘Designer CDEF by Kirk Chase’;
 TextBox(Pointer(ord(@sTemp) + 1), length(sTemp),
  tempRect, teJustLeft);
 TextFont(applFont);  
 pictRect := buttonHdl^^.contrlRect;
 InsetRect(pictRect, 2, 2);
 pictindex := GetCtlValue(buttonHdl);
 Pic_Handle := GetPicture(picBaseID + pictindex);
   {Get Picture into memory}
 IF (Pic_Handle <> NIL) THEN 
 DrawPicture(Pic_Handle, pictRect);
 DrawControls(MyWindow);  {Draw controls}
 END;    {End for if (MyWindow<>nil)}
 END;    {End of procedure}

  {Open our window and draw everything}
 PROCEDURE Open_ExampleWindow;
 VAR
 CDEFHandle: handle;
 chkhdl: controlhandle;

 BEGIN    {Start of Window open routine}
 IF (MyWindow = NIL) THEN     
 BEGIN
 MyWindow := GetNewWindow(1, NIL, Pointer(-1)); 
 {Get the window from the resource file}
 theWindow := MyWindow;

 {get a handle to our CDEF Proc}
 CDEFHandle := NewHandle(0);
 CDEFHandle^ := Ptr(@DesignerButtonProc);

         { Make a button, Button }
 CtrlHandle := GetNewControl(I_Buttonx1,
  MyWindow);
 HLock(Handle(CtrlHandle));
 CtrlHandle^^.contrlDefProc := CDEFHandle;
 HUnLock(Handle(CtrlHandle));
 CtrlHandle^^.contrlHilite := 255;
 buttonHdl := CtrlHandle;

         { Make a checkbox, Checkbox }
 CtrlHandle := GetNewControl(I_Checkboxx2,
  MyWindow); {Make a new checkbox}
 HLock(Handle(CtrlHandle));
 CtrlHandle^^.contrlDefProc := CDEFHandle;
 HUnLock(Handle(CtrlHandle));
 chkhdl := CtrlHandle;

        { Make a radio button, Radio1 }
 R1Control[1] := GetNewControl(I_Radio1,
  MyWindow);
 HLock(Handle(CtrlHandle));
 R1Control[1]^^.contrlDefProc := CDEFHandle;
 HUnLock(Handle(CtrlHandle));

        { Make a radio button, Radio2 }
 R1Control[2] := GetNewControl(I_Radio2,
  MyWindow);
 HLock(Handle(CtrlHandle));
 R1Control[2]^^.contrlDefProc := CDEFHandle;
 HUnLock(Handle(CtrlHandle));

        { Make a radio button, Radio3 }
 R1Control[3] := GetNewControl(I_Radio3,
  MyWindow);
 HLock(Handle(CtrlHandle));
 R1Control[3]^^.contrlDefProc := CDEFHandle;
 HUnLock(Handle(CtrlHandle));

 ShowWindow(MyWindow);
 SelectWindow(MyWindow); {window to front}
 SetPort(MyWindow); {write into our window}

 UpDate_ExampleWindow(MyWindow); 

 END    {End for if (MyWindow<>nil)}
 ELSE
 SelectWindow(MyWindow);      

 END;   {End of procedure}

  {Handle action to our window, like controls}
 PROCEDURE Do_ExampleWindow;
 CONST
 HiliteValue = 10;
 inactive = 255;
 active = 0;
 left = 0;
 right = 1;

 VAR
 RefCon: integer;   {RefCon for controls}
 code: integer;    {Location of event}
 theValue: integer;  {Current value of a control}
 whichWindow: WindowPtr;  {window for event}
 myPt, myPtGlobal: Point;   
 theControl: ControlHandle;   
 badRect: rect;

 PROCEDURE Do_A_Button;  

 BEGIN
 HiliteControl(theControl, HiliteValue);      
 {Darken the button}
 RefCon := GetCRefCon(theControl);   
 {get control refcon}

 CASE RefCon OF  {Select correct button}
 I_Buttonx1:    {Button, button}
 BEGIN        {start for this button}
 theValue := GetCtlValue(theControl);
 theValue := (theValue + 1) MOD 6; 
 SetCtlValue(theControl, theValue); 
 {Set button to new value}
 badRect := buttonhdl^^.contrlRect;
 InvalRect(badRect); 
 END;  {end for this button}

 OTHERWISE {allow other buttons, trap for debug}
 ;
 END;  {end of case}

 HiliteControl(theControl, active);  
 END;   {Handle a button being pressed}


 PROCEDURE Do_A_Checkbox;              
 {Handle a checkbox being pressed}
 VAR
 Index: integer; {Index used for radios}

 PROCEDURE Clear1RadioGroup;           
 {Routine to clear radios in group 1}
 VAR
 Index: integer; {Index used for radios}
 BEGIN    {Start of the clear routine}
 FOR Index := 1 TO 3 DO {Step thru all radios}
 SetCtlValue(R1Control[Index], 0);  
 {Set this radio to zero}
 END;   {End of the clear routine}

 BEGIN    {Handle a checkbox being pressed}
 RefCon := GetCRefCon(theControl);   
 theValue := GetCtlValue(theControl); 
 theValue := (theValue + 1) MOD 2;   {Change value}

 CASE RefCon OF {Select correct button}
 I_Checkboxx2:  {Checkbox, checkbox}
 BEGIN   {start for this button}
 SetCtlValue(theControl, theValue); 
 {Set checkbox to new value}
 badRect := buttonhdl^^.contrlRect;
 InvalRect(badRect);
 CASE theValue OF {left or right controls}
 left: 
 BEGIN
 HiliteControl(buttonHdl, inactive);
 HiliteControl(R1Control[1], active);
 HiliteControl(R1Control[2], active);
 HiliteControl(R1Control[3], active);
 END;
 right: 
 BEGIN
 HiliteControl(buttonHdl, active);
 HiliteControl(R1Control[1], inactive);
 HiliteControl(R1Control[2], inactive);
 HiliteControl(R1Control[3], inactive);
 END;
 OTHERWISE
 ;
 END;
 END;   {end for this checkbox}

 I_Radio1, I_Radio2, I_Radio3:                   
 {radio buttons}
 BEGIN    {start for this radio button}
 Clear1RadioGroup;  
 SetCtlValue(theControl, 1); 
 END; {end for this radio button}
 OTHERWISE
 ;
 END;    {end of case}
 END;   {Handle a checkbox being pressed}

 BEGIN   {Start of Window handler}
 IF (MyWindow <> NIL) THEN           
 BEGIN
 code := FindWindow(myEvent.where, whichWindow); 
 IF (myEvent.what = MouseDown) AND (MyWindow =
  whichWindow) THEN 
 BEGIN  
 myPt := myEvent.where; {Get mouse position}
 myPtGlobal := myPt;
 GlobalToLocal(myPt);
 END;
 IF (MyWindow = whichWindow) AND (code =
  inContent) THEN {for our window}
 BEGIN
 code := FindControl(myPt, whichWindow,
  theControl); {Get type of control}
 IF (code <> 0) THEN  {Check type}
 code := TrackControl(theControl, myPt,
  NIL); {Track the control}
 IF code = inButton THEN
 Do_A_Button;   {Do buttons}
 IF code = inCheckBox THEN
 Do_A_Checkbox;  {Do checkboxes}
 END;  {End for if (MyWindow=whichWindow)}
 END;    {End for if (MyWindow<>nil)}
 END;   {End of procedure}

END.   {End of unit}

UNIT HandleTheMenus;

INTERFACE

 USES
 AboutDialog, ExampleWindow, InitTheMenus;

 PROCEDURE Handle_My_Menu (VAR doneFlag: boolean;
  theMenu, theItem: integer); {Handle menu selection}

IMPLEMENTATION

 PROCEDURE Handle_My_Menu;
 CONST
 L_Apple = 201;  {Menu list}
 C_About = 1;
 L_File = 202;   {Menu list}
 C_Quit = 1;
 VAR
 DNA: integer;   {For opening DAs}
 BoolHolder: boolean;   {For SystemEdit result}
 DAName: Str255;   {For getting DA name}
 SavePort: GrafPtr;  {Save current port}

 BEGIN
 CASE theMenu OF   {Do selected menu list}

 L_Apple: 
 BEGIN
 IF theItem = C_About THEN
 D_AboutDialog   {Call a dialog}
 ELSE              {Handle the DAs}
 BEGIN
 GetPort(SavePort);    {Save port}
 GetItem(AppleMenu, theItem, DAName);
 DNA := OpenDeskAcc(DAName); {Open DA }
 SetPort(SavePort);    {Restore port}
 END;
 END;   {of L_Apple}

 L_File: 
 BEGIN
 IF theItem = C_Quit THEN
 doneFlag := true;
 END;

 OTHERWISE
 BEGIN
 END;
 END;
 HiliteMenu(0);   {Turn menu selection off}
 END;   {End of procedure Handle_My_Menu}

END.    {End of unit}

****************************
*
* RMaker resource file sources.
* File: DesignerButtons.R
* History: 12/19/88 Original by Prototyper.   
*

DesignerButtons.RSRC
????KCBx

Type KCBx = STR 
ID ,0
CDEF Demo \0D© by Kirk Chase \0Dver 19 DEC 1989

* Multifinder Menu for Quit Cmd
Type mstr = STR 
File  ,100
File

* Multifinder Quit name
Type mstr = STR 
Quit  ,101
Quit

Type FREF
CDEF,128
APPL 0

Type BNDL
Bundle,128
KCBx 0
ICN#
0 128
FREF 
0 128

Type SIZE = GNRL
MultiFinder ,-1
.H
4800    ;; $4800 = bits 14 & 11 set
.L
80000 ;; ( recomended)
.L
50000 ;; ( minimum)
.I

Type vers = GNRL
 , 1
.H
01 ;; byte vers # in BCD
10 ;; byte vers part 2 & 3
50 ;; byte release stage $50=release
00 ;; byte stage of non-release
00 00 ;; integer country 0=US
.P
V1.1 (US)
.P
CDEF Demo 1.1, © by Kirk Chase for MacTutor 1989

Type vers = GNRL
 , 2
.H
05 ;; byte vers # in BCD
30 ;; byte vers part 2 & 3
50 ;; byte release stage $50=release
00 ;; byte stage of non-release
00 00 ;; integer country 0=US
.P
V5.3
.P
MacTutor Volume 5 Number 3

* This is the definition for the DIALOG.
*
Type DLOG
About    ,2         ;;Resource ID
About Dialog        ;;Dialog title
186  87  313  411   ;;Top Left Bottom Right
Visible NoGoAway    ;;Visible GoAway 
1                   ;;ProcID, dialog def ID
2                   ;;Refcon, reference value
2                   ;;ID of item list

* This is the DIALOG or ALERT item list.
*
Type DITL
About Items   ,2    ;;Resource ID
3                   ;;Number of controls in list

Button  Enabled     ;;Push button
75  181  111  247   ;;Top Left Bottom Right
OK                  ;;message

StaticText          ;;Static text
40  11  56  297     ;;Top Left Bottom Right
Portions of code developed by Prototyper

StaticText          ;;Static text
15  6  36  307      ;;Top Left Bottom Right
Designer CDEF by Kirk Chase For MacTutor\0D

* This is the definition for the MENU.
*
Type MENU
Apple     ,201    ;;Resource ID
\14               ;;APPLE menu title
About Designer CDEF ...
(-

File     ,202   ;;Resource ID
File            ;;menu title
Quit/Q          ;;item title

* This is the definition for the WINDOW.
*
Type WIND
Kirk Chase    ,1   ;;Resource ID
Example Window     ;;Window title
55  17  210  373   ;;Top Left Bottom Right
InVisible  GoAway  ;;Visible GoAway 
4                  ;;ProcID, Window def ID
1                  ;;Refcon, reference value

* This is the CONTROL item list.
*
Type CNTL
Button   ,3      ;;Resource ID
Button           ;;Title for a Button
5  246  81  332  ;;Top Left Bottom Right
Visible          ;;Initially visible 
0                ;;ProcID (Control definition ID)
3                ;;RefCon (reference value)
0 5 0            ;;Min Max Value

Checkbox   ,4    ;;Resource ID
Deactivate       ;;Title for a Checkbox
5  136  80  221  ;;Top Left Bottom Right
Visible          ;;Initially visible 
1                ;;ProcID (Control definition ID)
4                ;;RefCon (reference value)
0 1 0            ;;Min Max Value

Radio Caution   ,6   ;;Resource ID
Caution                                  
25  21  45  106                        
Visible                                
2                                     
6                                     
0 1 0                                  

Radio Go   ,7    ;;Resource ID
Go                                  
45  21  65  106                         
Visible                                 
2                                       
7                                      
0 1 0                                

Radio Stop  ,5  ;;Resource ID
Stop                                  
5  21  25  106                          
Visible                                 
2                                       
5                                       
0 1 1                                   

* PICTs for button
Type PICT = GNRL
,149
.H
008B 0007 0007 0068 0068 1101 A000 82A0
008C 0100 0A00 0700 0700 6800 680A 0000
0000 0000 0000 0B00 1B00 1B44 0009 0009
0066 0066 0700 0200 0248 0AFF FFFF FFFF
FFFF FF54 0015 0015 0027 0027 0700 0100
0158 5400 2F00 1400 4200 2758 5400 1400
4A00 2700 5D58 5400 2F00 4A00 4200 5D58
5400 4A00 4A00 5D00 5D58 5400 4A00 1400
5D00 2758 A000 8DA0 0083 FF

Type PICT = GNRL
,148
.H
0081 0007 0007 0068 0068 1101 A000 82A0
008C 0100 0A00 0700 0700 6800 680A 0000
0000 0000 0000 0B00 1B00 1B44 0009 0009
0066 0066 0700 0200 0248 0AFF FFFF FFFF
FFFF FF54 004B 0015 005D 0027 0700 0100
0158 5400 4A00 4A00 5D00 5D58 5400 1400
1400 2700 2758 5400 1400 4A00 2700 5D58
5400 2F00 2F00 4200 4258 A000 8DA0 0083
FF

Type PICT = GNRL
,147
.H
0077 0007 0007 0068 0068 1101 A000 82A0
008C 0100 0A00 0700 0700 6800 680A 0000
0000 0000 0000 0B00 1B00 1B44 0009 0009
0066 0066 0700 0200 0248 0AFF FFFF FFFF
FFFF FF54 0015 0015 0027 0027 0700 0100
0158 5400 1400 4A00 2700 5D58 5400 4A00
1400 5D00 2758 5400 4A00 4A00 5D00 5D58
A000 8DA0 0083 FF

Type PICT = GNRL
,146
.H
006D 0007 0007 0068 0068 1101 A000 82A0
008C 0100 0A00 0700 0700 6800 680A 0000
0000 0000 0000 0B00 1B00 1B44 0009 0009
0066 0066 0700 0200 0248 0AFF FFFF FFFF
FFFF FF54 0015 0015 0027 0027 0700 0100
0158 5400 2F00 2F00 4200 4258 5400 4A00
4A00 5D00 5D58 A000 8DA0 0083 FF

Type PICT = GNRL
,145
.H
0063 0007 0007 0068 0068 1101 A000 82A0
008C 0100 0A00 0700 0700 6800 680A 0000
0000 0000 0000 0B00 1B00 1B44 0009 0009
0066 0066 0700 0200 0248 0AFF FFFF FFFF
FFFF FF54 004B 004B 005D 005D 0700 0100
0158 5400 1400 1400 2700 2758 A000 8DA0
0083 FF

Type PICT = GNRL
,144
.H
0059 0007 0007 0068 0068 1101 A000 82A0
008C 0100 0A00 0700 0700 6800 680A 0000
0000 0000 0000 0B00 1B00 1B44 0009 0009
0066 0066 0700 0200 0248 0AFF FFFF FFFF
FFFF FF54 0030 0030 0042 0042 0700 0100
0158 A000 8DA0 0083 FF

Type ICN# = GNRL
  ,128 (0)
.H
include MyIconFile
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

VirtualBox 5.2.6 - x86 virtualization so...
VirtualBox is a family of powerful x86 virtualization products for enterprise as well as home use. Not only is VirtualBox an extremely feature rich, high performance product for enterprise customers... Read more
Espresso 5.1 - Powerful HTML, XML, CSS,...
Note from the developer: For the new Espresso, we changed our versioning and licensing approach with more consistent pricing and a simpler development timeline: "X+1". Each new update would increase... Read more
MacFamilyTree 8.2.7 - Create and explore...
MacFamilyTree gives genealogy a facelift: modern, interactive, convenient and fast. Explore your family tree and your family history in a way generations of chroniclers before you would have loved.... Read more
VueScan 9.6.04 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more
WhatsApp 0.2.8000 - Desktop client for W...
WhatsApp is the desktop client for WhatsApp Messenger, a cross-platform mobile messaging app which allows you to exchange messages without having to pay for SMS. WhatsApp Messenger is available for... Read more
Vivaldi 1.13.1008.40 - An advanced brows...
Vivaldi is a browser for our friends. In 1994, two programmers started working on a web browser. Our idea was to make a really fast browser, capable of running on limited hardware, keeping in mind... Read more
TotalFinder 1.10.7 - Adds tabs, hotkeys,...
TotalFinder is a universally acclaimed navigational companion for your Mac. Enhance your Mac's Finder with features so smart and convenient, you won't believe you ever lived without them. Features... Read more
Box Sync 4.0.7886 - Online synchronizati...
Box Sync gives you a hard-drive in the Cloud for online storage. Note: You must first sign up to use Box. What if the files you need are on your laptop -- but you're on the road with your iPhone? No... Read more
iExplorer 4.1.14 - View and transfer fil...
iExplorer is an iPhone browser for Mac lets you view the files on your iOS device. By using a drag and drop interface, you can quickly copy files and folders between your Mac and your iPhone or... Read more
WhatRoute 2.1.1 - Geographically trace o...
WhatRoute is designed to find the names of all the routers an IP packet passes through on its way from your Mac to a destination host. It also measures the round-trip time from your Mac to the router... Read more

Latest Forum Discussions

See All

Tako Bubble guide - Tips and Tricks to S...
Tako Bubble is a pretty simple and fun puzzler, but the game can get downright devious with its puzzle design. If you insist on not paying for the game and want to manage your lives appropriately, check out these tips so you can avoid getting... | Read more »
Everything about Hero Academy 2 - The co...
It's fair to say we've spent a good deal of time on Hero Academy 2. So much so, that we think we're probably in a really good place to give you some advice about how to get the most out of the game. And in this guide, that's exactly what you're... | Read more »
Everything about Hero Academy 2: Part 3...
In the third part of our Hero Academy 2 guide we're going to take a look at the different modes you can play in the game. We'll explain what you need to do in each of them, and tell you why it's important that you do. [Read more] | Read more »
Everything about Hero Academy 2: Part 2...
In this second part of our guide to Hero Academy 2, we're going to have a look at the different card types that you're going to be using in the game. We'll split them up into different sections too, to make sure you're getting the most information... | Read more »
Everything about Hero Academy 2: Part 1...
So you've started playing Hero Academy 2, and you're feeling a little bit lost. Don't worry, we've got your back. So we've come up with a series of guides that are going to help you get to grips with everything that's going on in the game. [Read... | Read more »
What mobile gaming can learn from the Ni...
While Nintendo might not have had things all its own way since it began developing for mobile, one thing it has got right is the release of the Switch. After the disappointment of the WiiU, which I still can't really explain, the Switch felt a... | Read more »
Programmer of Sonic The Hedgehog launche...
Japanese programmer Yuji Naka is best known for leading the team that created the original Sonic The Hedgehog. He’s moved on from the speedy blue hero since then, launching his own company based in Tokyo – Prope Games. Legend of Coin is the... | Read more »
Why doesn't mobile gaming have its...
The Overwatch League is a pretty big deal. It's an attempt to really push eSports into the mainstream, by turning them into, well, regular sports. But slightly less sweaty. It's a lavish affair with teams from all around the world, and more... | Read more »
Give Webzen’s new billiard game PoolTime...
Best known for producing hugely popular MMO titles, South Korean publisher Webzen is now taking aim at a different genre altogether. PoolTime is a realistic eight ball pool simulator, allowing you to compete in real-time matches against players... | Read more »
Let Them Come Guide - How to survive aga...
Let Them Come is all about making it as far as possible against overwhelming odds. Check out some of these tips to help you last a little longer in your unwinnable fight: [Read more] | Read more »

Price Scanner via MacPrices.net

9.7-inch 2017 WiFi iPads on sale starting at...
B&H Photo has 9.7″ 2017 WiFi #Apple #iPads on sale for $30 off MSRP for a limited time. Shipping is free, and pay sales tax in NY & NJ only: – 32GB iPad WiFi: $299, $30 off – 128GB iPad WiFi... Read more
Wednesday deal: 13″ MacBook Pros for $100-$15...
B&H Photo has 13″ #Apple #MacBook Pros on sale for up to $100-$150 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13-inch 2.3GHz/128GB Space Gray... Read more
Apple now offering Certified Refurbished 2017...
Apple has Certified Refurbished 9.7″ WiFi iPads available for $50-$80 off the cost of new models. An Apple one-year warranty is included with each iPad, and shipping is free: – 9″ 32GB WiFi iPad: $... Read more
10″ iPad Pros on sale for $50-$75 off MSRP, n...
B&H Photo has 10″ and #Apple #iPad Pros on sale for up to $75 off MSRP. Shipping is free, and B&H charges sales tax in NY & NJ only. Note that some sale prices are restricted to certain... Read more
Apple refurbished Mac minis available startin...
Apple has restocked Certified Refurbished Mac minis starting at $419. Apple’s one-year warranty is included with each mini, and shipping is free: – 1.4GHz Mac mini: $419 $80 off MSRP – 2.6GHz Mac... Read more
Amazon offers Silver 13″ Apple MacBook Pros f...
Amazon has new Silver 2017 13″ #Apple #MacBook Pros on sale today for up to $150 off MSRP, each including free shipping: – 13″ 2.3GHz/128GB Silver MacBook Pro (MPXR2LL/A): $1199.99 $100 off MSRP – 13... Read more
Sale: 12″ 1.3GHz MacBooks on sale for $1499,...
B&H Photo has Space Gray and Rose Gold 12″ 1.3GHz #Apple MacBooks on sale for $100 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 12″ 1.3GHz Space... Read more
Apple offers Certified Refurbished 2017 iMacs...
Apple has a full line of Certified Refurbished iMacs available for up to $350 off original MSRP. Apple’s one-year warranty is standard, and shipping is free. The following models are available: – 27... Read more
13″ MacBook Airs on sale for $120-$100 off MS...
B&H Photo has 2017 13″ 128GB MacBook Airs on sale for $120 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13″ 1.8GHz/128GB MacBook Air (MQD32LL/A): $... Read more
15″ Touch Bar MacBook Pros on sale for up to...
Adorama has Space Gray 15″ MacBook Pros on sale for $200 off MSRP. Shipping is free, and Adorama charges sales tax in NJ and NY only: – 15″ 2.8GHz MacBook Pro Space Gray (MPTR2LL/A): $2199, $200 off... Read more

Jobs Board

*Apple* Solutions Consultant - Apple (United...
# Apple Solutions Consultant Job Number: 113384559 Brandon, Florida, United States Posted: 10-Jan-2018 Weekly Hours: 40.00 **Job Summary** Are you passionate about Read more
Art Director, *Apple* Music + Beats1 Market...
# Art Director, Apple Music + Beats1 Marketing Design Job Number: 113258081 Santa Clara Valley, California, United States Posted: 05-Jan-2018 Weekly Hours: 40.00 Read more
*Apple* Pay & Wallet Engineering Manager...
# Apple Pay & Wallet Engineering Manager, Apple Watch Job Number: 83769531 Santa Clara Valley, California, United States Posted: 06-Nov-2017 Weekly Hours: 40.00 Read more
UI Tools and Automation Engineer, *Apple* M...
# UI Tools and Automation Engineer, Apple Media Products Job Number: 113136387 Santa Clara Valley, California, United States Posted: 11-Jan-2018 Weekly Hours: 40.00 Read more
Senior Product Architect, *Apple* Pay - App...
# Senior Product Architect, Apple Pay Job Number: 58046427 Santa Clara Valley, California, United States Posted: 04-Jan-2018 Weekly Hours: **Job Summary** Apple , Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.