TweetFollow Us on Twitter

SuperPaint PlugIns
Volume Number:6
Issue Number:2
Column Tag:C Workshop

Related Info: Quickdraw

SuperPaint Plug-ins

By Linda McLennan, Cardiff, CA

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

SuperPaint Plug-in Tools in Think C

[Linda McLennan has a degree in Information Science from University of California at Santa Cruz. She was a Software Engineer for Silicon Beach Software for 2 years. As a member of the SuperPaint 2.0 team she was involved in developing the plug-in interface and creating many of the tools that shipped with SuperPaint. At present, she is an independent consultant.]

One of the exciting features of SuperPaint 2.0 is the introduction of Plug-in modules to provide flexibility and extensibility. These modules are executable files that reside separately from SuperPaint and are automatically incorporated into the application. The Plug-in module concept provides a mechanism for adding features to SuperPaint without modifying the application itself. This opens up the opportunity for developers to create sets of custom tools and commands which can be marketed independently with no requirement for permission or licensing from Silicon Beach Software. SuperPaint provides the framework and handles much of the overhead so that you can concentrate on the more creative task of developing the special effects.

SuperPaint 2.0 supports two types of Plug-in modules: interactive paint tools and transformation menu commands. Plug-ins are placed in SuperPaint’s special folder known as the Pouch. At startup time, SuperPaint scans the pouch for Plug-ins and after verifying that they are compatible with the version of SuperPaint that is running, incorporates them into the application as appropriate for each type. Interactive paint tools will appear automatically in the expandable paint tool palette as shown in Figure 1. Menu Commands will be added to the bottom of the Paint menu. The main distinction between palette tools and menu commands is in how they are used. An interactive tool generally creates an image continuously as the mouse moves while a menu command will act on a currently selected area rather than using mouse position. This article will focus on interactive paint tools. (See Mike Ogawa’s article on SuperPaint Menu Commands in this same issue.)

Anatomy of a Plug-in Module

The Plug-in module contains a stand-alone code resource. Since execution of a code resource begins with the first byte, the main routine must be linked at the beginning, or the code module must begin with a jump to the main entry point. With Think C, the ordering of the routines is controlled by the development system and a standard header with a jump to the routine named ‘main’ is included automatically when linking as a code resource. When using other development environments, special care must be taken to ensure that the object file containing the main entry point is linked first.

Think C 4.0 supports Multi-Segment code resources which allows you to create a Plug-in of virtually any size. When using other development environments that do not provide this support, the code resource must be a single segment.

In general, a Plug-in should not use global data. Think C does provide a mechanism for accessing globals through A4 which is sufficient for some situations. However, this is not recommended for saving variable data between calls to the Plug-in. There is the possibility that the code resource may be purged and reloaded by SuperPaint between calls causing the global data area to be reinitialized. If the Plug-in needs to maintain variable data between calls, it should allocate space in the heap for storing the data and return the handle to SuperPaint in the refCon as described in a following section. The global data issue is a frequent source of problems in writing Plug-ins, particularly since it isn’t always obvious that you are actually using globals. (Mike Ogawa’s article discusses this in greater detail.) It is recommended that you read about using global data in code resources in the User’s Manual for your development environment. MPW users may also want to read Macintosh Technical Note #256 titled “Globals in Stand-Alone Code”.

The code resource for an interactive tool is type ‘BWit’ in a file of the same type. The file creator should be the same as SuperPaint ‘SPNT’ in order to pick up the plug icon from the application. However, if you have a plug-in that is a commercial product you can give it its own creator and icon. The resource name of the ‘BWit’ is the name that will show up in SuperPaint’s About Box in the About Plug-ins list.

The Plug-in must also contain a ‘PiMI’’ resource indicating the interface version for the plug-in module. The PiMI resource contains the version number in a 16-bit integer. This article describes version 1 of the interface.

The Plug-in provides its icon for the tool palette as a SICN resource and can have any number of resources such as cursors, menus, dialogs, etc. keeping certain guidelines in mind for the numbering of the resources. The ‘BWit’ resource should be numbered 16000 or greater. This is the base number for the tool and all other resources associated with the tool should be numbered from this base number. Multiple resources of the same type should start with the base number and be numbered contiguously upward. The Plug-in can have hierarchical submenus with resource IDs following the general guidelines but the menu IDs must be in the range from 200-235.

The Plug-in should not assume constant resource IDs, but use the base number passed by SuperPaint instead. The reason for these guidelines is to allow for renumbering of the resources to prevent conflicts with other Plug-ins that may be placed in the same file. All resources should be marked as purgeable.

Figure 1. Expandable Paint Tool Palette

The Plug-in Interface

The Plug-in code module is created with the main procedure using a Pascal interface. The calling sequence for the main procedure is as follows:

/* 1 */

 pascal void main( selector, tDataPtr, refCon, returnCode )

 short  selector;
 ToolDataPtrtDataPtr;
 long   *refCon;
 short  *returnCode;

The selector parameter is a number which identifies the type of action the tool is to perform on a particular call. The selectors are:

toolAbout Provide “About Box” information

toolSelected Tool selected

toolDblClick Tool double-clicked in palette

