unit iconAnimation; { iconAnimation } { Copyright © 1993 by Michael J. Gibbs, all rights reserved. } { } { This unit provides a class that can be used by applications that want to } { do simple animations. } { } { By default, the animation is stationary and accomplished by overlaying each } { frame on top of the previous. The interval between frames can be set (in } { 60ths of a second) and the application must call animateIcon as often as } { possible. A delay can be specified between successive runs of the sequence,} { i.e., prior to starting at the first frame again. } { } { The animation can be moved to a new location or moved by a specific amount } { from its current location. In either case, it is possible to have the } { icon object's location be one value, and the actual screen location be } { another. getPreviousRect will always return the actual screen position, } { while getRect will return the position of the next frame. eraseBeforeDraw } { should be called with TRUE if the animation is to move from frame to frame. } { } { Methods defined for cAnimatedIcon: } { iAnimatedIcon initializes a new animated icon object and is } { passed the grafport the icon is to reside in, the } { resource ID of the first 'cicn' resource, the number } { of icons in the animation sequence, and the initial } { rectangle the icon is to be drawn in. } { The default minimum interval between animation frames } { is set to 5 ticks. } { free releases all the memory used by the object } { draw force an immediate redraw (can be called in response } { to an update event, for example) -- does not need to } { be called for normal animation. } { animateIcon called repeatedly, performs the animation sequence. } { setAnimationInterval sets the minimum interval between frames of the } { animation. This allows the application to call } { animateIcon without concern for timing. The } { interval is set in ticks. } { getAnimationInterval returns the interval between frames. } { playForwardOnly sets whether the animation runs forward or backward } { setOnceOnly sets whether the animation plays continuously or } { plays once only } { setFrameIncrement sets the increment value between frames: +1 is the } { default, +2 skips every other frame, etc., while -1 } { plays backwards, etc. } { getFrameIncrement returns the current frame increment } { setRect changes the rectangle within which the animation } { occurs. } { getRect returns the animation rectangle (the next frame to } { be drawn) } { getPreviousRect returns the screen animation rectangle (the } { previously drawn frame). } { shiftIcon moves the rectangle for the next animation frame. } { eraseIcon erases the animation rectangle. } { eraseBeforeDraw sets whether or not the previous frame should be } { erased before the next one is drawn. The previous } { frame is NOT erased until the next animation interval.} { setCurrentFrame sets the number of the frame to be displayed next. } { getCurrentFrame returns the number of the frame to be displayed next. } { setCycleDelay sets the number of 60ths of a second to delay before } { beginning the next animation sequence (i.e., before } { displaying the first frame). } { } { 9302041520 M. Gibbs: initial release } interface uses ObjIntf, QuickDraw, Resources, icons; const maxFrame = 63; type frameArray = array[0..maxFrame] of cIconHandle; cAnimatedIcon = object(tObject) itsBaseID: integer; itsNumFrames: integer; itsCurrentFrame: integer; itsFrameIncrement: integer; itsLastTime: longint; itsMinInterval: integer; itsRect, itsPreviousRect: rect; itsGrafPort: grafPtr; itsCycleDelay: integer; itsEraseBeforeDraw: boolean; itsFrames: frameArray; itsOnceOnly: boolean; itsForwardOnly: boolean; procedure iAnimatedIcon (thePort: grafPtr; baseResID, numberOfFrames: integer; iconRect: rect); procedure free; override; procedure draw; procedure animateIcon; procedure setAnimationInterval (minTime: integer); function getAnimationInterval: integer; procedure playForwardOnly (forwardOnly: boolean); procedure setOnceOnly (onceOnly: boolean); procedure setFrameIncrement (theIncrement: integer); function getFrameIncrement: integer; procedure setRect (r: rect); function getRect: rect; function getPreviousRect: rect; procedure shiftIcon (deltaX, deltaY: integer); procedure eraseIcon; procedure eraseBeforeDraw (should: boolean); procedure setCurrentFrame (newFrame: integer); function getCurrentFrame: integer; procedure setCycleDelay (newDelay: integer); end; implementation const defaultInterval = 5; procedure cAnimatedIcon.iAnimatedIcon (thePort: grafPtr; baseResID, numberOfFrames: integer; iconRect: rect); var x: integer; begin itsBaseID := baseResID; itsCurrentFrame := 0; itsNumFrames := numberOfFrames; itsFrameIncrement := 1; itsLastTime := 0; itsMinInterval := defaultInterval; itsRect := iconRect; itsPreviousRect := iconRect; itsGrafPort := thePort; itsEraseBeforeDraw := false; itsCycleDelay := 0; itsOnceOnly := false; itsForwardOnly := true; for x := 0 to itsNumFrames do itsFrames[x] := getCIcon(itsBaseID + x); end; { cAnimatedIcon.iAnimatedIcon } procedure cAnimatedIcon.free; var x: integer; begin for x := 1 to itsNumFrames do disposeCIcon(itsFrames[x]); inherited free; end; { cAnimatedIcon.free } procedure cAnimatedIcon.draw; var savePort: grafPtr; begin getPort(savePort); setPort(itsGrafPort); plotCIcon(itsRect, itsFrames[itsCurrentFrame]); setPort(savePort); end; { cAnimatedIcon.draw } procedure cAnimatedIcon.animateIcon; var currentTime: longint; savePort: grafPtr; begin currentTime := tickCount; if currentTime - itsLastTime > itsMinInterval then begin getPort(savePort); setPort(itsGrafPort); itsLastTime := currentTime; if itsEraseBeforeDraw then begin eraseRect(itsPreviousRect); itsPreviousRect := itsRect; end; plotCIcon(itsRect, itsFrames[itsCurrentFrame]); itsCurrentFrame := itsCurrentFrame + itsFrameIncrement; if (itsCurrentFrame >= itsNumFrames) or (itsCurrentFrame < 0) then begin if itsForwardOnly then begin if itsOnceOnly then begin if itsCurrentFrame < 0 then itsCurrentFrame := 0 else itsCurrentFrame := itsNumFrames - 1; itsFrameIncrement := 0; end else itsCurrentFrame := 0; end else begin itsFrameIncrement := -1 * itsFrameIncrement; itsCurrentFrame := itsCurrentFrame + itsFrameIncrement; end; itsLastTime := itsLastTime + itsCycleDelay; end; setPort(savePort); end; end; { cAnimatedIcon.animateIcon } procedure cAnimatedIcon.setAnimationInterval (minTime: integer); begin itsMinInterval := minTime; end; { cAnimatedIcon.setAnimationInterval } function cAnimatedIcon.getAnimationInterval: integer; begin getAnimationInterval := itsMinInterval; end; { cAnimatedIcon.setAnimationInterval } procedure cAnimatedIcon.playForwardOnly (forwardOnly: boolean); begin itsForwardOnly := forwardOnly; end; { cAnimatedIcon.playForwardOnly } procedure cAnimatedIcon.setOnceOnly (onceOnly: boolean); begin itsOnceOnly := onceOnly; end; { cAnimatedIcon.setOnceOnly } procedure cAnimatedIcon.setFrameIncrement (theIncrement: integer); begin itsFrameIncrement := theIncrement; end; { cAnimatedIcon.setFrameIncrement } function cAnimatedIcon.getFrameIncrement: integer; begin getFrameIncrement := itsFrameIncrement; end; { cAnimatedIcon.getFrameIncrement } procedure cAnimatedIcon.setRect (r: rect); begin itsRect := r; end; { cAnimatedIcon.setRect } function cAnimatedIcon.getRect: rect; begin getRect := itsRect; end; { cAnimatedIcon.getRect } function cAnimatedIcon.getPreviousRect: rect; begin getPreviousRect := itsPreviousRect; end; { cAnimatedIcon.getPreviousRect } procedure cAnimatedIcon.shiftIcon (deltaX, deltaY: integer); begin offsetRect(itsRect, deltaX, deltaY); end; { cAnimatedIcon.shiftIcon } procedure cAnimatedIcon.eraseIcon; var savePort: grafPtr; begin getPort(savePort); setPort(itsGrafPort); eraseRect(itsRect); setPort(savePort); end; { cAnimatedIcon.eraseIcon } procedure cAnimatedIcon.eraseBeforeDraw (should: boolean); begin itsEraseBeforeDraw := should; end; { cAnimatedIcon.eraseBeforeDraw } procedure cAnimatedIcon.setCurrentFrame (newFrame: integer); begin newFrame := newFrame - 1; if newFrame < 0 then itsCurrentFrame := 0 else if newFrame >= itsNumFrames then itsCurrentFrame := itsNumFrames - 1 else itsCurrentFrame := newFrame; end; { cAnimatedIcon.setCurrentFrame } function cAnimatedIcon.getCurrentFrame: integer; begin getCurrentFrame := itsCurrentFrame + 1; end; { cAnimatedIcon.getCurrentFrame } procedure cAnimatedIcon.setCycleDelay (newDelay: integer); begin itsCycleDelay := newDelay; end; { cAnimatedIcon.setCycleDelay } end. { iconAnimation }