{ *********************************************************************** }
{                                                                         }
{ Delphi Visual Component Library                                         }
{                                                                         }
{ Copyright (c) 2000-2004 Borland Software Corporation                    }
{                                                                         }
{ *********************************************************************** }

unit Borland.Vcl.Types;

interface

type
  TIntegerDynArray      = array of Integer;
  TCardinalDynArray     = array of Cardinal;
  TWordDynArray         = array of Word;
  TSmallIntDynArray     = array of SmallInt;
  TByteDynArray         = TBytes;
  TShortIntDynArray     = array of ShortInt;
  TInt64DynArray        = array of Int64;
  TLongWordDynArray     = array of LongWord;
  TSingleDynArray       = array of Single;
  TDoubleDynArray       = array of Double;
  TBooleanDynArray      = array of Boolean;
  TStringDynArray       = array of string;
  TWideStringDynArray   = array of WideString;

  TPoint = packed record
    X: LongInt;
    Y: LongInt;
  public
    class function Create(const AX, AY: LongInt): TPoint; static;
    class function Empty: TPoint; static;
    function ToString: string; override;

    function Left: LongInt;
    function Top: LongInt;

    function IsEmpty: Boolean;
    function IsInvalid: Boolean;
    function Equals(const AX, AY: LongInt): Boolean; overload;
    function Equals(const Value: TPoint): Boolean; overload;
  end;

  TSmallPoint = packed record
    X: SmallInt;
    Y: SmallInt;
  public
    class function Create(const AX, AY: SmallInt): TSmallPoint; static;
    class function Empty: TSmallPoint; static;
    function ToString: string; override;

    function Left: SmallInt;
    function Top: SmallInt;

    function IsEmpty: Boolean;
    function IsInvalid: Boolean;
    function Equals(const AX, AY: SmallInt): Boolean; overload;
    function Equals(const Value: TSmallPoint): Boolean; overload;
  end;

  TSize = packed record
    Width: LongInt;
    Height: LongInt;
  public
    class function Create(const AW, AH: LongInt): TSize; static;
    class function Empty: TSize; static;
    function ToString: string; override;

    function get_cx: LongInt; deprecated;
    procedure set_cx(const Value: LongInt); deprecated;
    function get_cy: LongInt; deprecated;
    procedure set_cy(const Value: LongInt); deprecated;

                                             
    /// TODO: Document that cx and cy no longer are passible as a var param
    property cx: LongInt read get_cx write set_cx; //deprecated;
    property cy: LongInt read get_cy write set_cy; //deprecated;

    function IsEmpty: Boolean;
    function Equals(const AW, AH: LongInt): Boolean; overload;
    function Equals(const Value: TSize): Boolean; overload;
                                                         
    //function Equals(const Value: TRect): Boolean; overload;
  end;

  TRect = packed record
    Left, Top, Right, Bottom: LongInt;
  strict private
    class function IfThen(const ATest: Boolean; const ATrue, AFalse: LongInt): LongInt; static;
  public
    class function Create(const ALeft, ATop, ARight, ABottom: LongInt): TRect; overload; static;
    class function Create(const ATopLeft, ABottomRight: TPoint): TRect; overload; static;
    class function Create(const ATopLeft: TPoint; const ASize: TSize): TRect; overload; static;
    class function Bounds(const ALeft, ATop, AWidth, AHeight: LongInt): TRect; static;
    class function Empty: TRect; static;
    function ToString: string; override;

    function get_TopLeft: TPoint;
    procedure set_TopLeft(const Value: TPoint);
    function get_BottomRight: TPoint;
    procedure set_BottomRight(const Value: TPoint);

    /// TODO: Document that TopLeft and BottomRight no longer are passible as a var param
    property TopLeft: TPoint read get_TopLeft write set_TopLeft;
    property BottomRight: TPoint read get_BottomRight write set_BottomRight;
    function GetWidth: LongInt;
    function GetHeight: LongInt;
    function GetSize: TSize;
    function GetCenterPoint: TPoint;

    function IsEmpty: Boolean;
    function Equals(const Value: TRect): Boolean; overload;
    function Equals(const Value: TSize): Boolean; overload;
    function Contains(const X, Y: LongInt): Boolean; overload;
    function Contains(const Value: TPoint): Boolean; overload;
    function Contains(const Value: TRect): Boolean; overload;
    function Intersects(const Other: TRect): Boolean; overload;

    function GetIntersect(const Other: TRect): TRect; overload;
    function GetIntersect(const Other: TRect; out AResult: TRect): Boolean; overload;

    function GetUnion(const Other: TRect): TRect; overload;
    function GetUnion(const Other: TRect; out AResult: TRect): Boolean; overload;

    function GetOffset(const X, Y: LongInt): TRect; overload;
    function GetOffset(const Value: TPoint): TRect; overload;

    function GetInflate(const DeltaWidth, DeltaHeight: LongInt): TRect; overload;
    function GetInflate(const Delta: TPoint): TRect; overload;
  end;