toolKeyDown Key event while tool is selected

toolMouseDown Mouse down with tool selected

toolStillDown Mouse button still down

toolMouseUp End of mouse down event

toolMenuEvent Menu event in tool’s menu

toolMenuInsert Tool can put up its menus

toolMenuDelete Tool must remove its menus

toolIdle Mouse button up with tool active

toolDeselected Tool deselected

toolRequestComp Special request completed

The paramPtr parameter is a pointer to the ToolDataRec structure of information passed between SuperPaint and the tool.

The refCon is a long word that SuperPaint saves for the plug-in module between calls. This allows a module to preserve data such as current tool settings by allocating heap space and passing the handle back to the application at the end of each call.

The returnCode field is a result code passed back to the application after a call to report its success or failure. A returnCode of zero indicates no error. Negative return codes correspond to standard Macintosh errors and positive numbers are available for plug-in specific errors.

The ToolDataRec Structure

The ToolDataRec structure contains fields which pass data to the tool and also back to SuperPaint. It begins with a 16-byte header for general plug-in information with the remaining part of the structure containing information specific to interactive paint tools. The following is a brief description of the fields in this structure.

toolID contains the resource ID of the BWit resource passed to the tool from SuperPaint. The tool should use toolID when loading its resources rather than assuming a specific resource ID. ifVersion contains the version number of the plug-in interface that the calling application is supporting. newPoint contains the current mouse position and oldPoint contains the previous mouse position in local coordinates of the paint window. updateRect passes back to SuperPaint the size of the area of the paint window which has changed. mouseIsDown will be set to true if the mouse button is down. shiftIsDown, cmdIsDown, and optIsDown will be set to true if the corresponding modifier key is down. dblClick will be set to true if a double-click was detected in the paint window.

SuperPaint passes the current setting for the Paint Multiple option in paintMultiple. paintCenter contains true if Paint From Center option is selected, false if Paint From Corner is selected. The fillPatNone and linePatNone fields indicate when the fill pattern and line patterns are set to none. The current fill pattern is passed in curFillPattern. The tool can pass a new fill pattern back to SuperPaint in this field to be used with autoPaint mode. changeFillPat must be set to true at the same time the new pattern is returned.

The possible values for cursorType are:

0 = use crosshair
1 = use cursor resource with base resource ID      
2 = use crosshair which shows current line width
3 = use current brush shape 
4 = use cursor from newCursor field

SuperPaint automatically sets the tool’s cursor when the tool is selected. If the tool wants to change the cursor after that, it sets changeCursor to true and at the same time, sets the cursorType field to specify the new cursor. If the tool sets cursorType to 4 and changeCursor to true, the contents of newCursor will be used for the new cursor. The toolActive flag may be set to true when the tool first becomes active after a toolMouseDown call. Calls of type toolStillDown, toolMouseUp, and toolIdle only occur when the toolActive flag is set.

The usesConstrain option should be set to true if the tool wants the automatic shift key constraint to vertical or horizontal mouse positions. The current brush shape is passed to the tool in curBrush. The curPatList field is a handle to a PAT# which is the currently selected pattern list. A pointer to the current event record is passed in evntRecPtr when the tool is being called for a key event with selector code toolKeyDown.

The autoPaint options are:

 0 = tool doesn’t use autoPaint
 1 = paint at newPoint only
 2 = paint continuously between oldPoint and newPoint

If option 1 or 2 is selected, SuperPaint will paint automatically with the current cursor as the brush shape.

The symmetry field defines the type of symmetry information the tool needs for radial or mirror symmetry:

 0 = tool doesn’t use symmetry 
 1 = pass symmetry information  and call tool for each reflection
 2 = pass symmetry information and call tool for current mouse position 
only

If symmetry is set to 1 or 2, numPts will contain the number of points of symmetry and mirrorPts will contain a pointer to a two-dimensional array of a maximum of nine pairs of symmetry points.

The menuID and menuItem fields pass the menu ID and the menu item number to the tool when an item has been selected in the tool’s menu.

The undoBits field is a BitMap structure which contains the image of the screen before the current active phase. The BitMap structure is set up for the size of the current port. Tools which need to erase a previous step before drawing a new one can use undoBits to restore the screen image between drawing steps.

SuperPaint can make a scratch buffer available to the tool if the usesScratch option is selected. It will pass a BitMap in scratchBits which will be set up for the size of the port. If the scratch area is not available to the tool, the scratchBits.baseAddr will be set to zero.

Special services can be requested from SuperPaint after calls of type toolDblClick and toolMenuEvent by returning the appropriate code in the field requestCode. The possible settings are:

 0 = no request
 1 = invoke edit brush shapes dialog
 2 = invoke the edit SICN dialog

If the requestCode field is set to 1, SuperPaint will respond by bringing up its built-in brush edit dialog and handling the events in it. When the user exits the dialog by clicking OK, SuperPaint will call the tool with the toolRequestComp call and pass the selected brush in the curBrush field. Another kind of tool that uses SICNs could also take advantage of SuperPaint’s built-in SICN editor by setting the requestCode to 2. The tool passes a handle to a SICN list in sicnListHdl and sicnIndex must contain the index of the SICN which is to be selected in the dialog. The sicnIndex field will also return the index of the selected SICN back to the tool with the toolRequestComp call.

