unit GVEyes;

{ Graphics Vision Eyes, Graphics Vision sample unit,
  Copr. 1994,1997 Matthias K”ppe.
}

{$ifndef FPK}
{$A+,B-,F+,G+,I-,O+,P-,Q-,R-,S-,T-,V+,X+}
{$endif FPK}

interface

{$ifdef FPK}
uses Views, Objects, Drivers, GvFPK,
  GvViews, GvDialog, ExtGraph, BGI, GvTexts;
{$else}
uses Views, Objects, Drivers, GvViews, GvDialog;
{$endif}

const
{ Eye palette
}
  CEyes = #1#144;

{ Let the eyes freeze on dragging (increases performance)
}
  EyesFreezeOnDragging: Boolean = false;

type
{ Eye viewer object
}
  PEyes = ^TEyes;
  TEyes = object(TGView)
    LookAt: TPoint;
    constructor Init(var Bounds: TRect);
    procedure CalcFirstPass; virtual;
    procedure Draw; virtual;
    function GetPalette: PPalette; virtual;
    procedure HandleEvent(var Event: TEvent); virtual;
    procedure Update;
  end;

{ Eye window object
}
  PEyeWindow = ^TEyeWindow;
  TEyeWindow = object(TWindow)
    Eyes: PEyes;
    constructor Init(var Bounds: TRect);
  end;

{ Transparent desktop eyes
}
  PDesktopEyes = ^TDesktopEyes;
  TDesktopEyes = object(TEyes)
    constructor Init(var Bounds: TRect);
    function CreateDragView: PGView; virtual;
    procedure HandleEvent(var Event: TEvent); virtual;
  end;

implementation

{$ifndef FPK}
{$ifdef Windows}
uses WinGr, ExtGraph, GvTexts;
{$else}
uses Gr, MyMouse, GVDriver, ExtGraph, MetaGr, GvTexts;
{$endif}
{$endif}

constructor TEyes.Init(var Bounds: TRect);
Begin
  TGView.Init(Bounds);
  GrowMode := gfGrowHiX + gfGrowHiY;
  Options := Options or (ofBuffer + ofBufferOne + ofFirstPass);
  EventMask := EventMask or evBroadCast;
  LookAt.X := MaxInt;
End;

procedure TEyes.CalcFirstPass;
begin
  SetState(sfFirstPass, Options and GlobalOptions and ofFirstPass <> 0)
end;

procedure TEyes.Draw;
var
  r1, r2: Integer;
  Aspect: Real;

const
  f1 = 0.5;
  f2 = 0.2;

 procedure DrawEye(X, Y: Integer);
 var
   dx, dy, dist: Real;
 Begin
   SetFillStyle(SolidFill, 15);
   FillCircle(X, Y, r1);
   If LookAt.X <> MaxInt then Begin
     dx := LookAt.X - X;
     dy := LookAt.Y - Y;
     dist := sqrt(sqr(dx) + sqr(dy));
     If dist > (1 - f1) * r1
     then Begin
       X := X + Round(f1 * r1 / dist * dx);
       Y := Y + Round(f1 * r1 / dist * dy * Aspect);
     End
     else Begin
       X := LookAt.X;
       Y := LookAt.Y
     End;
     SetFillStyle(SolidFill, GetColor(2));
     FillCircle(X, Y, Round(f1 * r1));
     SetFillStyle(SolidFill, 0);
     FillCircle(X, Y, Round(f2 * r1))
   End
 End;

Begin
  Aspect := GetAspect;
  r1 := (Size.X - 30) div 4;
  r2 := (Size.Y - 20) div 2;
  If r2 < r1 then r1 := r2;
  SetColor(0);
  If not GetState(sfTransparent)
  then begin
    SetFillStyle(SolidFill, 0);
    Bar(0, 0, Size.X - 1, Size.Y - 1);
  end;
  DrawEye((Size.X - 4 * r1) div 3 + r1, (Size.Y - 2 * r1) div 2 + r1);
  DrawEye(Size.X - (Size.X - 4 * r1) div 3 - r1, (Size.Y - 2 * r1) div 2 + r1);
End;

function TEyes.GetPalette: PPalette;
const
  P: String[Length(CEyes)] = CEyes;
Begin
  GetPalette := @P;
End;

procedure TEyes.HandleEvent(var Event: TEvent);
Begin
  TGView.HandleEvent(Event);
  If Event.What = evTimer
  then Update
End;

procedure TEyes.Update;
var
  P: TPoint;

	procedure ModifyingDraw; {$ifndef FPK}far;{$endif}
	begin
	  Draw
	end;

Begin
  MakeLocal(MouseWhere, P);
  If (not EyesFreezeOnDragging) or (TheDraggedView = nil) then
  If (P.X <> LookAt.X) or (P.Y <> LookAt.Y) then Begin
    LookAt := P;
    If GetState(sfTransparent)
    then DrawVisibleLocal(@ModifyingDraw)
    else DrawView
  End
End;

{ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ TEyeWindow
}

constructor TEyeWindow.Init(var Bounds: TRect);
var
  R: TRect;
Begin
  TWindow.Init(Bounds, GetStr(33), wnNoNumber);
  Flags := Flags and not wfBackground;
  Options := Options and not ofTileable;
  GetExtent(R);
  R.Grow (-4, -4);
  R.A.Y := 23;
  Eyes := New(PEyes, Init(R));
  Insert(Eyes)
End;

{ ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ TDesktopEyes
}

constructor TDesktopEyes.Init(var Bounds: TRect);
begin
  inherited Init(Bounds);
  State := State or sfTransparent;
  EventMask := EventMask or evMouse;
end;

function TDesktopEyes.CreateDragView: PGView;
begin
  CreateDragView := @Self
end;

procedure TDesktopEyes.HandleEvent(var Event: TEvent);
var
  Limits: TRect;
  Min, Max: TPoint;
begin
  If Event.What = evMouseDown
  then begin
    If Event.Double
    then begin
      Free;
      Exit
    end;
    GOwner^.GetExtent(Limits);
    Limits.A.X := 10 - Size.X;
    Limits.A.Y := 10 - Size.Y;
    Min.X := 45;
    Min.Y := 20;
    Max := Limits.B;
    If Event.Buttons = 1
    then DragView(Event, dmDragMove or DragMode, Limits, Min, Max, 0)
    else DragView(Event, dmDragGrow or DragMode, Limits, Min, Max, rmDnRi);
    ClearEvent(Event)
  end
  else
    inherited HandleEvent(Event)
end;

end.