function EqualRect(const R1, R2: TRect): Boolean;
function Rect(ALeft, ATop, ARight, ABottom: LongInt): TRect; overload;
function Rect(const ATopLeft, ABottomRight: TPoint): TRect; overload;
function Bounds(ALeft, ATop, AWidth, AHeight: LongInt): TRect;
function PtInRect(const ARect: TRect; const P: TPoint): Boolean; overload;
function PtInRect(const ARect: TRect; ALeft, ATop: LongInt): Boolean; overload;
function RectInRect(const R1, R2: TRect): Boolean;
function IntersectRect(out ARect: TRect; const R1, R2: TRect): Boolean;
function UnionRect(out ARect: TRect; const R1, R2: TRect): Boolean;
function IsRectEmpty(const ARect: TRect): Boolean;
function OffsetRect(var ARect: TRect; DX: LongInt; DY: LongInt): Boolean;
function CenterPoint(const ARect: TRect): TPoint;

function Point(AX, AY: LongInt): TPoint;
function SmallPoint(AX, AY: SmallInt): TSmallPoint;
function PointsEqual(const P1, P2: TPoint): Boolean; overload;
function PointsEqual(const P1, P2: TSmallPoint): Boolean; overload;
function InvalidPoint(X, Y: LongInt): Boolean; overload;
function InvalidPoint(const At: TPoint): Boolean; overload;
function InvalidPoint(const At: TSmallPoint): Boolean; overload;

type
  TValueRelationship = -1..1;

const
  LessThanValue = Low(TValueRelationship);
  EqualsValue = 0;
  GreaterThanValue = High(TValueRelationship);

const
  EmptyRect: TRect = (Left: 0; Right: 0; Top: 0; Bottom: 0);

implementation

class function TPoint.Create(const AX, AY: LongInt): TPoint;
begin
  Result.X := AX;
  Result.Y := AY;
end;

class function TPoint.Empty: TPoint;
begin
  Result := Create(0, 0);
end;

function TPoint.ToString: string;
begin
  Result := '{X=' + X.ToString + // DO NOT LOCALIZE
            ',Y=' + Y.ToString + '}'; // DO NOT LOCALIZE
end;

function TPoint.Left: LongInt;
begin
  Result := X;
end;

function TPoint.Top: LongInt;
begin
  Result := Y;
end;

function TPoint.IsEmpty: Boolean;
begin
  Result := (X = 0) and (Y = 0);
end;

function TPoint.IsInvalid: Boolean;
begin
  Result := (X = -1) and (Y = -1);
end;

function TPoint.Equals(const AX, AY: LongInt): Boolean;
begin
  Result := (X = AX) and (Y = AY);
end;

function TPoint.Equals(const Value: TPoint): Boolean;
begin
  Result := (X = Value.X) and (Y = Value.Y);
end;


class function TSmallPoint.Create(const AX, AY: SmallInt): TSmallPoint;
begin
  Result.X := AX;
  Result.Y := AY;
end;

class function TSmallPoint.Empty: TSmallPoint;
begin
  Result := Create(0, 0);
end;

function TSmallPoint.ToString: string;
begin
  Result := '{X=' + X.ToString + // DO NOT LOCALIZE
            ',Y=' + Y.ToString + '}'; // DO NOT LOCALIZE
end;

function TSmallPoint.Left: SmallInt;
begin
  Result := X;
end;

function TSmallPoint.Top: SmallInt;
begin
  Result := Y;
end;

function TSmallPoint.IsEmpty: Boolean;
begin
  Result := (X = 0) and (Y = 0);
end;

function TSmallPoint.IsInvalid: Boolean;
begin
  Result := (X = -1) and (Y = -1);
end;

function TSmallPoint.Equals(const AX, AY: SmallInt): Boolean;
begin
  Result := (X = AX) and (Y = AY);
end;

function TSmallPoint.Equals(const Value: TSmallPoint): Boolean;
begin
  Result := (X = Value.X) and (Y = Value.Y);
end;


class function TSize.Create(const AW, AH: LongInt): TSize;
begin
  Result.Width := AW;
  Result.Height := AH;
end;

class function TSize.Empty: TSize;
begin
  Result := TSize.Create(0, 0);
end;

function TSize.ToString: string;
begin
  Result := '{Width=' + Width.ToString + // DO NOT LOCALIZE
            ',Height=' + Height.ToString + '}'; // DO NOT LOCALIZE
end;

function TSize.get_CX: LongInt;
begin
  Result := Width;
end;

procedure TSize.set_CX(const Value: LongInt);
begin
  Width := Value;