Overview of an Interactive Paint Tool

When a tool is selected from the palette, SuperPaint will load the tool’s code resource into the application heap and lock it. It also sets curResFile to the tool’s file. The tool will receive a call of type toolSelected. The refCon parameter will be zero the first time the tool is called, so that a tool can determine if any initialization is required by checking the refCon. If it needs its own global data area, it can allocate space in the heap and return the handle to SuperPaint as the refCon. At this time the tool sets fields in the toolDataRec to specify various options. If a tool has menu resources, they should be loaded and detached the first time the tool is selected. The menu handles can be saved in the tool’s global data area.

The toolSelected call will be followed by a call of type toolMenuInsert. This call is also received when SuperPaint has an activate event. If the tool has menus, it should put them up at this time.

When a tool is selected from the list of plug-ins in the About SuperPaint dialog, it will receive a call of type toolAbout. The tool can put up its own modal dialog or can return a request for SuperPaint to display its TEXT resource.

A mouse down event in the document window will result in a call of type toolMouseDown. If the tool sets the toolActive field to true, it will continue to receive calls of type toolStillDown, toolMouseUp, and toolIdle until the tool sets the toolActive field to false.

Double-clicking a tool’s icon in the palette will result in a call of type toolDblClick. If the tool returns a non-zero requestCode, it will receive another call of type toolRequestComp after the tool’s special request has been completed.

When an item in a tool’s menu is selected, it will receive a call of type toolMenuEvent. If the tool returns a non-zero requestCode, it will receive another call of type toolRequestComp after the tool’s special request has been completed.

A call of type toolKeyDown is sent when a key other than option, shift or command is pressed. This call can occur intermixed with toolStillDown or toolIdle calls if the toolActive flag is set.

When a tool is deselected, it will receive a call of type toolMenuDelete followed by a call of type toolDeselected.

Fuzzy Brush Example

The Fuzzy Brush is a simple example of a brush with options for creating different effects. See Figure 2 for sample output from this tool. The main routine consists of a switch statement on the selector parameter. This tool doesn’t use all possible selectors so the default case handles those cases by returning an empty update area and sets returnCode to zero. The refCon parameter has been defined in this example as a pointer to a handle rather than a pointer to a long to eliminate the necessity of casting every time it is referenced.

Figure 2. Fuzzy Brush Output

When our tool is selected from the palette, we will receive a toolSelected call. We call the FuzzyInit routine to initialize fields in the toolDataRec to set various options. We then check the refCon to see if this is the first time called and if so, allocate space in the heap to store the tool’s global data. The handle to this area is returned to SuperPaint in the refCon.

/* 2 */

 if ( *refCon == nil )
   *refCon =
 NewHandle(sizeof(FuzzyData));

Handling Menus

The tool also gets its menu at the time it is first selected, makes it non-purgeable and detaches it. The toolID passed from SuperPaint is used for the resource ID of the menu rather than assuming a specific resource ID. The tool could have hierarchical sub-menus as well and would load them and detach them all in the same way as its main menu.

We must wait for the appropriate call to actually insert the menu in the menu bar so the menu handle is saved in the FuzzyData structure along with other initial settings for the brush size and effect.

Immediately following the toolSelected call, we will receive a toolMenuInsert call. This call is also received when SuperPaint has an activate event. At this time, we insert our menu and redraw the menu bar. If we had hierarchical sub-menus we would also insert them now. A tool which does not have menus can ignore this call and just return a result code of zero.

When there is an event in the tool’s menu, we receive a toolMenuEvent call with the menu ID and item number passed in the toolDataRec. In our example, we have only one menu so we only need to check which item was selected. If we had sub-menus, it would be necessary to check the menu ID as well to determine which sub-menu had been selected. Our example uses the menu to allow selection of different texture effects. All that we need to do at this time is to save the item number of the new selection in our FuzzyData structure and update the menu by unchecking the previous selection and checking the new one.

Drawing

Now that we are initialized and know how to handle menus, we are ready to do some drawing. There are four calls to the tool when the tool can draw. Before calling the tool, SuperPaint sets up the offscreen drawing port for the tool with all of the current settings such as pen pattern, pen size, paint mode, etc. Fuzzy Brush will draw with the pattern selected in the pattern palette, the line thickness set in the tool palette, selected paint mode, etc. This is the power of writing a plug-in tool - the support is already there for selecting options, auto-scroll while drawing, constraining lines, printing, etc. It also works with symmetry without any additional programming effort. The tool draws into the current port and returns the dimensions of the changed area for SuperPaint to transfer the new image to the screen. If the tool doesn’t do any painting for any of these calls, it should return an empty update rectangle.

The first call we would receive for drawing is the toolMouseDown call. Some tools do actual drawing at this time and others just do some initialization such as moving to or saving the initial mouse down position. In our example, we won’t do any actual drawing yet so we return the empty update rectangle. Since we want to receive followup calls of type toolStillDown, we must set the toolActive flag, but only after verifying that we don’t have a line pattern of ‘none’.

