TweetFollow Us on Twitter

Sprocket Menus 4
Volume Number:11
Issue Number:8
Column Tag:Getting Started

Sprocket Menus, Part 4

By Dave Mark, MacTech Magazine Regular Contributing Author

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

Last month, we added code to our SprocketPicText project to implement the Style and most of the Size submenus that appear underneath the Text menu when a TTextWindow is the frontmost window. This month, we’re going to finish up the Size menu by implementing the Other... item. We’ll also add code to implement the Font submenu. Finally, we’ll add the code to the TPictureWindow to implement the two items in the Picture window that appears whenever a TPictureWindow is the frontmost window.

A DLOG and a DITL

We’ll start off by adding a single DLOG resource and its associated DITL resource to SprocketStarter.rsrc. The two resources will implement a dialog that prompts the user to type in a new font size. The dialog will be brought up when the user selects Other... from the Size menu.

• Start by duplicating last month’s SprocketStarter folder (be sure you remove objects first if you care about disk space).

Don’t duplicate the Sprocket folder, since it hasn’t changed from last month. Last month’s Sprocket-Starter folder was named “SprocketPicText.04/25/95”. Name the new copy “SprocketPicText.05/31/95”.

Open up your new Sprocket-Starter folder and launch either the 68K or PowerMac SprocketStarter project. When your project window appears, double-click on the file named SprocketStarter.rsrc to launch your favorite resource editor.

• Create a new DLOG with a resource ID of 1000, a top of 71, left of 97, bottom of 146, and a right of 363. Be sure you select the modal dialog window type.

• Create a DITL with a resource ID of 1000.

