home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-04-23 | 12.8 KB | 521 lines | [TEXT/PJMM] |
- { Watch.p --> routines devoted to drawing the watch }
- unit Watch;
- interface
- uses
- QDOffscreen, Globals;
- type
- TStringRec = record
- lastValue: integer;
- startPnt: Point;
- blankRect: Rect;
- theString: StringHandle;
- end;
- const
-
- YEAR_NUM = 1;
- MONTH_NUM = 2;
- DAY_NUM = 3;
- HOUR_NUM = 4;
- MINUTE_NUM = 5;
- SECOND_NUM = 6;
- NUM_FIELDS = SECOND_NUM;
- var
- gRectArray: array[1..NUM_FIELDS] of TStringRec;
-
- gDayRectPict: PicHandle;
-
- gFramePict: PicHandle;
- gZoomed: Boolean;
- gWatchPict: PicHandle;
- gLongHandLenSquared, gShortHandLenSquared: Extended;
- gLongHandLen, gShortHandLen: integer;
- gCenter, gBigHandEnd, gLittleHandEnd: Point;
- gRadDegRatio: Extended;
- gScratchWorld, gWatchWorld: GWorldPtr;
- gEndTime: LONGINT;
- gLastTime: LONGINT;
- { function prototypes }
- { calculation routines }
- procedure CalcCenter (usesOffScreen: Boolean);
- procedure CalcHands (time: LONGINT);
-
- procedure FillAString (value: integer;
- aStringH: StringHandle);
-
- procedure GetNewPoint (minute, length: integer;
- lenSquared: Extended;
- var endPoint: Point);
- { gWorld operations }
- function CheckGWorlds: Boolean;
- function FindDepth: Boolean;
- function InitMyGWorlds: Boolean;
- { draw routines }
- procedure DrawAString (aRecord: TStringRec);
- procedure DrawFace (intoOffscreen: Boolean);
- procedure DrawHand (pSize: integer;
- deltaPoint: Point;
- intoOffscreen: Boolean);
- function DrawIfNeeded (value: integer;
- var aRecord: TStringRec): Boolean;
- procedure DrawMyStrings;
- procedure DrawTheWatch;
- procedure KillMyGWorlds;
- procedure RefreshWatch;
-
- implementation
- uses
- Sane, MySpeech;
- { calculation routines }
- const
-
- BIG_HAND_SIZE = 2;
- LITTLE_HAND_SIZE = 3;
-
- { *********************** }
- { calc center of picture }
- procedure CalcCenter (usesOffScreen: Boolean);
- var
- pictRect: Rect;
- begin
- pictRect := gWatchPict^^.picFrame;
- if usesOffScreen then
- OffSetRect(pictRect, -pictRect.left, -pictRect.top);
-
- gCenter.h := 2 + (pictRect.right - pictRect.left) div 2;
- gCenter.v := (pictRect.bottom - pictRect.top) div 2;
- end; { CalcCenter }
-
- procedure CalcHands (time: LONGINT);
- var
- hour, minute: LONGINT;
- dateRec: DateTimeRec;
- begin
- Secs2Date(time, dateRec);
- minute := dateRec.minute;
- minute := minute * 6;
- GetNewPoint(minute, gLongHandLen, gLongHandLenSquared, gBigHandEnd);
- if dateRec.hour >= 12 then
- begin
- hour := dateRec.hour - 12;
- end
- else
- begin
- hour := dateRec.hour;
- end;
- hour := hour * 30;
- hour := hour + minute div 12;
- GetNewPoint(hour, gShortHandLen, gShortHandLenSquared, gLittleHandEnd);
- end; (* CalcHands *)
-
- { fill a string with the ascii equivalent of an integer }
- procedure FillAString (value: integer;
- aStringH: StringHandle);
- var
- tempLong: LONGINT;
- begin
- HLock(Handle(aStringH));
- tempLong := value;
- NumToString(tempLong, aStringH^^);
- HUnlock(Handle(aStringH));
- end;
-
- { figure out where a hand is supposed to end }
- procedure GetNewPoint (minute, length: integer;
- lenSquared: Extended;
- var endPoint: Point);
- var
- sinThetaSquared, temp: Extended;
- angle: Extended;
- begin
- if minute = 0 then
- begin
- endPoint.v := -length;
- endPoint.h := 0;
- end
- else if minute = 180 then
- begin
- endPoint.v := length;
- endPoint.h := 0;
- end
- else
- begin
- angle := gRadDegRatio * minute;
- sinThetaSquared := Sin(angle);
- sinThetaSquared := sinThetaSquared * sinThetaSquared;
- temp := 1.0 - sinThetaSquared;
- temp := temp * lenSquared;
- temp := sqrt(temp);
- endPoint.v := Num2Longint(temp);
- temp := sinThetaSquared * lenSquared;
- temp := sqrt(temp);
- endPoint.h := Num2Longint(temp);
- if minute <= 90 then
- begin
- endPoint.v := -endPoint.v;
- end
- else if minute <= 180 then
- begin
-
- end
- else if minute <= 270 then
- begin
- endPoint.h := -endPoint.h;
- end
- else
- begin
- endPoint.v := -endPoint.v;
- endPoint.h := -endPoint.h;
- end;
- end;
- end;
-
- { Make the GWorlds we use for offscreen drawing }
- function InitMyGWorlds: Boolean;
- var
- myErr: QDErr;
- worldRect, globRect: Rect;
- wFlags: GWorldFlags;
- gdh: GDHandle;
- theDevPixMap: PixMapHandle;
- tempHandle: Handle;
- begin
- InitMyGWorlds := FALSE;
- worldRect := gWatchPict^^.picFrame;
- OffsetRect(worldRect, -worldRect.left, -worldRect.top);
- LONGINT(wFlags) := 0;
- gWatchWorld := nil;
- gScratchWorld := nil;
- tempHandle := NewHandle(10000);
- if (MaxBlock > 10000) then
- begin
- myErr := NewGWorld(gWatchWorld, 0, worldRect, nil, nil, wFlags);
-
- if (myErr = 0) and (gWatchWorld <> nil) then
- begin
- RefreshWatch;
- if (MaxBlock > 10000) then
- myErr := NewGWorld(gScratchWorld, 0, worldRect, nil, nil, wFlags);
- end;
- end;
- if tempHandle <> nil then
- DisposHandle(tempHandle);
- end;
-
- procedure KillMyGWorlds;
- begin
- if gWatchWorld <> nil then
- DisposeGWorld(gWatchWorld);
- if gScratchWorld <> nil then
- DisposeGWorld(gScratchWorld);
- gWatchWorld := nil;
- gScratchWorld := nil;
- end;
- { make sure the gworlds are valid for current depth, user might have switched }
- function CheckGWorlds: Boolean;
- begin
- CheckGWorlds := FALSE;
- if FindDepth then
- begin
- CheckGWorlds := TRUE;
- KillMyGWorlds;
- if InitMyGWorlds = FALSE then
- begin
- end;
- end;
- end;
- { find the minimum depth of the current watch face }
- function FindDepth: Boolean;
- var
- globRect: Rect;
- offSet: Point;
- gdh: GDHandle;
- theDevPixMap: PixMapHandle;
- begin
- FindDepth := FALSE;
- if gColorAvailable then
- begin
- offset.h := 0;
- offset.v := 0;
- LocalToGlobal(offset);
- globRect := gWatchPict^^.picFrame;
- OffsetRect(globRect, offset.h, offset.v);
- gdh := GetMaxDevice(globRect);
- theDevPixMap := gdh^^.gdPMap;
- if gDepth <> theDevPixMap^^.pixelSize then
- begin
- FindDepth := TRUE;
- gDepth := theDevPixMap^^.pixelSize;
- end;
- end
- else
- begin
- gDepth := 1;
- end;
- end;
- { draw routines }
- { ********************************* }
- procedure DrawAString (aRecord: TStringRec);
- begin
- HLock(Handle(aRecord.theString));
- with aRecord do
- begin
- MoveTo(startPnt.h, startPnt.v);
- EraseRect(blankRect);
- DrawString(theString^^);
- end;
- HUnlock(Handle(aRecord.theString));
- end;
-
- procedure DrawMyStrings;
- var
- i: integer;
- begin
- for i := YEAR_NUM to NUM_FIELDS do
- begin
- DrawAString(gRectArray[i]);
- end;
- end;
-
- function DrawIfNeeded (value: integer;
- var aRecord: TStringRec): Boolean;
- begin
-
- if value <> aRecord.lastValue then
- begin
- aRecord.lastValue := value;
- FillAString(value, aRecord.theString);
- DrawAString(aRecord);
- DrawIfNeeded := TRUE;
- end
- else
- begin
- DrawIfNeeded := FALSE;
- end;
- end;
-
- procedure DrawHand (pSize: integer;
- deltaPoint: Point;
- intoOffscreen: Boolean);
- var
- oldColor, greyColor: RGBColor;
- circleRect: Rect;
- circleWidth: integer;
- hOffset: integer;
- vOffset: integer;
- begin
- if intoOffscreen then
- begin
- hOffset := 0;
- vOffset := 0;
- end
- else
- begin
- hOffset := gWatchPict^^.picFrame.left;
- vOffset := gWatchPict^^.picFrame.top;
- end;
- circleWidth := pSize + 3;
- circleRect.right := gCenter.h + deltaPoint.h + circleWidth + hOffset;
- circleRect.left := gCenter.h + deltaPoint.h - circleWidth + hOffset;
- circleRect.top := gCenter.v + deltaPoint.v - circleWidth + vOffset;
- circleRect.bottom := gCenter.v + deltaPoint.v + circleWidth + vOffset;
-
- MoveTo(gCenter.h + hOffset, gCenter.v + vOffset);
-
- PenSize(1, 1);
- if pSize = LITTLE_HAND_SIZE then
- begin
-
- Line(deltaPoint.h, deltaPoint.v);
- EraseOval(circleRect);
- FrameOval(circleRect);
- end
- else
- begin
- Line(deltaPoint.h, deltaPoint.v);
- PaintOval(circleRect);
- end;
- end;
-
- procedure DrawPieArc (wf: Rect;
- time: LONGINT);
- var
- arcAngle: LONGINT;
- oldColor, newColor: RGBColor;
- frame: Rect;
- inset: integer;
- center: Point;
- begin
- arcAngle := (gEndTime - time) div 350640; { # seconds in 4 years / 360 degrees }
- arcAngle := 360 - arcAngle;
- SetRect(frame, wf.left, wf.top, wf.right, wf.bottom);
- InsetRect(frame, 4, 4); { the outer circle is 2 pixels wide }
- OffsetRect(frame, 2, -2);
-
- if gDepth >= 8 then
- begin
- GetForeColor(oldColor);
- newColor.red := 40000;
- newColor.green := 40000;
- newColor.blue := 40000;
- RGBForeColor(newColor);
- PaintArc(frame, 0, arcAngle);
- RGBForeColor(oldColor);
- end
- else
- begin
- FillArc(frame, 0, arcAngle, ltGray);
- end;
-
- center.h := frame.left + (frame.right - frame.left) div 2;
- center.v := 1 + frame.top + (frame.bottom - frame.top) div 2;
-
- frame.top := center.v - 7;
- frame.bottom := frame.top + 14;
- frame.left := center.h - 7;
- frame.right := frame.left + 14;
-
- PaintOval(frame); { make center hand pivot circle }
- PenPat(white);
- FrameOval(frame);
- PenPat(black);
- end;
- { Draw the face, hopefully into offscreen gworld once an hour }
- { otherwise into the window every minute }
- procedure DrawFace (intoOffscreen: Boolean);
- var
- dayFrame, watchFrame, blankRect: Rect;
- aString: Str255;
- time: LONGINT;
- dateRec: DateTimeRec;
- fInfo: FontInfo;
- distHoriz, distVert: integer;
- begin
-
- watchFrame := gWatchPict^^.picFrame;
- dayFrame := gDayRectPict^^.picFrame;
- if intoOffscreen then
- begin
- SetRect(blankRect, 0, 0, 32767, 32767);
- EraseRect(blankRect);
- distHoriz := -watchFrame.left;
- distVert := -watchFrame.top;
- OffsetRect(watchFrame, distHoriz, distVert);
- OffsetRect(dayFrame, distHoriz, distVert);
- end;
- GetDateTime(time);
- HLock(Handle(gWatchPict));
- DrawPicture(gWatchPict, watchFrame);
- HUnlock(Handle(gWatchPict));
-
- DrawPieArc(watchFrame, time);
-
-
- HLock(Handle(gDayRectPict));
- DrawPicture(gDayRectPict, dayFrame);
- HUnlock(Handle(gDayRectPict));
-
- InsetRect(dayFrame, 2, 2);
- ClipRect(dayFrame);
-
- Secs2Date(time, dateRec);
- NumToString(dateRec.day, aString);
- GetFontInfo(fInfo);
- MoveTo(dayFrame.left, dayFrame.top + fInfo.ascent - 1);
- DrawString(aString);
- SetRect(dayFrame, -32768, -32768, 32767, 32767);
- ClipRect(dayFrame);
- end;
-
- { we have 3 separate ways of drawing }
- { 1) we have 2 gworlds one with the background, arc, date }
- { and another which we blit the background into and then }
- { draw the hands }
- { 2) we have 1 gworld into which draw everything and then blit }
- { it to the screen }
- { 3) we draw everything into the screen (flickers galore) }
- procedure DrawTheWatch;
- var
- watchPixMap, scratch: PixMapHandle;
- watchBitH, scratchBitH: BitMapHandle;
- port: CGrafPtr;
- gdh: GDHandle;
- worldRect: Rect;
- drawn: Boolean;
- begin
- drawn := FALSE;
- if gWatchWorld <> nil then
- begin
- worldRect := gWatchPict^^.picFrame;
- OffsetRect(worldRect, -worldRect.left, -worldRect.top);
- watchPixMap := GetGWorldPixMap(gWatchWorld);
- if (LockPixels(watchPixMap)) then
- begin
- watchBitH := BitMapHandle(watchPixMap);
- CalcCenter(TRUE);
- if gScratchWorld <> nil then
- begin
- scratch := GetGWorldPixMap(gScratchWorld);
- if (LockPixels(scratch)) then
- begin
- scratchBitH := BitMapHandle(scratch);
- CopyBits(watchBitH^^, scratchBitH^^, worldRect, worldRect, srcCopy, nil);
- UnlockPixels(watchPixMap);
- GetGWorld(port, gdh);
- SetGWorld(gScratchWorld, nil);
- DrawHand(BIG_HAND_SIZE, gBigHandEnd, TRUE);
- DrawHand(LITTLE_HAND_SIZE, gLittleHandEnd, TRUE);
- SetGWorld(port, gdh);
- CopyBits(scratchBitH^^, thePort^.portBits, worldRect, gWatchPict^^.picFrame, srcCopy, nil);
- UnLockPixels(scratch);
- drawn := TRUE;
- end;
- end;
- if drawn = FALSE then (* ok, will draw the picture into the scratch world *)
- begin
- CalcCenter(TRUE);
- GetGWorld(port, gdh);
- SetGWorld(gWatchWorld, nil);
- DrawFace(TRUE);
- DrawHand(BIG_HAND_SIZE, gBigHandEnd, TRUE);
- DrawHand(LITTLE_HAND_SIZE, gLittleHandEnd, TRUE);
- SetGWorld(port, gdh);
- CopyBits(watchBitH^^, thePort^.portBits, worldRect, gWatchPict^^.picFrame, srcCopy, nil);
- UnLockPixels(watchPixMap);
- drawn := TRUE;
- end;
- end;
- end;
- if (drawn = FALSE) then
- begin
- CalcCenter(FALSE);
- DrawFace(FALSE);
- DrawHand(BIG_HAND_SIZE, gBigHandEnd, FALSE);
- DrawHand(LITTLE_HAND_SIZE, gLittleHandEnd, FALSE);
- end;
- end;
- { refresh the background gworld (every hour) }
- procedure RefreshWatch;
- var
- port: CGrafPtr;
- gdh: GDHandle;
- watchPixMap: PixMapHandle;
- clip: Rect;
- begin
- if gWatchWorld <> nil then
- begin
- GetGWorld(port, gdh);
- watchPixMap := GetGWorldPixMap(gWatchWorld);
- if (LockPixels(watchPixMap)) then
- begin
- SetGWorld(gWatchWorld, nil);
- SetRect(clip, -32768, -32768, 32767, 32767);
- ClipRect(clip);
- TextFont(1);
- DrawFace(TRUE);
- UnlockPixels(watchPixMap);
- end;
- SetGWorld(port, gdh);
- end;
- end;
-
- end.