When we receive a toolStillDown call, our tool does its drawing. The simplest example of output at this point can be shown by just drawing a line to the current mouse position and setting the update rectangle to be the area from the previous mouse position to the current one. This would be similar to the pencil tool, or more precisely a freehand line tool since this would draw a line using the currently selected line pattern and pen width. Notice that the update rectangle must be adjusted for the current pen width.

/* 3 */

 case toolStillDown: 
 LineTo( tDataPtr->newPoint.h,
 tDataPtr->newPoint.v );
 Pt2Rect(tDataPtr->oldPoint,
 tDataPtr->newPoint,
 &tDataPtr->updateRect );
 GetPort( &drawingPort );
 tDataPtr->updateRect.right +=     drawingPort->pnSize.h;
 tDataPtr->updateRect.bottom +=    drawingPort->pnSize.v;
 break;

By modifying this short segment of code, you can create a tool with unusual and interesting results. The Fuzzy Brush creates its special effects in the DrawEffect routine by generating a number of random offsets from the current mouse position and just moving to each point and drawing short lines.

A toolMouseUp call signals the end of drawing for the Fuzzy Brush so we clear the toolActive flag and return an empty update rectangle.

Some tools need to continue to draw after the mouse is up. The 3D Box tool is an example of this as it draws the rubber-band lines while placing the 3D part of the box. That kind of tool would not clear the toolActive flag on the first mouse up because it needs to receive toolIdle calls from SuperPaint while the mouse is up. It clears its toolActive flag after another mouse click following the toolIdle calls. The Fuzzy Brush doesn’t use this call and should never receive it since it always clears the toolActive flag when it receives the toolMouseUp call.

Using Key Events

Now we can add enhancements to our example to demonstrate the use of the toolKeyDown call. We receive this call if there is a key pressed which is not a modifier key (option, shift or command key). We determine which key was pressed from the message field of the event record that is passed in the toolDataRec from SuperPaint. The Fuzzy Brush uses keys ‘1’, ‘2’, and ‘3’ to select three different sizes of brushes. The advantage of using keys to change brush size is that we can receive toolKeyDown calls when the mouse is either up or down. This means that we can change brush size on the fly while we are drawing. In our example, we only need to save a new brush size computed from the key pressed. The DrawEffect routine will use the new size the next time it is called.

The About Box

Finally, we come to displaying our About Box. This is our chance to give ourselves credit for the exciting new tools we are creating. This is especially important if you are developing tools commercially. Clicking the “Plug-ins” button in SuperPaint’s About Box leads to a scrolling list of all Plug-ins currently in the pouch as shown in Figure 3. When our tool is selected and the About button clicked, we receive a call to provide information about our tool. There are basically two ways to do this. The easiest way would be to use the TEXT resource option. We simply make a TEXT resource and give it the same resource ID as the tool base ID. Setting the returnCode to textAbout will cause SuperPaint to display our text in a scrolling window.

Figure 3. Plug-ins

/* 4 */
 case toolAbout: *returnCode = textAbout;
 break;

However, in our example we want to do something more interesting so we put up our own modal dialog. The returnCode is set to zero to tell SuperPaint that we have handled the About Box ourselves.

There are several methods to center a DLOG on the screen. The CenterWindow routine creates a temporary port to get the size of the screen since we don’t have direct access to the Quickdraw global screenBits. (Mike Ogawa’s article uses another technique by accessing Quickdraw globals through low memory global CurrentA5.)

In our example, the same About Box code has also been placed under the toolDblClick call to demonstrate responding to this call as well. In a more complex tool, we might want to bring up another dialog for tool settings.

The Goodbye Kiss

We will receive a toolMenuDelete call when the tool is deselected or when SuperPaint has a deactivate event. At this time, we delete our menu and redraw the menu bar. This call is followed by a toolDeselected call. This is an opportunity to do any cleanup that might be required. Our example doesn’t have anything to do here so this call is just handled by the default case.

Building the Code Resource

The process of building the code resource in Think C is quite simple. “Set Project Type” under the Project menu brings up a dialog which allows you to specify that this is a code resource and to set the file type and creator, resource type, number, name and attributes. (See Figure 4.) The “Build Code Resource” command in the Project menu handles compiling all source files and loading libraries as necessary, linking, copying additional resources into the designated output file and setting the file type and creator. Place the file in the SuperPaint Pouch and you are ready to go.

Figure 4. Project Type

Conclusion

Creating your own custom paint tool can give instant satisfaction by allowing you to develop new kinds of graphic tools quickly without having to write an entire application to support them. Since the plug-in tool described in this article uses only some of the many features of the plug-in interface, it is recommended that anyone interested in writing their own plug-in tools obtain the Plug-in Developer Toolkit from Silicon Beach. The Developer Toolkit contains full documentation of the interface along with several different source code examples in five different development environments. It is currently available for $15 from Silicon Beach Software, Inc., P.O. Box 262460, Dept. 20, San Diego, CA 92126.

