#include "metawndo.h" #include const stlOUTLINE = 0x00; const stlFILLED = 0x01; void WaitDisplayBusy( int busy ); typedef struct _range { int lower; int upper; int current; } range; const int objDisplay = 0x01; // The object has been drawn and is visible. const int objActive = 0x02; // The object is active and SHOULD be drawn. class screenObject { protected: point location; int color; int angle; int fillStyle; int Flags; virtual void CalculatePoints() = 0; virtual void CalculateOvals() = 0; public: virtual void Draw (void) = 0; virtual void Erase (void) = 0; virtual void Move (int X, int Y) = 0; virtual void On () { Flags = Flags | objActive; Draw(); }; virtual void Off () { Erase(); Flags = (Flags & (~objActive)); }; virtual void SetColor (int Color = White) { color = Color; if (Flags & objDisplay) Draw(); if (!color) // If the color is black, turn off the display flag. Flags &= (~objDisplay); }; virtual void SetStyle (int Style = stlOUTLINE) { fillStyle = Style; }; virtual void SetAngle (int Angle = 900) { if (angle == Angle) return; if (Angle >= 3600) angle = Angle % 3600; else angle = Angle; Erase(); CalculatePoints(); Draw(); }; }; class hand: public virtual screenObject { protected: rect headOval; // The head is the part of the needle that points // towards the guage value. The body of the needle. rect tailOval; // The tail is a little stub that points away from // the guage value. int headLength; int tailLength; int width; // Width of needle point points[2]; virtual void CalculatePoints () { // Generate the point list. // based on the current ovals // and location. OvalPt ( &headOval, angle, points); if (tailLength) OvalPt ( &tailOval, angle + 1800, &points[1]); else DupPt (&location, &points[1]); }; void CalculateOvals () { // Calculate the head's oval. RadiusToRect ( &location, headLength, &headOval); if (tailLength) { // Calculate the tail's oval. RadiusToRect (&location, tailLength, &tailOval); }; }; virtual void OffsetOvals (int X, int Y) { OffsetRect (&headOval, X, Y); OffsetRect (&tailOval, X, Y); }; virtual void Offset (int X, int Y) { OffsetOvals (X, Y); OffsetPoints (2, points, X, Y); }; friend void RadiusToRect (point *center, int length, rect *Oval); friend void OffsetPoints (int pntCount, point *pointList, int X, int Y); public: hand ( int X = 50, int Y=50, int Angle = 900, int Length = 200, int TailSize = 0, int Width = 0): headLength (Length), tailLength (TailSize), width (Width) { angle = Angle; location.X = X; location.Y = Y; Flags = 0; CalculateOvals(); CalculatePoints(); }; virtual ~hand () { Off(); }; virtual void Draw (void) { if (Flags & objActive) { PenColor (color); if (width) { PenShape (shapeOval); PenCap (capFlat); } PenSize (width, width); PolyLine (2, points); Flags |= objDisplay; // Will only ever be set if objActive is also true. } }; virtual void Erase () { if (Flags & objDisplay) { PenPattern (0); Draw (); Flags &= (~objDisplay); PenPattern (1); } else return; }; virtual void Move (int X, int Y) { if ( (location.X != X) || (location.Y != Y) ) { Erase(); // Have to erase it otherwise it will be bad. int offsetX = X - location.X; int offsetY = Y - location.Y; location.X = X; location.Y = Y; Offset(offsetX, offsetY); Draw(); }; }; virtual void SetLength (int Length) { headLength = Length; CalculateOvals(); CalculatePoints(); Erase(); Draw(); }; virtual void SetWidth (int Width) { width = Width; CalculateOvals(); CalculatePoints(); Erase(); Draw(); }; virtual void SetTailLength (int Length) { tailLength = Length; CalculateOvals(); CalculatePoints(); Erase(); Draw(); }; }; class diamondHand: public virtual hand { protected: rect flareOval; point points[6]; virtual void CalculateOvals () { RadiusToRect ( &location, width/2, &flareOval); // Calculate the head's oval. RadiusToRect ( &location, headLength, &headOval); if (tailLength) // Calculate the tail's oval. RadiusToRect (&location, tailLength, &tailOval); }; virtual void OffsetOvals (int X, int Y) { OffsetRect (&headOval, X, Y); OffsetRect (&tailOval, X, Y); OffsetRect (&flareOval, X, Y); }; virtual void Offset (int X, int Y) { OffsetOvals (X, Y); OffsetPoints (6, points, X, Y); }; virtual void CalculatePoints() { if (tailLength) OvalPt (&tailOval, angle + 1800, points); else DupPt (&location, points); OvalPt (&headOval, angle, &points[1]); OvalPt (&flareOval, angle + 900, &points[2]); DupPt (points, &points[3]); // Same point. OvalPt (&flareOval, angle + 2700, &points[4]); DupPt (&points[1], &points[5]); // Same point. }; public: diamondHand ( int X = 50, int Y=50, int Angle = 900, int Length = 200, int TailSize = 0, int Width = 0): hand (X, Y, Angle, Length, TailSize, Width) { CalculateOvals(); CalculatePoints(); }; virtual ~diamondHand () { Off(); }; virtual void Draw (void) { if (Flags & objActive) { Flags |= objDisplay; PenColor (color); PenSize (0,0); WaitDisplayBusy(False); PolyLine (6, points); } }; }; #include class Watch { hand seconds; diamondHand minutes; diamondHand hours; struct time theTime; struct time oldTime; friend int SecondsToAngle (int seconds); friend int HoursToAngle (int hours); public: Watch () { // Make shure the hands are set to -1 so they'll // recalculate on Watch.Draw() oldTime.ti_sec = -1; oldTime.ti_min = -1; oldTime.ti_hour= -1; seconds.SetColor(Blue); minutes.SetColor(White); hours.SetColor(Red); seconds.SetWidth (5); minutes.SetWidth (20); hours.SetWidth(20); hours.SetLength(120); seconds.SetTailLength (20); minutes.SetTailLength (20); hours.SetTailLength (20); }; On () { Draw(); // Still not on, just sets the time. seconds.On(); minutes.On(); hours.On(); }; Off () { seconds.Off(); minutes.Off(); hours.Off(); }; Draw () { gettime (&theTime); if (theTime.ti_sec != oldTime.ti_sec) { seconds.Erase(); minutes.Draw(); hours.Draw(); seconds.SetAngle (SecondsToAngle (int(theTime.ti_sec))); oldTime.ti_sec = theTime.ti_sec; } if (theTime.ti_min != oldTime.ti_min) { minutes.Erase(); seconds.Draw(); hours.Draw(); minutes.SetAngle (SecondsToAngle (int (theTime.ti_min))); oldTime.ti_min = theTime.ti_min; } if (theTime.ti_hour != oldTime.ti_hour) { hours.Erase(); seconds.Draw(); minutes.Draw(); hours.SetAngle (HoursToAngle (int (theTime.ti_hour))); oldTime.ti_hour = theTime.ti_hour; } }; Move (int X, int Y) { seconds.Move (X,Y); minutes.Move (X,Y); hours.Move (X,Y); }; Erase () { seconds.Erase(); minutes.Erase(); hours.Erase(); }; SetColor (int color) { seconds.SetColor (color); minutes.SetColor (color); hours.SetColor (color); }; }; int SecondsToAngle (int time) { return 900 - (time * 60); }; int HoursToAngle (int time) { return 900 - ((time%12) * 300); }; void OffsetPoints (int pntCount, point *list, int X, int Y) { for (int count = 0; count < pntCount; count++) { list->X += X; list->Y += Y; list++; } }; void RadiusToRect ( point *center, int length, rect *Oval) { // Calculates a bounding rectangle given a center point and radius // of a circle. Oval->Xmin = center->X - length; Oval->Xmax = center->X + length; Oval->Ymin = center->Y - length; Oval->Ymax = center->Y + length; }; extern unsigned _stklen = 14336U; void TestClock (); void main (void) { InitGraphics (VGA640x480); SetDisplay (GrafPg0); grafPort *screen; GetPort (&screen); BackColor (Black); EraseRect (&screen->portRect); TestClock(); SetDisplay (TextPg0); StopGraphics(); }; void TestClock() { Watch TheObject; int color = White; int X = 640 / 2; int Y = 480 / 2; TheObject.Move (X, Y); TheObject.On(); char key; do { do { // Keep drawing the object until a key is pressed. TheObject.Draw(); } while (!kbhit()); key = getch(); // Get the key and decode it. switch (key) { case 'i': Y -= 10; TheObject.Move (X, Y); break; case 'm': Y +=10; TheObject.Move (X, Y); break; case 'j': X -=10; TheObject.Move (X, Y); break; case 'k': X +=10; TheObject.Move (X, Y); break; /* case 'd': angle += 100; TheObject.SetAngle(angle); break; case 'f': angle -= 100; TheObject.SetAngle(angle); break; */ case 'e': color -= 1; TheObject.SetColor (color); break; case 'r': color += 1; TheObject.SetColor (color); break; default: break; }; } while ( key != 'q'); // if the key is 'q' exit out. }; void TestHands() { int X = 320; int Y = 240; int angle = 3600; int color = White; hand TheObject ( X, Y, 3600, 200, 50, 5); TheObject.SetColor (White); TheObject.Draw(); char key; do { key = getch(); switch (key) { case 'i': Y -= 10; TheObject.Move (X, Y); break; case 'm': Y +=10; TheObject.Move (X, Y); break; case 'j': X -=10; TheObject.Move (X, Y); break; case 'k': X +=10; TheObject.Move (X, Y); break; case 'd': angle += 100; TheObject.SetAngle(angle); break; case 'f': angle -= 100; TheObject.SetAngle(angle); break; case 'e': color -= 1; TheObject.Erase(); TheObject.SetColor (color); TheObject.Draw(); break; case 'r': color -= 1; TheObject.Erase(); TheObject.SetColor (color); TheObject.Draw(); break; default: break; }; } while (key != 'q'); }; /* wait for display to: busy = True be in display period busy = False be in vertical retrace period */ void WaitDisplayBusy( int busy ) { int vsync; static int CRTStatusPort = 0x3DA; // EGA\VGA color and CGA // CRTStatusPort = 0x3DA; if( busy ) { // waiting for vertical retrace bit = 0 vsync = 1; while( vsync ) // read the vertical retrace status bit of the CRT status port vsync = inp( CRTStatusPort ) & 8; } else { // waiting for vertical retrace bit = 1 vsync = 0; while( !vsync ) // read the vertical retrace status bit of the CRT status port vsync = inp( CRTStatusPort ) & 8; } }