end;

function TSize.get_CY: LongInt;
begin
  Result := Height;
end;

procedure TSize.set_CY(const Value: LongInt);
begin
  Height := Value;
end;

function TSize.IsEmpty: Boolean;
begin
  Result := (Width <= 0) and
            (Height <= 0);
end;

function TSize.Equals(const AW, AH: LongInt): Boolean;
begin
  Result := (Width = AW) and
            (Height = AH);
end;

function TSize.Equals(const Value: TSize): Boolean;
begin
  Result := Equals(Value.Width, Value.Height);
end;

                                                     
//function TSize.Equals(const Value: TRect): Boolean;
//begin
//  Result := Equals(Value.Size);
//end;


class function TRect.Create(const ALeft, ATop, ARight, ABottom: LongInt): TRect;
begin
  Result.Left := ALeft;
  Result.Top := ATop;
  Result.Right := ARight;
  Result.Bottom := ABottom;
end;

class function TRect.Create(const ATopLeft, ABottomRight: TPoint): TRect;
begin
  Result := TRect.Create(ATopLeft.X, ATopLeft.Y,
                         ABottomRight.X, ABottomRight.Y);
end;

class function TRect.Create(const ATopLeft: TPoint; const ASize: TSize): TRect;
begin
  Result := TRect.Create(ATopLeft.X, ATopLeft.Y,
                         ATopLeft.X + ASize.Width, ATopLeft.Y + ASize.Height);
end;

class function TRect.Bounds(const ALeft, ATop, AWidth, AHeight: LongInt): TRect;
begin
  Result := TRect.Create(ALeft, ATop, ALeft + AWidth, ATop + AHeight);
end;

class function TRect.Empty: TRect;
begin
  Result := TRect.Create(0, 0, 0, 0);
end;

function TRect.ToString: string;
begin
  Result := '{X=' + Left.ToString + // DO NOT LOCALIZE
            ',Y=' + Top.ToString + // DO NOT LOCALIZE
            ',Width=' + GetWidth.ToString + // DO NOT LOCALIZE
            ',Height=' + GetHeight.ToString + '}'; // DO NOT LOCALIZE
end;

function TRect.get_TopLeft: TPoint;
begin
  Result := TPoint.Create(Left, Top);
end;

procedure TRect.set_TopLeft(const Value: TPoint);
begin
  Left := Value.X;
  Top := Value.Y;
end;

function TRect.get_BottomRight: TPoint;
begin
  Result := TPoint.Create(Right, Bottom);
end;

procedure TRect.set_BottomRight(const Value: TPoint);
begin
  Right := Value.X;
  Bottom := Value.Y;
end;

function TRect.GetWidth: LongInt;
begin
  Result := Right - Left;
end;

function TRect.GetHeight: LongInt;
begin
  Result := Bottom - Top;
end;

function TRect.GetSize: TSize;
begin
  Result := TSize.Create(GetWidth, GetHeight);
end;

function TRect.GetCenterPoint: TPoint;
begin
  Result := TPoint.Create(GetWidth div 2 + Left,
                          GetHeight div 2 + Top);
end;


function TRect.IsEmpty: Boolean;
begin
  Result := (Right <= Left) or
            (Bottom <= Top);
end;

function TRect.Equals(const Value: TRect): Boolean;
begin
  Result := (Left = Value.Left) and
            (Top = Value.Top) and
            (Right = Value.Right) and
            (Bottom = Value.Bottom);
end;

function TRect.Equals(const Value: TSize): Boolean;
begin
  Result := Value.Equals(GetSize);
end;

function TRect.Contains(const X, Y: LongInt): Boolean;
begin
  Result := (X >= Left) and
            (Y >= Top) and
            (X < Right) and
            (Y < Bottom);
end;

function TRect.Contains(const Value: TPoint): Boolean;
begin
  Result := Contains(Value.X, Value.Y);
end;

function TRect.Contains(const Value: TRect): Boolean;
begin
  Result := (Value.Left >= Left) and
            (Value.Top >= Top) and
            (Value.Right < Right) and
            (Value.Bottom < Bottom);
end;

// This is here because Types can't know about Math
class function TRect.IfThen(const ATest: Boolean; const ATrue, AFalse: LongInt): LongInt;
begin
  if ATest then
    Result := ATrue
  else
    Result := AFalse;
end;

function TRect.Intersects(const Other: TRect): Boolean;
begin
  Result := ((Left < Other.Right) and
             (Right > Other.Left)) and
            ((Top < Other.Bottom) and
             (Bottom > Other.Top));
end;