Listing:  BWit.h
/*
 *  BWit.h
 * Linda McLennan
 COPYRIGHT © 1989 Silicon Beach Software, Inc.
 Permission is hereby granted to the purchaser
 to use this source code for the limited
 purpose of producing and distributing compiled
 object files and applications.  The source
 code is and shall remain the sole property of
 Silicon Beach Software, Inc., and except as
 expressly provided, purchaser obtains no
 right, title or interest in the source code.
 Distribution of the un-compiled or text
 versions of this source code is prohibited.
 */

/* interface version number */
#define verNum   1

/* paint mode constants */
#define paintOpaquepatCopy
#define paintTransparent  patOr
#define paintOnBlack notPatBic
#define paintInvertpatXor

/* toolAbout return codes */
#define noAbout  1
#define textAbout2

/* values for CursorType */
#define defaultCursor0
#define resourceCursor    1
#define lineWidthCursor 2
#define brushCursor3
#define passedCursor 4
 
/* values for type of symmetry support */
#define noSymmetry 0
#define autoSymmetry 1
#define passSymmetryPts 2 

/* values for autoPaint */
#define noAutoPaint0
#define autoPaintPt1
#define autoPaintLine2  

/* values for requestCode field */
#define editBrushes1
#define editSICNs2

/* call selector codes */
#define toolAbout0

#define toolSelected 11
#define toolDblClick 12
#define toolKeyDown13
#define toolMouseDown14
#define toolStillDown15
#define toolMouseUp16
#define toolMenuEvent17
#define toolMenuInsert    18
#define toolMenuDelete    19
#define toolIdle 20
#define toolDeselected    21
#define toolRequestComp 22

typedef struct
{
 short  toolID;  
 short  spare1;
 short  spare2;
 short  spare3;
 short  spare4;
 short  spare5;
 short  spare6;
 short  spare7;

 Point  newPoint;
 Point  oldPoint;
 Rect   updateRect;
 
 BooleanmouseIsDown;
 BooleanshiftIsDown;
 BooleancmdIsDown;
 BooleanoptIsDown;
 BooleandblClick;
 BooleanpaintMultiple;
 BooleanfillPatNone;
 BooleanlinePatNone;
 BooleanchangeCursor;
 BooleantoolActive;
 BooleanpaintCenter;
 BooleanusesScratch;
 BooleanusesConstrain;
 BooleanchangeFillPat;
 
 Cursor newCursor;
 Bits16 curBrush;
 PatterncurFillPat;
 Handle curPatList;
 EventRecord*evntRecPtr;

 short  autoPaint;
 short  cursorType;
 short  symmetry;
 short  spare8;
 short  menuID;
 short  menuItem;

 short  numPts;
 Point  (*mirrorPts)[9][2];

 BitMap scratchBits;
 BitMap undoBits;
 Handle sicnListHdl;
 short  sicnIndex;
 short  requestCode; 
} ToolDataRec, *ToolDataPtr;
Listing:  Fuzzy.h

/* Fuzzy.h */

#define nil 0
#define behind   -1
#define fuzzy    1
#define furry    2
#define crosshatch 3

typedef struct
{
 MenuHandle theMenu;
 short  whichEffect;
 short  brushSize;
}  FuzzyData, *FuzzyDataPtr, **FuzzyDataHandle;
Listing:  Fuzzy.c

/*
 *  Fuzzy Brush
 * Linda McLennan
 *  COPYRIGHT © 1989 Ventana Software
*/

#include“BWit.h”
#include“Fuzzy.h”

