unit nkavesimu;
{
   Tässä tiedostossa on simulaattorin peruskomponentit.

   Author:  Vesa Lappalainen
   Date:    9.9.1996
   Changes: 5.10.1996
              + Automaattinen scale
              + muuttuneen top/left/height/width muuttaminen
                reaalikoordinaatteihin
   Changes: 02.04.1997
              + SimulationOn ominaisuus, joka on oletuksen poissa päältä.
                Se voidaan asettaa komponenttikohtaisesti päälle.
                Erikseen pitää tarkistaa mihin komponentteihin tämä
                vaikuttaa.  Lisäyshetkellä vain anturiin


     TScale        - paneeli, johon voidaan komponentteja laittaa, ja
                     jolla on skaala, jolla komponentit skaalataan

     TaSimuObject  - "abstrakti" simulaattoriobjekti, joka osaa käyttää
                     reaalilukokoordinaatteja ja periytyy TShape-komponentista

         Paint-viestin käsittely
                     Jos tämän perillisessä määritellään Paint uudestaan
                     pitää joko kutsua perittyä Paintia tai kutsua
                     CheckScale -metodia, jolla voidaan tarkistaa onko
                     skaala muuttunut tai suunnittelija siirtänyt komponenttia
                     kokonaislukukoordinaattien avulla (lähinnä suunnittelun
                     aikana).

         Automaattinen scale
                     Jos komponentti laitetaan Scale-ikkunan sisään, on sen
                     Scale aina Parent.  Jos laitetaan ei-Scale -ikkunan
                     sisään, niin Scale voidaan vaihtaa, mutta Scale-arvon
                     muuttuessa ei välttämättä päivitys onnistu
                     sataporsenttisesti (ei tule välttämättä Paint-viestiä

}

interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls,kdouble,nkpoint,nkbox,nkscale;

type

  {----------------------------------------------------------------------------}
  {
      TaSimuObject
        - Fy,Fy  - reaalisia
  }
  {----------------------------------------------------------------------------}
  TLinkDirX = (ldLeft,ldMid,ldRight);
  TLinkDirY = (ldBottom,ldCenter,ldTop);
  TaSimuObject = class;
  TLinkComp = class;

  TLink = class(TPersistent)
  private
    FLink : TControl;
    FLink2 : TLinkComp;
    FLinkP : TDPoint;
    FLinkDirX : TLinkDirX;
    FLinkDirY : TLinkDirY;
    FLinkOrgX : TLinkDirX;
    FLinkOrgY : TLinkDirY;
    FLinkBox : TDBox;
    FWhosLink : TaSimuObject;  // WhosLink
  protected

  public
    constructor Create; virtual;
    constructor Create1(AWhosLink:TaSimuObject); virtual;
    destructor Destroy; override;
    procedure SetLinkDirX(value:TLinkDirX); virtual;
    procedure SetLinkDirY(value:TLinkDirY); virtual;
    procedure SetLinkOrgX(value:TLinkDirX); virtual;
    procedure SetLinkOrgY(value:TLinkDirY); virtual;
    procedure SetLink(l:TControl);             virtual;
    procedure LinkChange(const p:TDPoint); virtual;
    procedure CheckLink;                       virtual;
    procedure Assign(Source: TPersistent); override;
    procedure SetWhosLink(s:TaSimuObject); virtual;
    procedure SetWhosLink2(s:TaSimuObject); virtual;
    procedure SetLink2(value:TLinkComp); virtual;
  published
    property Link : TControl read FLink write SetLink;
    property LinkP : TDPoint read FLinkP write FLinkP;
    property LinkDirX : TLinkDirX read FLinkDirX write SetLinkDirX default ldLeft;
    property LinkDirY : TLinkDirY read FLinkDirY write SetLinkDirY default ldBottom;
    property LinkOrgX : TLinkDirX read FLinkOrgX write SetLinkOrgX default ldLeft;
    property LinkOrgY : TLinkDirY read FLinkOrgY write SetLinkOrgY default ldBottom;
    property Link2 : TLinkComp read FLink2 write SetLink2;
  end;

  TLinkComp = class(TComponent)
    FLink : TLink;
  public
    constructor Create(AParent:TComponent); override;
    destructor Destroy; override;
    procedure CheckLink;                       virtual;
  published
    property Link : TLink read FLink write FLink;
  end;


  TaSimuObject = class(TShape)
  private
    FScale : TScale;
    FScaleVersion : integer;         { Skaalauksen muuttumisen tarkistus       }
    FBox : TDBox;
    FLink : TLink;
    FSimulationOn : boolean;
  protected

    procedure SetScale(AScale:TScale);         virtual;
    procedure SetParent(AParent:TWinControl);  override;
  public
    constructor Create(AOwner:TComponent);     override;
    destructor Destroy;                        override;
    procedure DoScale(force:boolean);          virtual;
    procedure DoIScale;                        virtual;
    procedure ShowChange;                      virtual;
    function Advance(dx:Double) : boolean;     virtual;
    procedure Paint;                           override;
    procedure Loaded;                          override;
    procedure SetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
    procedure BoxChange(const b:TDBox); virtual;
    procedure SetLink(l:TLink); virtual;
    procedure CheckLink;                       virtual;
  published
    property Scale : TScale Read FScale write SetScale;
    property Box : TDBox read FBox write FBox;
    property Link : TLink read FLink write SetLink;
    property SimulationOn : boolean Read FSimulationOn write FSimulationOn default false;
    property Left stored false;
    property Top stored false;
    property Width stored false;
    property Height stored false;
  end; { TSheet }


procedure Register;

{------------------------------------------------------------------------------}
implementation

{------------------------------------------------------------------------------}
procedure Register;
begin
  RegisterComponents('Kave2000', [TaSimuObject,TLinkComp]);
end;

{------------------------------------------------------------------------------}
{ TaSimuObject ================================================================}
{------------------------------------------------------------------------------}

{------------------------------------------------------------------------------}
procedure TaSimuObject.ShowChange;
begin
end;

{------------------------------------------------------------------------------}
procedure TaSimuObject.DoIScale;
{ Skaalataan reaalikoordinaatit kok. koordinaattien pohjalta                   }
begin

end;

{------------------------------------------------------------------------------}
procedure TaSimuObject.DoScale(force:boolean);
// Kaikki koonmuutokset kiertävät tästä kautta.
var ip,idp : TPoint;
begin
  if ( not force ) and ( csLoading in ComponentState ) then exit;
  if ( FScale = NIL ) then begin
    DoIScale;
    Exit;
  end;
  Box.ToWin(ip,idp,Scale);
  FScaleVersion := Scale.Changes;
  if ( idp.x <= 0 ) then idp.x := 1;
  if ( idp.y <= 0 ) then idp.y := 1;
  inherited SetBounds(ip.x,ip.y,idp.x,idp.y);
  CheckLink;
end;

{------------------------------------------------------------------------------}
procedure TaSimuObject.SetScale(AScale:TScale);
begin
//  if ( FScale = Parent ) then exit;
  FScale := AScale;
  if ( csLoading in ComponentState ) then exit;
  DoScale(false);
end;

{------------------------------------------------------------------------------}
function TaSimuObject.Advance(dx:Double) : boolean;
begin
  Box.p.AddXY(dx,0);
  Result := True;
end;

{------------------------------------------------------------------------------}
constructor TaSimuObject.Create(AOwner:TComponent);
begin
  inherited Create(AOwner);
  Shape := stRectangle;
  FScale := NIL;
  FSimulationOn := false;
  FBox := TDBox.Create5(0,0,20,20,BoxChange);
  FLink := TLink.Create1(self);
{  Brush.Color := clBlue;}
end;

//-----------------------------------------------------------------------------
destructor TaSimuObject.Destroy; //                         override;
begin
  FLink.Free;
  FBox.Free;
  inherited;
end;

{------------------------------------------------------------------------------}
procedure TaSimuObject.Paint;
begin
  inherited Paint;
end;

{------------------------------------------------------------------------------}
procedure TaSimuObject.Loaded;
begin
  inherited Loaded;
  if ( Scale = NIL ) and ( Parent is TScale ) then begin
    FScale := (Parent as TScale);
    DoIScale;
    Exit;
  end;
  if ( Scale <> NIL ) then DoScale(true);
end;

{------------------------------------------------------------------------------}
procedure TaSimuObject.SetParent(AParent:TWinControl);
begin
  inherited SetParent(AParent);
  if {( Scale = NIL ) and }( Parent is TScale ) then begin
    Scale := (Parent as TScale);
{    ShowMessage(Format('(%g,%g)',[Fx,Fy]));}
  end;

end;

//-----------------------------------------------------------------------------
procedure TaSimuObject.SetBounds(ALeft, ATop, AWidth, AHeight: Integer); //  override;
{ Tämän pääasiallinen tehtävä on tarkistaa SUUNNITTELUN aikan mahdolliset
  suunnittelijan tekemät siirrot kontrollille.  Jos on siirretty, niin
  reaalikoordinaatit pitää päivittää muuttuneiden kokonaislukukoordinaattien
  mukaan
}
begin
  if ( Box = nil ) then begin
    inherited SetBounds(ALeft,ATop,AWidth,AHeight);
    Exit;
  end;
  if ( csLoading in ComponentState ) then exit;
  Box.FromWin(ALeft,ATop,AWidth,AHeight,Scale);
  CheckLink;
end;

//-----------------------------------------------------------------------------
procedure TaSimuObject.BoxChange(const b:TDBox); //  virtual;
begin
  DoScale(true);
end;


//-----------------------------------------------------------------------------
procedure TaSimuObject.SetLink(l:TLink); //  virtual;
begin
  FLink := l;
end;


//-----------------------------------------------------------------------------
procedure TaSimuObject.CheckLink; //                        virtual;
begin
  if ( Assigned(Link) ) then Link.CheckLink;
end;

//-----------------------------------------------------------------------------
// TLink
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
procedure TLink.SetWhosLink2(s:TaSimuObject); //  virtual;
// Asettaa sen, kuka linkkaa, muttei päivitä linkkejä => edullisempi rekursio
begin
  FWhosLink := s; // ???? Ja kaikki tähän liittyvä
  if ( Assigned(Link2) ) then Link2.Link.SetWhosLink2(s);
end;


//-----------------------------------------------------------------------------
procedure TLink.SetWhosLink(s:TaSimuObject); //  virtual;
// Asettaa sen, kuka linkkaa ja päivittää linkit
begin
  SetWhosLink2(s);
  CheckLink;
end;


//-----------------------------------------------------------------------------
constructor TLink.Create; //  virtual;
begin
  inherited Create;
  FLinkP := TDPoint.Create3(0,0,LinkChange);
  FLinkBox := TDBox.Create;

end;

//-----------------------------------------------------------------------------
constructor TLink.Create1(AWhosLink:TaSimuObject); //  virtual;
begin
  inherited Create;
  FLinkP := TDPoint.Create3(0,0,LinkChange);
  FLinkBox := TDBox.Create;
  FWhosLink := AWhosLink;
end;


//-----------------------------------------------------------------------------
destructor TLink.Destroy; //  override;
begin
  FLinkBox.Free;
  FLinkP.Free;
  inherited;
end;

//------------------------------------------------------------------------------
procedure TLink.SetLink(l:TControl);
begin
  FLink := l;
  CheckLink;
end;

//------------------------------------------------------------------------------
procedure TLink.CheckLink;
var np,ndp : TPoint; l : TaSimuObject;
  procedure AddOrg;
  begin
    FLinkBox.p.AddXY(Ord(LinkOrgX)/2*FWhosLink.Box.dp.x,
                     Ord(LinkOrgY)/2*FWhosLink.Box.dp.y);
  end;
begin
  if ( FLink = NIL ) then exit;
  if ( FWhosLink = nil ) then exit;
  if ( Link is TaSimuObject ) then begin
    l := Link as TaSimuObject;
    FLinkBox.p.Assign(FWhosLink.Box.p); FLinkBox.p.AddV(LinkP);
    AddOrg;
    l.Box.p.Assign(FLinkBox.p);
    exit;
  end;
  FLinkBox.FromWin(Link.Left,Link.Top,Link.Width,Link.Height,FWhosLink.Scale);
  FLinkBox.p.Assign(FWhosLink.Box.p);
  AddOrg;
  FLinkBox.ToWinDXY(np,ndp,FWhosLink.Scale,
                    -ord(LinkDirX)*Link.Width div 2,
                    -ord(LinkDirY)*Link.Height div 2);
  Link.SetBounds(np.x,np.y,Link.Width,Link.Height);
  if ( Assigned(Link2) ) then Link2.CheckLink;
end;

//-----------------------------------------------------------------------------
procedure TLink.LinkChange(const p:TDPoint); //  virtual;
begin
  FLinkBox.Origo.Assign(p);
  FLinkBox.Origo.Neg;
  CheckLink;
end;

//-----------------------------------------------------------------------------
procedure TLink.SetLinkDirX(value:TLinkDirX); //  virtual;
begin
  FLinkDirX := value;
  CheckLink;
end;

//-----------------------------------------------------------------------------
procedure TLink.SetLinkDirY(value:TLinkDirY); //  virtual;
begin
  FLinkDirY := value;
  CheckLink;
end;

//-----------------------------------------------------------------------------
procedure TLink.SetLinkOrgX(value:TLinkDirX); //  virtual;
begin
  FLinkOrgX := value;
  CheckLink;
end;


//-----------------------------------------------------------------------------
procedure TLink.SetLinkOrgY(value:TLinkDirY); //  virtual;
begin
  FLinkOrgY := value;
  CheckLink;
end;


//-----------------------------------------------------------------------------
procedure TLink.Assign(Source: TPersistent); //  virtual;
var l : TLink;
begin
  if not (source is TPersistent) then exit;
  l := source as TLink;
  FLink := l.Link;
  LinkP.Assign(l.LinkP);
  FLinkDirX := l.LinkDirX;
  FLinkDirY := l.LinkDirY;
  CheckLink;
end;

//-----------------------------------------------------------------------------
procedure TLink.SetLink2(value:TLinkCOmp); //  virtual;
begin
  FLink2 := value;
  if ( assigned(Link2) ) then Link2.Link.SetWhosLink2(FWhosLink);
  CheckLink;
end;


//-----------------------------------------------------------------------------
// TLinkCOmp
//-----------------------------------------------------------------------------
constructor TLinkComp.Create(AParent:TComponent); //  override;
begin
  inherited;
  FLink := TLink.Create1(nil);
end;


//-----------------------------------------------------------------------------
destructor TLinkComp.Destroy; //  override;
begin
  FLink.Free;
  inherited;
end;


//-----------------------------------------------------------------------------
procedure TLinkComp.CheckLink; //                        virtual;
begin
  if ( Assigned(Link) ) then Link.CheckLink;
end;




end.



