home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Pascal / Utilities / Siege Watch 2.0 / Watch.p < prev   
Encoding:
Text File  |  1994-04-23  |  12.8 KB  |  521 lines  |  [TEXT/PJMM]

  1. { Watch.p --> routines devoted to drawing the watch }
  2. unit Watch;
  3. interface
  4.     uses
  5.         QDOffscreen, Globals;
  6.     type
  7.         TStringRec = record
  8.                 lastValue: integer;
  9.                 startPnt: Point;
  10.                 blankRect: Rect;
  11.                 theString: StringHandle;
  12.             end;
  13.     const
  14.  
  15.         YEAR_NUM = 1;
  16.         MONTH_NUM = 2;
  17.         DAY_NUM = 3;
  18.         HOUR_NUM = 4;
  19.         MINUTE_NUM = 5;
  20.         SECOND_NUM = 6;
  21.         NUM_FIELDS = SECOND_NUM;
  22.     var
  23.         gRectArray: array[1..NUM_FIELDS] of TStringRec;
  24.  
  25.         gDayRectPict: PicHandle;
  26.  
  27.         gFramePict: PicHandle;
  28.         gZoomed: Boolean;
  29.         gWatchPict: PicHandle;
  30.         gLongHandLenSquared, gShortHandLenSquared: Extended;
  31.         gLongHandLen, gShortHandLen: integer;
  32.         gCenter, gBigHandEnd, gLittleHandEnd: Point;
  33.         gRadDegRatio: Extended;
  34.         gScratchWorld, gWatchWorld: GWorldPtr;
  35.         gEndTime: LONGINT;
  36.         gLastTime: LONGINT;
  37. { function prototypes }
  38. { calculation routines }
  39.     procedure CalcCenter (usesOffScreen: Boolean);
  40.     procedure CalcHands (time: LONGINT);
  41.  
  42.     procedure FillAString (value: integer;
  43.                                     aStringH: StringHandle);
  44.  
  45.     procedure GetNewPoint (minute, length: integer;
  46.                                     lenSquared: Extended;
  47.                                     var endPoint: Point);
  48. { gWorld operations }
  49.     function CheckGWorlds: Boolean;
  50.     function FindDepth: Boolean;
  51.     function InitMyGWorlds: Boolean;
  52. { draw routines }
  53.     procedure DrawAString (aRecord: TStringRec);
  54.     procedure DrawFace (intoOffscreen: Boolean);
  55.     procedure DrawHand (pSize: integer;
  56.                                     deltaPoint: Point;
  57.                                     intoOffscreen: Boolean);
  58.     function DrawIfNeeded (value: integer;
  59.                                     var aRecord: TStringRec): Boolean;
  60.     procedure DrawMyStrings;
  61.     procedure DrawTheWatch;
  62.     procedure KillMyGWorlds;
  63.     procedure RefreshWatch;
  64.  
  65. implementation
  66.     uses
  67.         Sane, MySpeech;
  68. { calculation routines }
  69.     const
  70.  
  71.         BIG_HAND_SIZE = 2;
  72.         LITTLE_HAND_SIZE = 3;
  73.  
  74. { *********************** }
  75. { calc center of picture }
  76.     procedure CalcCenter (usesOffScreen: Boolean);
  77.         var
  78.             pictRect: Rect;
  79.     begin
  80.         pictRect := gWatchPict^^.picFrame;
  81.         if usesOffScreen then
  82.             OffSetRect(pictRect, -pictRect.left, -pictRect.top);
  83.  
  84.         gCenter.h := 2 + (pictRect.right - pictRect.left) div 2;
  85.         gCenter.v := (pictRect.bottom - pictRect.top) div 2;
  86.     end; { CalcCenter }
  87.  
  88.     procedure CalcHands (time: LONGINT);
  89.         var
  90.             hour, minute: LONGINT;
  91.             dateRec: DateTimeRec;
  92.     begin
  93.         Secs2Date(time, dateRec);
  94.         minute := dateRec.minute;
  95.         minute := minute * 6;
  96.         GetNewPoint(minute, gLongHandLen, gLongHandLenSquared, gBigHandEnd);
  97.         if dateRec.hour >= 12 then
  98.             begin
  99.                 hour := dateRec.hour - 12;
  100.             end
  101.         else
  102.             begin
  103.                 hour := dateRec.hour;
  104.             end;
  105.         hour := hour * 30;
  106.         hour := hour + minute div 12;
  107.         GetNewPoint(hour, gShortHandLen, gShortHandLenSquared, gLittleHandEnd);
  108.     end; (* CalcHands *)
  109.  
  110. { fill a string with the ascii equivalent of an integer }
  111.     procedure FillAString (value: integer;
  112.                                     aStringH: StringHandle);
  113.         var
  114.             tempLong: LONGINT;
  115.     begin
  116.         HLock(Handle(aStringH));
  117.         tempLong := value;
  118.         NumToString(tempLong, aStringH^^);
  119.         HUnlock(Handle(aStringH));
  120.     end;
  121.  
  122. { figure out where a hand is supposed to end }
  123.     procedure GetNewPoint (minute, length: integer;
  124.                                     lenSquared: Extended;
  125.                                     var endPoint: Point);
  126.         var
  127.             sinThetaSquared, temp: Extended;
  128.             angle: Extended;
  129.     begin
  130.         if minute = 0 then
  131.             begin
  132.                 endPoint.v := -length;
  133.                 endPoint.h := 0;
  134.             end
  135.         else if minute = 180 then
  136.             begin
  137.                 endPoint.v := length;
  138.                 endPoint.h := 0;
  139.             end
  140.         else
  141.             begin
  142.                 angle := gRadDegRatio * minute;
  143.                 sinThetaSquared := Sin(angle);
  144.                 sinThetaSquared := sinThetaSquared * sinThetaSquared;
  145.                 temp := 1.0 - sinThetaSquared;
  146.                 temp := temp * lenSquared;
  147.                 temp := sqrt(temp);
  148.                 endPoint.v := Num2Longint(temp);
  149.                 temp := sinThetaSquared * lenSquared;
  150.                 temp := sqrt(temp);
  151.                 endPoint.h := Num2Longint(temp);
  152.                 if minute <= 90 then
  153.                     begin
  154.                         endPoint.v := -endPoint.v;
  155.                     end
  156.                 else if minute <= 180 then
  157.                     begin
  158.  
  159.                     end
  160.                 else if minute <= 270 then
  161.                     begin
  162.                         endPoint.h := -endPoint.h;
  163.                     end
  164.                 else
  165.                     begin
  166.                         endPoint.v := -endPoint.v;
  167.                         endPoint.h := -endPoint.h;
  168.                     end;
  169.             end;
  170.     end;
  171.  
  172. { Make the GWorlds we use for offscreen drawing }
  173.     function InitMyGWorlds: Boolean;
  174.         var
  175.             myErr: QDErr;
  176.             worldRect, globRect: Rect;
  177.             wFlags: GWorldFlags;
  178.             gdh: GDHandle;
  179.             theDevPixMap: PixMapHandle;
  180.             tempHandle: Handle;
  181.     begin
  182.         InitMyGWorlds := FALSE;
  183.         worldRect := gWatchPict^^.picFrame;
  184.         OffsetRect(worldRect, -worldRect.left, -worldRect.top);
  185.         LONGINT(wFlags) := 0;
  186.         gWatchWorld := nil;
  187.         gScratchWorld := nil;
  188.         tempHandle := NewHandle(10000);
  189.         if (MaxBlock > 10000) then
  190.             begin
  191.                 myErr := NewGWorld(gWatchWorld, 0, worldRect, nil, nil, wFlags);
  192.  
  193.                 if (myErr = 0) and (gWatchWorld <> nil) then
  194.                     begin
  195.                         RefreshWatch;
  196.                         if (MaxBlock > 10000) then
  197.                             myErr := NewGWorld(gScratchWorld, 0, worldRect, nil, nil, wFlags);
  198.                     end;
  199.             end;
  200.         if tempHandle <> nil then
  201.             DisposHandle(tempHandle);
  202.     end;
  203.  
  204.     procedure KillMyGWorlds;
  205.     begin
  206.         if gWatchWorld <> nil then
  207.             DisposeGWorld(gWatchWorld);
  208.         if gScratchWorld <> nil then
  209.             DisposeGWorld(gScratchWorld);
  210.         gWatchWorld := nil;
  211.         gScratchWorld := nil;
  212.     end;
  213. { make sure the gworlds are valid for current depth, user might have switched }
  214.     function CheckGWorlds: Boolean;
  215.     begin
  216.         CheckGWorlds := FALSE;
  217.         if FindDepth then
  218.             begin
  219.                 CheckGWorlds := TRUE;
  220.                 KillMyGWorlds;
  221.                 if InitMyGWorlds = FALSE then
  222.                     begin
  223.                     end;
  224.             end;
  225.     end;
  226. { find the minimum depth of the current watch face }
  227.     function FindDepth: Boolean;
  228.         var
  229.             globRect: Rect;
  230.             offSet: Point;
  231.             gdh: GDHandle;
  232.             theDevPixMap: PixMapHandle;
  233.     begin
  234.         FindDepth := FALSE;
  235.         if gColorAvailable then
  236.             begin
  237.                 offset.h := 0;
  238.                 offset.v := 0;
  239.                 LocalToGlobal(offset);
  240.                 globRect := gWatchPict^^.picFrame;
  241.                 OffsetRect(globRect, offset.h, offset.v);
  242.                 gdh := GetMaxDevice(globRect);
  243.                 theDevPixMap := gdh^^.gdPMap;
  244.                 if gDepth <> theDevPixMap^^.pixelSize then
  245.                     begin
  246.                         FindDepth := TRUE;
  247.                         gDepth := theDevPixMap^^.pixelSize;
  248.                     end;
  249.             end
  250.         else
  251.             begin
  252.                 gDepth := 1;
  253.             end;
  254.     end;
  255. { draw routines }
  256. { ********************************* }
  257.     procedure DrawAString (aRecord: TStringRec);
  258.     begin
  259.         HLock(Handle(aRecord.theString));
  260.         with aRecord do
  261.             begin
  262.                 MoveTo(startPnt.h, startPnt.v);
  263.                 EraseRect(blankRect);
  264.                 DrawString(theString^^);
  265.             end;
  266.         HUnlock(Handle(aRecord.theString));
  267.     end;
  268.  
  269.     procedure DrawMyStrings;
  270.         var
  271.             i: integer;
  272.     begin
  273.         for i := YEAR_NUM to NUM_FIELDS do
  274.             begin
  275.                 DrawAString(gRectArray[i]);
  276.             end;
  277.     end;
  278.  
  279.     function DrawIfNeeded (value: integer;
  280.                                     var aRecord: TStringRec): Boolean;
  281.     begin
  282.  
  283.         if value <> aRecord.lastValue then
  284.             begin
  285.                 aRecord.lastValue := value;
  286.                 FillAString(value, aRecord.theString);
  287.                 DrawAString(aRecord);
  288.                 DrawIfNeeded := TRUE;
  289.             end
  290.         else
  291.             begin
  292.                 DrawIfNeeded := FALSE;
  293.             end;
  294.     end;
  295.  
  296.     procedure DrawHand (pSize: integer;
  297.                                     deltaPoint: Point;
  298.                                     intoOffscreen: Boolean);
  299.         var
  300.             oldColor, greyColor: RGBColor;
  301.             circleRect: Rect;
  302.             circleWidth: integer;
  303.             hOffset: integer;
  304.             vOffset: integer;
  305.     begin
  306.         if intoOffscreen then
  307.             begin
  308.                 hOffset := 0;
  309.                 vOffset := 0;
  310.             end
  311.         else
  312.             begin
  313.                 hOffset := gWatchPict^^.picFrame.left;
  314.                 vOffset := gWatchPict^^.picFrame.top;
  315.             end;
  316.         circleWidth := pSize + 3;
  317.         circleRect.right := gCenter.h + deltaPoint.h + circleWidth + hOffset;
  318.         circleRect.left := gCenter.h + deltaPoint.h - circleWidth + hOffset;
  319.         circleRect.top := gCenter.v + deltaPoint.v - circleWidth + vOffset;
  320.         circleRect.bottom := gCenter.v + deltaPoint.v + circleWidth + vOffset;
  321.  
  322.         MoveTo(gCenter.h + hOffset, gCenter.v + vOffset);
  323.  
  324.         PenSize(1, 1);
  325.         if pSize = LITTLE_HAND_SIZE then
  326.             begin
  327.  
  328.                 Line(deltaPoint.h, deltaPoint.v);
  329.                 EraseOval(circleRect);
  330.                 FrameOval(circleRect);
  331.             end
  332.         else
  333.             begin
  334.                 Line(deltaPoint.h, deltaPoint.v);
  335.                 PaintOval(circleRect);
  336.             end;
  337.     end;
  338.  
  339.     procedure DrawPieArc (wf: Rect;
  340.                                     time: LONGINT);
  341.         var
  342.             arcAngle: LONGINT;
  343.             oldColor, newColor: RGBColor;
  344.             frame: Rect;
  345.             inset: integer;
  346.             center: Point;
  347.     begin
  348.         arcAngle := (gEndTime - time) div 350640; { # seconds in 4 years / 360 degrees }
  349.         arcAngle := 360 - arcAngle;
  350.         SetRect(frame, wf.left, wf.top, wf.right, wf.bottom);
  351.         InsetRect(frame, 4, 4); { the outer circle is 2 pixels wide }
  352.         OffsetRect(frame, 2, -2);
  353.  
  354.         if gDepth >= 8 then
  355.             begin
  356.                 GetForeColor(oldColor);
  357.                 newColor.red := 40000;
  358.                 newColor.green := 40000;
  359.                 newColor.blue := 40000;
  360.                 RGBForeColor(newColor);
  361.                 PaintArc(frame, 0, arcAngle);
  362.                 RGBForeColor(oldColor);
  363.             end
  364.         else
  365.             begin
  366.                 FillArc(frame, 0, arcAngle, ltGray);
  367.             end;
  368.  
  369.         center.h := frame.left + (frame.right - frame.left) div 2;
  370.         center.v := 1 + frame.top + (frame.bottom - frame.top) div 2;
  371.  
  372.         frame.top := center.v - 7;
  373.         frame.bottom := frame.top + 14;
  374.         frame.left := center.h - 7;
  375.         frame.right := frame.left + 14;
  376.  
  377.         PaintOval(frame); { make center hand pivot circle }
  378.         PenPat(white);
  379.         FrameOval(frame);
  380.         PenPat(black);
  381.     end;
  382. { Draw the face, hopefully into offscreen gworld once an hour }
  383. { otherwise into the window every minute }
  384.     procedure DrawFace (intoOffscreen: Boolean);
  385.         var
  386.             dayFrame, watchFrame, blankRect: Rect;
  387.             aString: Str255;
  388.             time: LONGINT;
  389.             dateRec: DateTimeRec;
  390.             fInfo: FontInfo;
  391.             distHoriz, distVert: integer;
  392.     begin
  393.  
  394.         watchFrame := gWatchPict^^.picFrame;
  395.         dayFrame := gDayRectPict^^.picFrame;
  396.         if intoOffscreen then
  397.             begin
  398.                 SetRect(blankRect, 0, 0, 32767, 32767);
  399.                 EraseRect(blankRect);
  400.                 distHoriz := -watchFrame.left;
  401.                 distVert := -watchFrame.top;
  402.                 OffsetRect(watchFrame, distHoriz, distVert);
  403.                 OffsetRect(dayFrame, distHoriz, distVert);
  404.             end;
  405.         GetDateTime(time);
  406.         HLock(Handle(gWatchPict));
  407.         DrawPicture(gWatchPict, watchFrame);
  408.         HUnlock(Handle(gWatchPict));
  409.  
  410.         DrawPieArc(watchFrame, time);
  411.  
  412.  
  413.         HLock(Handle(gDayRectPict));
  414.         DrawPicture(gDayRectPict, dayFrame);
  415.         HUnlock(Handle(gDayRectPict));
  416.  
  417.         InsetRect(dayFrame, 2, 2);
  418.         ClipRect(dayFrame);
  419.  
  420.         Secs2Date(time, dateRec);
  421.         NumToString(dateRec.day, aString);
  422.         GetFontInfo(fInfo);
  423.         MoveTo(dayFrame.left, dayFrame.top + fInfo.ascent - 1);
  424.         DrawString(aString);
  425.         SetRect(dayFrame, -32768, -32768, 32767, 32767);
  426.         ClipRect(dayFrame);
  427.     end;
  428.  
  429. { we have 3 separate ways of drawing }
  430. { 1) we have 2 gworlds one with the background, arc, date }
  431. {    and another which we blit the background into and then }
  432. {    draw the hands }
  433. { 2) we have 1 gworld into which draw everything and then blit }
  434. {    it to the screen }
  435. { 3) we draw everything into the screen (flickers galore) }
  436.     procedure DrawTheWatch;
  437.         var
  438.             watchPixMap, scratch: PixMapHandle;
  439.             watchBitH, scratchBitH: BitMapHandle;
  440.             port: CGrafPtr;
  441.             gdh: GDHandle;
  442.             worldRect: Rect;
  443.             drawn: Boolean;
  444.     begin
  445.         drawn := FALSE;
  446.         if gWatchWorld <> nil then
  447.             begin
  448.                 worldRect := gWatchPict^^.picFrame;
  449.                 OffsetRect(worldRect, -worldRect.left, -worldRect.top);
  450.                 watchPixMap := GetGWorldPixMap(gWatchWorld);
  451.                 if (LockPixels(watchPixMap)) then
  452.                     begin
  453.                         watchBitH := BitMapHandle(watchPixMap);
  454.                         CalcCenter(TRUE);
  455.                         if gScratchWorld <> nil then
  456.                             begin
  457.                                 scratch := GetGWorldPixMap(gScratchWorld);
  458.                                 if (LockPixels(scratch)) then
  459.                                     begin
  460.                                         scratchBitH := BitMapHandle(scratch);
  461.                                         CopyBits(watchBitH^^, scratchBitH^^, worldRect, worldRect, srcCopy, nil);
  462.                                         UnlockPixels(watchPixMap);
  463.                                         GetGWorld(port, gdh);
  464.                                         SetGWorld(gScratchWorld, nil);
  465.                                         DrawHand(BIG_HAND_SIZE, gBigHandEnd, TRUE);
  466.                                         DrawHand(LITTLE_HAND_SIZE, gLittleHandEnd, TRUE);
  467.                                         SetGWorld(port, gdh);
  468.                                         CopyBits(scratchBitH^^, thePort^.portBits, worldRect, gWatchPict^^.picFrame, srcCopy, nil);
  469.                                         UnLockPixels(scratch);
  470.                                         drawn := TRUE;
  471.                                     end;
  472.                             end;
  473.                         if drawn = FALSE then (* ok, will draw the picture into the scratch world *)
  474.                             begin
  475.                                 CalcCenter(TRUE);
  476.                                 GetGWorld(port, gdh);
  477.                                 SetGWorld(gWatchWorld, nil);
  478.                                 DrawFace(TRUE);
  479.                                 DrawHand(BIG_HAND_SIZE, gBigHandEnd, TRUE);
  480.                                 DrawHand(LITTLE_HAND_SIZE, gLittleHandEnd, TRUE);
  481.                                 SetGWorld(port, gdh);
  482.                                 CopyBits(watchBitH^^, thePort^.portBits, worldRect, gWatchPict^^.picFrame, srcCopy, nil);
  483.                                 UnLockPixels(watchPixMap);
  484.                                 drawn := TRUE;
  485.                             end;
  486.                     end;
  487.             end;
  488.         if (drawn = FALSE) then
  489.             begin
  490.                 CalcCenter(FALSE);
  491.                 DrawFace(FALSE);
  492.                 DrawHand(BIG_HAND_SIZE, gBigHandEnd, FALSE);
  493.                 DrawHand(LITTLE_HAND_SIZE, gLittleHandEnd, FALSE);
  494.             end;
  495.     end;
  496. { refresh the background gworld (every hour) }
  497.     procedure RefreshWatch;
  498.         var
  499.             port: CGrafPtr;
  500.             gdh: GDHandle;
  501.             watchPixMap: PixMapHandle;
  502.             clip: Rect;
  503.     begin
  504.         if gWatchWorld <> nil then
  505.             begin
  506.                 GetGWorld(port, gdh);
  507.                 watchPixMap := GetGWorldPixMap(gWatchWorld);
  508.                 if (LockPixels(watchPixMap)) then
  509.                     begin
  510.                         SetGWorld(gWatchWorld, nil);
  511.                         SetRect(clip, -32768, -32768, 32767, 32767);
  512.                         ClipRect(clip);
  513.                         TextFont(1);
  514.                         DrawFace(TRUE);
  515.                         UnlockPixels(watchPixMap);
  516.                     end;
  517.                 SetGWorld(port, gdh);
  518.             end;
  519.     end;
  520.  
  521. end.