pascal void main( selector, tDataPtr, refCon, returnCode )
short   selector;
ToolDataPtr tDataPtr;
Handle  *refCon;
short   *returnCode;
{
 DialogPtrdLogPtr;
 short  itemHit;
 MenuHandle fuzzyMenu;
 FuzzyDataPtr  fzDataPtr;
 EventRecord*eventDataPtr;
 char   keyHit;
 GrafPtrdrawingPort;
 *returnCode = noErr;

 switch( selector )
 {
 case toolAbout: 
 /* show about box */
 CenterWindow(‘DLOG’,tDataPtr->toolID);
 dLogPtr = GetNewDialog( tDataPtr->toolID,
 nil, (WindowPtr)behind );
 ModalDialog( nil, &itemHit );
 DisposDialog( dLogPtr );
 break;
 case toolSelected:/* tool selected from palette */
 FuzzyInit( tDataPtr, refCon );
 if ( *refCon == nil )  *returnCode = memFullErr;
 break;
 case toolMenuInsert:/* put up menu */
 HLock( *refCon );
 fzDataPtr = (FuzzyDataPtr)**refCon;
 fuzzyMenu = fzDataPtr->theMenu;
 if ( fuzzyMenu != nil )
 {
 InsertMenu( fuzzyMenu, 0 );
 CheckItem( fuzzyMenu,
 fzDataPtr->whichEffect, true );
 }
 HUnlock( *refCon );

 DrawMenuBar();
 break;
 case toolDblClick:/* show about box */
 CenterWindow(‘DLOG’,tDataPtr->toolID);
 dLogPtr = GetNewDialog( tDataPtr->toolID,
 nil, (WindowPtr)behind );
 ModalDialog( nil, &itemHit );
 DisposDialog( dLogPtr );
 break;
 case toolKeyDown:
 /* non-modifier key pressed */
 eventDataPtr = tDataPtr->evntRecPtr;
 keyHit = (char)(charCodeMask &
 (eventDataPtr->message) );
 if ( (keyHit >= ‘1’) && (keyHit <= ‘3’) )
 {
 HLock( *refCon );
 fzDataPtr = (FuzzyDataPtr)**refCon;
 fzDataPtr->brushSize =
 (keyHit - 0x0030) * 16;
 HUnlock( *refCon );
 } 
 break;
 case toolMouseDown:/* mouse down, set update area empty */
        SetRect(&tDataPtr->updateRect,0,0,0,0);
 if (! tDataPtr->linePatNone)
 tDataPtr->toolActive = true;
 break;
 case toolStillDown:/* mouse still down, draw something */
 DrawEffect( tDataPtr, *refCon );
 break;
 case toolMouseUp: 
 /* mouse up */
 SetRect(&tDataPtr->updateRect,0,0,0,0);
 tDataPtr->toolActive = false;
 break;
 case toolMenuEvent: /* select new effect */
 HLock( *refCon );
 fzDataPtr = (FuzzyDataPtr)**refCon;
 if ( tDataPtr->menuItem  !=
 fzDataPtr->whichEffect )
 {
 CheckItem( fzDataPtr->theMenu,
 fzDataPtr->whichEffect, false );
 CheckItem( fzDataPtr->theMenu,
 tDataPtr->menuItem, true );
 fzDataPtr->whichEffect =
 tDataPtr->menuItem;
 }
 HUnlock( *refCon );
 break;

 case toolMenuDelete:/*tool deselected, delete menu */
 DeleteMenu( tDataPtr->toolID );
 DrawMenuBar();  
 break;

 default: /* just clear the update area */
 SetRect(&tDataPtr->updateRect,0,0,0,0);
 break;
 
 } /* end switch */
 }
Listing:  FuzzyInit.c

/*
 *  FuzzyInit.c
 * Linda McLennan
 *  COPYRIGHT © 1989 Ventana Software
*/

#include“BWit.h”
#include“Fuzzy.h”

FuzzyInit( tDataPtr, refCon )
 ToolDataPtrtDataPtr;
 Handle *refCon;
{
 MenuHandle fuzzyMenu;
 FuzzyDataPtr  fzDataPtr;

 /* set options */
 tDataPtr->cursorType = resourceCursor;
 tDataPtr->symmetry = autoSymmetry;
 tDataPtr->autoPaint = noAutoPaint;
 tDataPtr->usesScratch = false;
 tDataPtr->usesConstrain = true;
 tDataPtr->changeFillPat = false;

 /* check if first time called */
 if ( *refCon == nil )
 {
 /* allocate space for globals */
      *refCon = NewHandle( sizeof ( FuzzyData ) );

 /* get the menu, detach it */
 /* and save the handle */
 if ( *refCon != nil )
 {
 fuzzyMenu = GetMenu(tDataPtr->toolID);
 if ( fuzzyMenu != nil )
 {
 HNoPurge((Handle)fuzzyMenu); 
 DetachResource((Handle)fuzzyMenu);
 } 
 
 HLock( *refCon );
 fzDataPtr = (FuzzyDataPtr)**refCon;
 fzDataPtr->theMenu = fuzzyMenu;
 fzDataPtr->whichEffect = fuzzy;
 fzDataPtr->brushSize = 16;
 HUnlock( *refCon ); 
 }
 }
 }
Listing:  DrawEffect.c

/*
 *  DrawEffect.c
 * Linda McLennan
 *  COPYRIGHT © 1989 Ventana Software
*/
#include“BWit.h”
#include“Fuzzy.h”

DrawEffect( tDataPtr, fzDataHandle )
 ToolDataPtrtDataPtr;
 FuzzyDataHandle fzDataHandle;
{
 GrafPtrdPort;
 short  n, theEffect;
 short  halfSize, numPts;
 Point  offset;
 FuzzyDataPtr  fzDataPtr;

 HLock( fzDataHandle );
 fzDataPtr = *fzDataHandle;
 theEffect = fzDataPtr->whichEffect;
 if ( theEffect == crosshatch )
 numPts = 1;
 else
 numPts = 8;
 
 halfSize = (fzDataPtr->brushSize)/2;

 for ( n = 1; n <= numPts; n++ )
 {
 /* get random offset from current */
 /* mouse within size of brush */
 offset.h = Random() % halfSize;
 offset.v = Random() % halfSize;
 switch( theEffect )
 {
 case fuzzy:
 MoveTo( tDataPtr->newPoint.h,
 tDataPtr->newPoint.v );
 Line( offset.h, offset.v);
 break;
 case furry:
 MoveTo( tDataPtr->newPoint.h +    offset.h, tDataPtr->newPoint.v + offset.v 
);
 Line( offset.h, offset.v);
 break;
 case crosshatch:
 MoveTo( tDataPtr->newPoint.h +
 offset.h, tDataPtr->newPoint.v + offset.v );
 Line( 7, 0);
 MoveTo( tDataPtr->newPoint.h +
 offset.h + 1, tDataPtr->newPoint.v +
 offset.v - 2);
 Line( 6, 6 );
 break;
 }
 }

 HLock( fzDataHandle );

 /* compute update area and add pen size */
 Pt2Rect(tDataPtr->oldPoint, tDataPtr->newPoint,
 &tDataPtr->updateRect );
 InsetRect( &tDataPtr->updateRect,
 -halfSize, -halfSize );

 if ( theEffect == furry )
 InsetRect( &tDataPtr->updateRect,
 -halfSize, -halfSize );
 
 GetPort( &dPort );
 tDataPtr->updateRect.right += dPort->pnSize.h;
 tDataPtr->updateRect.bottom += dPort->pnSize.v;
 }