• Create a pushbutton (item#1) with the text OK, a top of 42, left of 184, bottom of 62, and a right of 253.

• Create a pushbutton (item#2) with the text Cancel, a top of 42, left of 99, bottom of 62, and a right of 168.

• Create a static text item (item#3) with the text Font size:, a top of 13, left of 13, bottom of 29, and a right of 81.

• Create an editable text item (item#4) with no text, a top of 13, left of 91, bottom of 29, and a right of 250.

Figure 1 shows the finished dialog, as displayed by Resorcerer.

Figure 1. The DLOG and DITL resources, as displayed by Resorcerer.

TextWindow.h

Quit your resource editor, saving your changes, and return to CodeWarrior. Now open the file TextWindow.h and make these changes:

• Add these lines to the top of the file, just before the enum:

#include <Fonts.h>

const longkCancelButtonPressed = 0L;
const short iNumberEditTextField = 4;
const short kGetNumberDialogResID = 1000;

• Add these member function declarations to the TTextWindow class:

 virtual long    DoNumberDialog( void );
 virtual void    SetOtherMenuItemString( void );
 virtual void    PascalStringCat( Str255 dest, Str255 source );
 virtual void    AdjustFontMenu( void );
 virtual Boolean DoMenuSelection( short menu, short item );

TextWindow.cp

Close TextWindow.h and open the file TextWindow.cp. Make these changes:

• Add to the file the member function

TTextWindow::DoNumberDialog()

Here’s the source code:

long
TTextWindow::DoNumberDialog( void )
{
 BooleandialogDone = false;
 Str255 text;
 Handle itemHandle;
 short  itemHit, itemType;
 Rect   itemRect;
 long   returnValue;
 DialogPtrdialog;
 
 dialog = GetNewDialog( kGetNumberDialogResID, NULL, 
 (WindowPtr)-1L );
 
 if ( dialog == NULL )
 return kCancelButtonPressed;
 
 SetDialogDefaultItem( dialog, ok );
 SetDialogCancelItem( dialog, cancel );
 
 NumToString( (long)fCurrentFontSize, text );
 
 GetDialogItem( dialog, iNumberEditTextField, &itemType,
 &itemHandle, &itemRect );
 SetDialogItemText( itemHandle, text );
 
 SelectDialogItemText( dialog, iNumberEditTextField, 0, 32767 );
 
 ShowWindow( dialog );
 
 do
 {
 ModalDialog( NULL, &itemHit );
 
 if ( itemHit == ok )
 {
 GetDialogItem( dialog, iNumberEditTextField, &itemType,
 &itemHandle, &itemRect );
 GetDialogItemText( itemHandle, text );
 
 StringToNum( text, &returnValue );
 
 if ( (returnValue < kMinimumFontSize) ||
 (returnValue > kMaximumFontSize) )
 {
 SysBeep( 20 );
 SelectDialogItemText( dialog, iNumberEditTextField,
  0, 32767 );
 itemHit = iNumberEditTextField;
 }
 else
 dialogDone = true;
 }
 else if ( itemHit == cancel )
 {
 returnValue = kCancelButtonPressed;
 dialogDone = true;
 }
 } while ( ! dialogDone );
 
 DisposeDialog( dialog );
 
 return returnValue;
}

This function implements the dialog box whose resources you created earlier. The dialog allows the reader to enter a new font size for the frontmost text window. The user must enter a size between kMinimumFontSize and kMaximumFontSize, otherwise we’ll beep and highlight the editable text field.

We’ll start off by converting the current text size, stored in the data member fCurrentFontSize, into a Str255 and we’ll place the Str255 version of the number in the dialog’s editable text field. We’ll then highlight the text field so if the user wants to type a new value, they don’t have to select the text first to replace it.

Inside the dialog loop, if the user presses the OK button, we’ll convert the text field to a long, then check to be sure it’s in range. If so, we’ll set dialogDone to true so we drop out of the loop.

If they hit the Cancel button, we’ll set the return value to kCancelButtonPressed, which has been pre-defined as 0L, which we know won’t be a legal font size.

Finally, once we drop out of the loop, we’ll dispose of the dialog and return returnValue.

• Add to the file the member function

TTextWindow::PascalStringCat()

Here’s the source code:

void
TTextWindow::PascalStringCat( Str255 dest, Str255 source )
{
 unsigned char i, destStringLength, sourceStringLength;
 
 destStringLength = dest[0];
 sourceStringLength = source[0];
 
 if ( sourceStringLength <= 0 )
 return;
 
 for ( i=1; i<=sourceStringLength; i++ )
 dest[i+destStringLength] = source[i];
 
 dest[0] += sourceStringLength;
}

Much like the function strcat(), this function appends the source pascal string on to the end of thepascal string already in dest. The length byte from source is deleted and the length byte of dest is incremented to reflect its new length.

This function is called by SetOtherMenuItemString() which we’ll add next.

• Add to the file the member function

TTextWindow::SetOtherMenuItemString() .

Here’s the source code:

void
TTextWindow::SetOtherMenuItemString( void )
{
 Str255 menuItemStr = "\pOther (";
 Str255 numberStr;
 
 NumToString( (long)fCurrentFontSize, numberStr );
 
 PascalStringCat( menuItemStr, numberStr );
 PascalStringCat( menuItemStr, "\p)..." );
 
 gMenuBar->SetItemString( cFontSizeOther, menuItemStr );
}

This function changes the Other... item in the Size menu to reflect the current text size. For example, if the current size is 37, the menu item should read Other (37).... Note that the Size menu we’ve implemented here is not my invention. It comes from the pages of Inside Macintosh and represents the standard you should use in your own applications.

SetOtherMenuItemString() starts off by defining a Str255 named menuItemStr with the text “Other (”. We’ll then convert the current size to a pascal string and append it to menuItemStr. Finally, we’ll append the pascal string “)...” to menuItemStr then call the TMenuBar member function SetItemString() to change the item associated with the command cFontSizeOther to menuItemStr.

• Add a call of SetOtherMenuItemString() to the end of the member function AdjustSizeMenu(). AdjustSizeMenu() gets called when a mousedown occurs in the menu bar.

• Add to the file the member function

TTextWindow::DoMenuSelection()

Here’s the source code:

Boolean
TTextWindow::DoMenuSelection( short menu, short item )
{
 Str255 itemString;
 short  fontNumber;
 
 if ( menu == mTextFont )
 {
 GetMenuItemText( fgFontSubMenu, item, itemString );
 GetFNum( itemString, &fontNumber );
 SetPort( fWindow );
 TextFont( fontNumber );
 InvalRect( &fWindow->portRect );
 return true;
 }
 else
 return false;
}

DoMenuSelection() gets called before any of the command dispatching functions, giving you a chance to handle menus that contain unregistered items. Since there is no way to construct a CMNU resource for the Font menu (how would we assign command numbers when we don’t know how many or which fonts are installed?), we’ll handle selections from the Font menu in this function.

Before you read on, take a look at the function this function overrides, TWindow::DoMenuSelection(). Note that it simply returns false. If DoMenuSelection() returns false, Sprocket converts the menu selection to a command number and handles it that way. If DoMenuSelection() returns true, Sprocket assumes the menu selection has been processed and does nothing more.

DoMenuSelection() first checks to be sure the selection was from the Font menu. If so, it converts the selected item to a font number, then calls TextFont() to set the font for the associated fWindow, forces a redraw, and returns true.

Next, we’re going to make some changes to the function DoMenuCommand(), our menu command dispatcher that gets called if DoMenuSelection() returns false.

• Add a declaration of the variable newSize at the top of TTextWindow::DoMenuCommand():

 long newSize;

• Still in TTextWindow::DoMenuCommand(), edit the cFontSizeOther case in the switch statement to read:

 case cFontSizeOther:
 newSize = DoNumberDialog();
 if ( newSize != kCancelButtonPressed )
 SetNewTextSize( newSize );
 return true;
 break;

This case gets executed when Other (xx)... is selected from the Size menu. We’ll start by calling DoNumberDialog() to prompt the user for a new size. If a new size was entered, we’ll call SetNewTextSize() to set the new size.

Now we need to add the code that places the check mark next to the current font in the Font menu.

• Add a call of the function AdjustFontMenu() to the member function TTextWindow::AdjustMenusBeforeMenuSelection(). Here’s the new version of TTextWindow::AdjustMenusBeforeMenuSelection():

void
TTextWindow::AdjustMenusBeforeMenuSelection( void )
{
 AdjustFontMenu();
 AdjustSizeMenu();
 AdjustStyleMenu();
}

• Add the member function TTextWindow::AdjustFontMenu() to the file. Here’s the source code:

void
TTextWindow::AdjustFontMenu( void )
{
 short  fontNumber, numFonts, i;
 Str255 fontName, itemName;
 
 fontNumber = fWindow->txFont;
 GetFontName( fontNumber, fontName );
 
 numFonts = CountMItems( fgFontSubMenu );
 
 for ( i=1; i<=numFonts; i++ )
 {
 GetMenuItemText( fgFontSubMenu, i, itemName );
 
 if ( EqualString( itemName, fontName, true, true ) )
 CheckItem( fgFontSubMenu, i, true);
 else
 CheckItem( fgFontSubMenu, i, false);
 }
}

AdjustFontMenu() turns the current font family id into its name. Next, CountMItems() is called to return the number of items in the Font menu. The for loop steps through each of the items, checking to see if the item is equal to the font name. If so, the item gets a check mark. If not, the item does not get a check mark.

PictureWindow.h

Our final task is to add the code that implements the two items in the Picture menu, Centered and Upper Left. Centered causes the picture to be drawn centered in the picture window and Upper Left causes the picture to be pressed against the upper-left corner of the window.

• Close TextWindow.cp and open the file PictureWindow.h.

• Add the declaration of the data member fIsPictureCentered to the TPictureWindow class declaration:

 BooleanfIsPictureCentered;

• Add the declarations of the member functions DoMenuCommand() and AdjustMenusBeforeMenuSelection() to the TPictureWindow class declaration:

 virtual Boolean DoMenuCommand( unsigned long menuCommand );
 virtual void    AdjustMenusBeforeMenuSelection( void );

PictureWindow.cp

Close PictureWindow.h and open the file PictureWindow.cp.

• Add the code that initializes fIsPictureCentered to the TPictureWindow constructor:

 fIsPictureCentered = true;

• In the function TPictureWindow::Draw(), edit the last two lines of code so Draw() looks like this:

void
TPictureWindow::Draw(void)
{
 PicHandlepic;
 Rect   r;
 
 r = fWindow->portRect;
 EraseRect( &r );
 
 if ( fDraggedPicHandle == nil )
 pic = this->LoadDefaultPicture();
 else
 pic = fDraggedPicHandle;

 if ( fIsPictureCentered )
 {
 this->CenterPict( pic, &r );
 }
 else
 {
 r = (**pic).picFrame;
 OffsetRect( &r, - r.left, - r.top );
 }
 
 DrawPicture( pic, &r );
}

Basically, we’ve made Draw() depend on fIsPictureCentered.

• Add the member function TPictureWindow::DoMenuCommand() to the file. Here’s the source code:

Boolean
TPictureWindow::DoMenuCommand( unsigned long menuCommand )
{
 switch ( menuCommand )
 {
 case cCentered:
 fIsPictureCentered = true;
 SetPort( fWindow );
 InvalRect( &fWindow->portRect );
 return true;
 break;
 
 case cUpperLeft:
 fIsPictureCentered = false;
 SetPort( fWindow );
 InvalRect( &fWindow->portRect );
 return true;
 break;
 }

 return false;
}

This code gets called in response to a selection from the Picture menu.

• Add the member function TPictureWindow::AdjustMenusBeforeMenuSelection() to the file. Here’s the source code:

void
TPictureWindow::AdjustMenusBeforeMenuSelection( void )
{
 if ( fIsPictureCentered )
 {
 gMenuBar->EnableAndCheckCommand( cCentered, true, true );
 gMenuBar->EnableAndCheckCommand( cUpperLeft, true, false );
 }
 else
 {
 gMenuBar->EnableAndCheckCommand( cCentered, true, false );
 gMenuBar->EnableAndCheckCommand( cUpperLeft, true, true );
 }
}

Depending on the value of fIsPictureCentered, this code places a check mark next to the appropriate item in the Picture menu.

SprocketStarter.cp

Several months ago, when we first started this program, we added code to the function HandleMenuCommand() in SprocketStarter.cp that beeped when either of the Picture items was selected. Since we now handle these two cases inside the file PictureWindow.cp (as it should be done), we need to delete the two commands from the case statement in HandleMenuCommand() inside SprocketStarter.cp.

• Close the file PictureWindow.cp and open the file SprocketStarter.cp.

• Find the function HandleMenuCommand(). Inside the switch statement, delete the cases (all the way down to the break) for cCentered and cUpperLeft.

Running SprocketStarter

Well, that’s about it. Now’s the time to test your new creation. Select Run from the Project menu. When it runs, SprocketStarter will create a new text window, and the Text menu will appear at the end of the menu bar. Click on the Text menu, then make a selection from the Font submenu (Figure 2). The font of the frontmost text window should change and, the next time you select from the Font submenu, the check mark should appear next to this new font.

Figure 2. The Font submenu, showing the checkmark by Geneva
with Chicago selected.

Next, select Other (18)... from the Size submenu (we set up18 as the default font size). The font size dialog will appear, with the number 18 in the editable text field. Type 0 and click the OK button. You’ll hear a beep and the 0 will be highlighted. Type 37 and click the OK button (Figure 3). This time, your new font size is accepted and the text in the text window is redrawn showing the new font size.

Figure 3. The font size dialog that appears when you select Other (xx)...
from the Size submenu.

Once again, pull down the Text menu and bring down the Size submenu. Notice that the last item now reads Other (37)... and that the check mark has moved to this item (Figure 4).

Figure 4. The Size submenu with the Other (37)... item selected and checked.

Finally, create a picture window, then select one of the two items from the Picture menu that appears. With each selection, the picture in the picture window should be redrawn to match the selection and the check mark should appear next to the last selected item.

Figure 5. The Picture menu.

About the only thing left to do with this code is to make the sizes in the Size menu appear in outline font if they are available on the current machine or in regular font if that size is not available. Take some time to add this code. A good place to add the code is in the function TTextWindow::SetUpStaticMenu(), after you set up the static member fgSizeSubMenu. You’ll need to use the functions SetItemStyle() and RealFont() for each of the 6 sizes in the menu.

What’s Next

I hope the last few columns have given you an appreciation for the complexity and coolness of a framework. One thing I’ve grown to appreciate is the incredible amount of work it must have been for Dave Falkenburg to build Sprocket. Way to go, Dave!

I’m not sure what topic we’ll be tackling next month. I’ve been thinking about building a small PowerPlant project, just to explore the differences between Sprocket and PowerPlant. On the other hand, I’ve really got a hankering to build a tool palette using Sprocket. And there’s this cool OpenDoc part I’ve been fiddling with. Any preferences? Send some email my way...

See you next month!

 
AAPL
$99.76
Apple Inc.
+2.09
MSFT
$44.08
Microsoft Corpora
+0.45
GOOG
$520.84
Google Inc.
+9.67

MacTech Search:
Community Search:

Software Updates via MacUpdate

Macgo Blu-ray Player 2.10.9.1750 - Blu-r...
Macgo Mac Blu-ray Player can bring you the most unforgettable Blu-ray experience on your Mac. Overview Macgo Mac Blu-ray Player can satisfy just about every need you could possibly have in a Blu-ray... Read more
Apple iOS 8.1 - The latest version of Ap...
The latest version of iOS can be downloaded through iTunes. Apple iOS 8 comes with big updates to apps you use every day, like Messages and Photos. A whole new way to share content with your family.... Read more
TechTool Pro 7.0.5 - Hard drive and syst...
TechTool Pro is now 7, and this is the most advanced version of the acclaimed Macintosh troubleshooting utility created in its 20-year history. Micromat has redeveloped TechTool Pro 7 to be fully 64... Read more
PDFKey Pro 4.0.2 - Edit and print passwo...
PDFKey Pro can unlock PDF documents protected for printing and copying when you've forgotten your password. It can now also protect your PDF files with a password to prevent unauthorized access and/... Read more
Yasu 2.9.1 - System maintenance app; per...
Yasu was originally created with System Administrators who service large groups of workstations in mind, Yasu (Yet Another System Utility) was made to do a specific group of maintenance tasks... Read more
Hazel 3.3 - Create rules for organizing...
Hazel is your personal housekeeper, organizing and cleaning folders based on rules you define. Hazel can also manage your trash and uninstall your applications. Organize your files using a... Read more
Autopano Giga 3.7 - Stitch multiple imag...
Autopano Giga allows you to stitch 2, 20, or 2,000 images. Version 3.0 integrates impressive new features that will definitely make you adopt Autopano Pro or Autopano Giga: Choose between 9... Read more
MenuMeters 1.8 - CPU, memory, disk, and...
MenuMeters is a set of CPU, memory, disk, and network monitoring tools for Mac OS X. Although there are numerous other programs which do the same thing, none had quite the feature set I was looking... Read more
Coda 2.5 - One-window Web development su...
Coda is a powerful Web editor that puts everything in one place. An editor. Terminal. CSS. Files. With Coda 2, we went beyond expectations. With loads of new, much-requested features, a few... Read more
Arq 4.6.1 - Online backup to Google Driv...
Arq is super-easy online backup for the Mac. Back up to your own Google Drive storage (15GB free storage), your own Amazon Glacier ($.01/GB per month storage) or S3, or any SFTP server. Arq backs up... Read more

Latest Forum Discussions

See All

This Week at 148Apps: October 13-17, 201...
Expert App Reviewers   So little time and so very many apps. What’s a poor iPhone/iPad lover to do? Fortunately, 148Apps is here to give you the rundown on the latest and greatest releases. And we even have a tremendous back catalog of reviews; just... | Read more »
Angry Birds Transformers Review
Angry Birds Transformers Review By Jennifer Allen on October 20th, 2014 Our Rating: :: TRANSFORMED BIRDSUniversal App - Designed for iPhone and iPad Transformed in a way you wouldn’t expect, Angry Birds Transformers is a quite... | Read more »
GAMEVIL Announces the Upcoming Launch of...
GAMEVIL Announces the Upcoming Launch of Mark of the Dragon Posted by Jessica Fisher on October 20th, 2014 [ permalink ] Mark of the Dragon, by GAMEVIL, put | Read more »
Interview With the Angry Birds Transform...
Angry Birds Transformers recently transformed and rolled out worldwide. This run-and-gun title is a hit with young Transformers fans, but the ample references to classic Transformers fandom has also earned it a place in the hearts of long-time... | Read more »
Find Free Food on Campus with Ypay
Find Free Food on Campus with Ypay Posted by Jessica Fisher on October 20th, 2014 [ permalink ] iPhone App - Designed for the iPhone, compatible with the iPad | Read more »
Strung Along Review
Strung Along Review By Jordan Minor on October 20th, 2014 Our Rating: :: GOT NO STRINGSUniversal App - Designed for iPhone and iPad A cool gimmick and a great art style keep Strung Along from completely falling apart.   | Read more »
P2P file transferring app Send Anywhere...
File sharing services like Dropbox have security issues. Email attachments can be problematic when it comes to sharing large files. USB dongles don’t fit into your phone. Send Anywhere, a peer-to-peer file transferring application, solves all of... | Read more »
Zero Age Review
Zero Age Review By Jordan Minor on October 20th, 2014 Our Rating: :: MORE THAN ZEROiPad Only App - Designed for the iPad With its mind-bending puzzles and spellbinding visuals, Zero Age has it all.   | Read more »
Hay Ewe Review
Hay Ewe Review By Campbell Bird on October 20th, 2014 Our Rating: :: SAVE YOUR SHEEPLEUniversal App - Designed for iPhone and iPad Pave the way for your flock in this line drawing puzzle game from the creators of Worms.   | Read more »
My Very Hungry Caterpillar (Education)
My Very Hungry Caterpillar 1.0.0 Device: iOS Universal Category: Education Price: $3.99, Version: 1.0.0 (iTunes) Description: Care for your very own Very Hungry Caterpillar! My Very Hungry Caterpillar will captivate you as he crawls... | Read more »

Price Scanner via MacPrices.net

2013 15-inch 2.0GHz Retina MacBook Pro availa...
B&H Photo has leftover previous-generation 15″ 2.0GHz Retina MacBook Pros now available for $1599 including free shipping plus NY sales tax only. Their price is $400 off original MSRP. B&H... Read more
Updated iPad Prices
We’ve updated our iPad Air Price Tracker and our iPad mini Price Tracker with the latest information on prices and availability from Apple and other resellers, including the new iPad Air 2 and the... Read more
Apple Pay Available to Millions of Visa Cardh...
Visa Inc. brings secure, convenient payments to iPad Air 2 and iPad mini 3as well as iPhone 6 and 6 Plus. Starting October 20th, eligible Visa cardholders in the U.S. will be able to use Apple Pay,... Read more
Textkraft Pocket – the missing TextEdit for i...
infovole GmbH has announced the release and immediate availability of Textkraft Pocket 1.0, a professional text editor and note taking app for Apple’s iPhone. In March 2014 rumors were all about... Read more
C Spire to offer iPad Air 2 and iPad mini 3,...
C Spire on Friday announced that it will offer iPad Air 2 and iPad mini 3, both with Wi-Fi + Cellular, on its 4G+ LTE network in the coming weeks. C Spire will offer the new iPads with a range of... Read more
Belkin Announces Full Line of Keyboards and C...
Belkin International has unveiled a new lineup of keyboard cases and accessories for Apple’s newest iPads, featuring three QODE keyboards and a collection of thin, lightweight folios for both the... Read more
Verizon offers new iPad Air 2 preorders for $...
Verizon Wireless is accepting preorders for the new iPad Air 2, cellular models, for $100 off MSRP with a 2-year service agreement: - 16GB iPad Air 2 WiFi + Cellular: $529.99 - 64GB iPad Air 2 WiFi... Read more
Price drops on refurbished Mac minis, now ava...
The Apple Store has dropped prices on Apple Certified Refurbished previous-generation Mac minis, with models now available starting at $419. Apple’s one-year warranty is included with each mini, and... Read more
Apple refurbished 2014 MacBook Airs available...
The Apple Store has Apple Certified Refurbished 2014 MacBook Airs available for up to $180 off the cost of new models. An Apple one-year warranty is included with each MacBook, and shipping is free.... Read more
Refurbished 2013 MacBook Pros available for u...
The Apple Store has Apple Certified Refurbished 13″ and 15″ MacBook Pros available starting at $929. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.5GHz MacBook Pros (4GB RAM/... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Position Opening at *Apple* - Apple (United...
…customers purchase our products, you're the one who helps them get more out of their new Apple technology. Your day in the Apple Store is filled with a range of Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** At the Apple Store, you connect business professionals and entrepreneurs with the tools they need in order to put Apple solutions to work in their Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** The Apple Store is a retail environment like no other - uniquely focused on delivering amazing customer experiences. As an Expert, you introduce people Read more
Position Opening at *Apple* - Apple (United...
**Job Summary** As businesses discover the power of Apple computers and mobile devices, it's your job - as a Solutions Engineer - to show them how to introduce these Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.