function TRect.GetIntersect(const Other: TRect): TRect;
begin
  Result := TRect.Create(IfThen(Other.Left > Left, Other.Left, Left),
                         IfThen(Other.Top > Top, Other.Top, Top),
                         IfThen(Other.Right < Right, Other.Right, Right),
                         IfThen(Other.Bottom < Bottom, Other.Bottom, Bottom));
end;

function TRect.GetIntersect(const Other: TRect; out AResult: TRect): Boolean;
begin
  AResult := GetIntersect(Other);
  Result := not AResult.IsEmpty;
  if not Result then
    AResult := Empty;
end;

function TRect.GetUnion(const Other: TRect): TRect;
begin
  if Other.IsEmpty then
    Result := Self
  else
    Result := TRect.Create(IfThen(Other.Left < Left, Other.Left, Left),
                           IfThen(Other.Top < Top, Other.Top, Top),
                           IfThen(Other.Right > Right, Other.Right, Right),
                           IfThen(Other.Bottom > Bottom, Other.Bottom, Bottom));
end;

function TRect.GetUnion(const Other: TRect; out AResult: TRect): Boolean;
begin
  AResult := GetUnion(Other);
  Result := not AResult.IsEmpty;
  if not Result then
    AResult := Empty;
end;

function TRect.GetOffset(const X, Y: LongInt): TRect;
begin
  Result := TRect.Create(Left + X, Top + Y, Right + X, Bottom + Y);
end;

function TRect.GetOffset(const Value: TPoint): TRect;
begin
  Result := GetOffset(Value.X, Value.Y);
end;

function TRect.GetInflate(const DeltaWidth, DeltaHeight: LongInt): TRect;
begin
  Result := TRect.Create(Left - DeltaWidth, Top - DeltaHeight,
                         Right + DeltaWidth, Bottom + DeltaHeight);
end;

function TRect.GetInflate(const Delta: TPoint): TRect;
begin
  Result := GetInflate(Delta.X, Delta.Y);
end;


function EqualRect(const R1, R2: TRect): Boolean;
begin
  Result := R1.Equals(R2);
end;

function Rect(ALeft, ATop, ARight, ABottom: LongInt): TRect;
begin
  Result := TRect.Create(ALeft, ATop, ARight, ABottom);
end;

function Rect(const ATopLeft, ABottomRight: TPoint): TRect;
begin
  Result := TRect.Create(ATopLeft, ABottomRight);
end;

function PtInRect(const ARect: TRect; const P: TPoint): Boolean;
begin
  Result := ARect.Contains(P);
end;

function PtInRect(const ARect: TRect; ALeft, ATop: LongInt): Boolean;
begin
  Result := ARect.Contains(ALeft, ATop);
end;

function RectInRect(const R1, R2: TRect): Boolean;
begin
  Result := R1.Contains(R2);
end;

function IntersectRect(out ARect: TRect; const R1, R2: TRect): Boolean;
begin
  Result := R1.GetIntersect(R2, ARect);
end;

function UnionRect(out ARect: TRect; const R1, R2: TRect): Boolean;
begin
  Result := R1.GetUnion(R2, ARect);
end;

function IsRectEmpty(const ARect: TRect): Boolean;
begin
  Result := ARect.IsEmpty;
end;

function OffsetRect(var ARect: TRect; DX: LongInt; DY: LongInt): Boolean;
begin
                          
  ARect := ARect.GetOffset(DX, DY);
  Result := True;
                                                                           
  {if @ARect <> nil then // Test to increase compatiblity with Windows
  begin
    Inc(ARect.Left, DX);
    Inc(ARect.Right, DX);
    Inc(ARect.Top, DY);
    Inc(ARect.Bottom, DY);
    Result := True;
  end
  else
    Result := False;}
end;

function Bounds(ALeft, ATop, AWidth, AHeight: LongInt): TRect;
begin
  Result := TRect.Bounds(ALeft, ATop, AWidth, AHeight);
end;

function CenterPoint(const ARect: TRect): TPoint;
begin
  Result := ARect.GetCenterPoint;
end;

function Point(AX, AY: LongInt): TPoint;
begin
  Result := TPoint.Create(AX, AY);
end;

function SmallPoint(AX, AY: SmallInt): TSmallPoint;
begin
  Result := TSmallPoint.Create(AX, AY);
end;

function PointsEqual(const P1, P2: TPoint): Boolean;
begin
  Result := P1.Equals(P2);
end;

function PointsEqual(const P1, P2: TSmallPoint): Boolean;
begin
  Result := P1.Equals(P2);
end;

function InvalidPoint(X, Y: LongInt): Boolean;
begin
  Result := TPoint.Create(X, Y).IsInvalid;
end;

function InvalidPoint(const At: TPoint): Boolean;
begin
  Result := At.IsInvalid;
end;

function InvalidPoint(const At: TSmallPoint): Boolean;
begin
  Result := At.IsInvalid;
end;

end.