Listing:  CenterWindow.c

/*
 CenterWindow
 COPYRIGHT © 1989 Silicon Beach Software, Inc.
 Permission is hereby granted to the purchaser
 to use this source code for the limited
 purpose of producing and distributing compiled
 object files and applications.  The source
 code is and shall remain the sole property of
 Silicon Beach Software, Inc., and except as
 expressly provided, purchaser obtains no
 right, title or interest in the source code.
 Distribution of the un-compiled or text
 versions of this source code is prohibited.
*/
#define MBarHeight ( *(short  *)0xBAA )
#define nil 0

CenterWindow( Type, ID )
ResType Type;
short   ID;
{

 DialogTHndlwindowHdl;
 Rect   boundsRect;
 short  screenHeight;
 short  screenWidth;
 short  boxHeight;
 short  boxWidth;
 short  topMargin;
 short  leftMargin;
 GrafPtrtempPort, savePort;
 
 windowHdl  = (DialogTHndl)GetResource(Type,ID);
 
 if( windowHdl != nil ) {
 /* open a temporary port to */
 /* get the size of the screen */
 GetPort( &savePort );
 tempPort = (GrafPtr)NewPtr( sizeof( GrafPort ) );
 OpenPort( tempPort );
 screenWidth = tempPort->portRect.right - 
 tempPort->portRect.left;
 screenHeight = tempPort->portRect.bottom -
 tempPort->portRect.top - MBarHeight;
 ClosePort( tempPort );
 DisposPtr( (Ptr)tempPort );
 SetPort( savePort );

 /* get size of dialog window */
 boundsRect = (*windowHdl)->boundsRect;
 boxHeight = boundsRect.bottom -   boundsRect.top;
 boxWidth = boundsRect.right  - boundsRect.left;

 /* compute position for the dialog */
 topMargin = (screenHeight-boxHeight)/4;
 leftMargin = (screenWidth-boxWidth)/2;
 
 boundsRect.top = MBarHeight + topMargin;
 boundsRect.left = leftMargin;
 boundsRect.bottom = boundsRect.top  + boxHeight;
 boundsRect.right = boundsRect.left + boxWidth;
 
 (*windowHdl)->boundsRect = boundsRect;
 }/* if( got the resource ) */
 }/*CenterWindow*/

 
AAPL
$100.96
Apple Inc.
-0.83
MSFT
$47.52
Microsoft Corpora
+0.84
GOOG
$596.08
Google Inc.
+6.81

MacTech Search:
Community Search:

Software Updates via MacUpdate

Airfoil 4.8.9 - Send audio from any app...
Airfoil allows you to send any audio to AirPort Express units, Apple TVs, and even other Macs and PCs, all in sync! It's your audio - everywhere. With Airfoil you can take audio from any... Read more
WhatRoute 1.13.0 - Geographically trace...
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... Read more
Chromium 37.0.2062.122 - Fast and stable...
Chromium is an open-source browser project that aims to build a safer, faster, and more stable way for all Internet users to experience the web. FreeSMUG-Free OpenSource Mac User Group build is... Read more
Attachment Tamer 3.1.14b9 - Take control...
Attachment Tamer gives you control over attachment handling in Apple Mail. It fixes the most annoying Apple Mail flaws, ensures compatibility with other email software, and allows you to set up how... Read more
Duplicate Annihilator 5.0 - Find and del...
Duplicate Annihilator takes on the time-consuming task of comparing the images in your iPhoto library using effective algorithms to make sure that no duplicate escapes. Duplicate Annihilator detects... Read more
jAlbum Pro 12.2 - Organize your digital...
jAlbum Pro has all the features you love in jAlbum, but comes with a commercial license. With jAlbum, you can create gorgeous custom photo galleries for the Web without writing a line of code!... Read more
jAlbum 12.2 - Create custom photo galler...
With jAlbum, you can create gorgeous custom photo galleries for the Web without writing a line of code! Beginner-friendly, with pro results Simply drag and drop photos into groups, choose a design... Read more
Quicken 2015 2.0.4 - Complete personal f...
Quicken 2015 helps you manage all your personal finances in one place, so you can see where you're spending and where you can save. Quicken automatically categorizes your financial transactions,... Read more
iMazing 1.0 - Complete iOS device manage...
iMazing (formerly DiskAid) is the ultimate iOS device manager with capabilities far beyond what iTunes offers. With iMazing and your iOS device (iPhone, iPad, or iPod), you can: Copy music to and... Read more
Xcode 6.0.1 - Integrated development env...
Apple Xcode is Apple Computer's integrated development environment (IDE) for OS X. The full Xcode package is free to ADC members and includes all the tools you need to create, debug, and optimize... Read more

Latest Forum Discussions

See All

View Source – HTML, JavaScript and CSS...
View Source – HTML, JavaScript and CSS 1.0 Device: iOS Universal Category: Utilities Price: $.99, Version: 1.0 (iTunes) Description: View Source is an app plus an iOS 8 Safari extension that makes it easy to do one key web developer... | Read more »
Avenged Sevenfold’s Hail To The King: De...
Avenged Sevenfold’s Hail To The King: Deathbat is Coming to iOS on October 16th Posted by Jessica Fisher on September 19th, 2014 [ permalink ] Just in time for Halloween, on October 16 Avenged Sevenfold will be launching | Read more »
Talisman Has Gone Universal – Can Now be...
Talisman Has Gone Universal – Can Now be Played on the iPhone Posted by Jessica Fisher on September 19th, 2014 [ permalink ] | Read more »
Tap Army Review
Tap Army Review By Jennifer Allen on September 19th, 2014 Our Rating: :: SHOOT EM ALLUniversal App - Designed for iPhone and iPad Mindless but fun, Tap Army is a lane-based shooter that should help you relieve some stress.   | Read more »
Monsters! Volcanoes! Loot! Epic Island f...
Monsters! Volcanoes! Loot! | Read more »
Plunder Pirates: Tips, Tricks, Strategie...
Ahoy There, Seadogs: Interested in knowing our thoughts on all this plundering and pirating? Check out our Plunder Pirates Review! Have you just downloaded the rather enjoyable pirate-em-up Plunder Pirates and are in need of some assistance? Never... | Read more »
Goat Simulator Review
Goat Simulator Review By Lee Hamlet on September 19th, 2014 Our Rating: :: THE GRUFFEST OF BILLY GOATSUniversal App - Designed for iPhone and iPad Unleash chaos as a grumpy goat in this humorous but short-lived casual game.   | Read more »
A New and Improved Wunderlist is Here fo...
A New and Improved Wunderlist is Here for iOS 8 Posted by Jessica Fisher on September 19th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Evernote Update for iOS 8 Adds Web Clipp...
Evernote Update for iOS 8 Adds Web Clipping, Quick Notes, and More Posted by Ellis Spice on September 19th, 2014 [ permalink ] | Read more »
Apple Names Ultimate Productivity Bundl...
Apple Names Ultimate Productivity Bundle by Readdle as the Essential Bundle on the App Store Posted by Jessica Fisher on September 19th, 2014 [ permalink | Read more »

Price Scanner via MacPrices.net

Updated Price Trackers
We’ve updated our Mac Price Trackers with the latest information on prices, bundles, and availability on systems from Apple’s authorized internet/catalog resellers: - 15″ MacBook Pros - 13″ MacBook... Read more
Mac Pros available for up to $260 off MSRP
Adorama has Mac Pros on sale for up to $260 off MSRP. Shipping is free, and Adorama charges sales tax in NY & NJ only: - 4-core Mac Pro: $2839.99, $160 off MSRP - 6-core Mac Pro: $3739.99, $260... Read more
13-inch 2.6GHz/256GB Retina MacBook Pros avai...
B&H Photo has the 13″ 2.6GHz/256GB Retina MacBook Pro on sale for $1379 including free shipping plus NY sales tax only. Their price is $120 off MSRP. Read more
Previous-generation 15-inch 2.0GHz Retina Mac...
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
21″ 2.7GHz iMac available for $1179, save $12...
Adorama has 21″ 2.7GHz Hawell iMacs on sale for $1179.99 including free shipping. Their price is $120 off MSRP. NY and NJ sales tax only. Read more
iOS 8 Adoption Rate Slower than iOS 7, 6, Hit...
Apple began pushing out iOS 8 updates to eligible devices around 1pm ET on September 17, 2014. However, unlike with iOS 7, which boasted a wide variety of differences from its predecessor iOS 6, in... Read more
LIkely Final Definitive OS X 10.9.5 Mavericks...
Apple has released what will almost certainly be the last incremental version number update of OS X 10.9 Mavericks (save for futire security updates) before OS X 10.10 Yosemite is released next month... Read more
Fingerprints, Apple Pay and Identity Theft Wa...
On Sep 9th, CEO Tim Cook unveiled Apple Pay, along with the new iPhone 6 and iWatch. Apple Pay is a newly developed technology that utilizes a near field communication (NFC) to enable customer... Read more
Amazon Introduces Two All-New Kindles
Amazon on Thursday introduced the 7th generation of its Kindle dedicated e-reader device: Kindle Voyage, its top-of-the-line e-reader, and the new $79 Kindle, with a 20% faster processor, twice the... Read more
Save up to $300 on the price of a new Mac wit...
Purchase a new Mac or iPad at The Apple Store for Education and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free,... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
Project Manager, *Apple* Financial Services...
**Job Summary** Apple Financial Services (AFS) offers consumers, businesses and educational institutions ways to finance Apple purchases. We work with national and Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.