// Пример разработки и использования коллекции.
// Юрий Зотов (yurzosoft@mtu-net.ru?subject=Collections).
// 29 апреля 2000 года.
// Специально для сайта "Королевство Delphi" (http://delphi.vitpc.com).

unit DappledShape;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls;

type
  TSpot = class(TCollectionItem)
  private
    FCenterX: integer;
    FCenterY: integer;
    FColor: TColor;
    procedure SetCenterX(const Value: integer);
    procedure SetCenterY(const Value: integer);
    procedure SetColor(const Value: TColor);
  public
    constructor Create(Collection: TCollection); override;
  published
    property CenterX: integer read FCenterX write SetCenterX default 3;
    property CenterY: integer read FCenterY write SetCenterY default 3;
    property Color: TColor read FColor write SetColor default clBlack;
  end;

  TDappledShape = class;
  TItemChangeEvent = procedure(Item: TCollectionItem) of object;

  TSpotCollection = class(TCollection)
  private
    FDappledShape: TDappledShape;
    FOnItemChange : TItemChangeEvent;
    function GetItem(Index: Integer): TSpot;
    procedure SetItem(Index: Integer; const Value: TSpot);
  protected
    function GetOwner: TPersistent; override;
    procedure Update(Item: TCollectionItem); override;
    procedure DoItemChange(Item: TCollectionItem); dynamic;
  public
    constructor Create(DappledShape: TDappledShape);
    function Add: TSpot;
    property Items[Index: Integer]: TSpot read GetItem write SetItem; default;
  published
    property OnItemChange: TItemChangeEvent
      read FOnItemChange write FOnItemChange;
  end;

  TDappledShape = class(TShape)
  private
    FSpots: TSpotCollection;
    procedure SetSpots(const Value: TSpotCollection);
  protected
    procedure Paint; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Spots: TSpotCollection read FSpots write SetSpots;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Samples', [TDappledShape]);
end;

{ TSpot }

constructor TSpot.Create(Collection: TCollection);
begin
  inherited Create(Collection);
  FCenterX := 3;
  FCenterY := 3;
  FColor := clBlack
end;

procedure TSpot.SetCenterX(const Value: integer);
begin
  if FCenterX <> Value
     then begin
            FCenterX := Value;
            Changed(False)
          end
end;

procedure TSpot.SetCenterY(const Value: integer);
begin
  if FCenterY <> Value
     then begin
            FCenterY := Value;
            Changed(False)
          end
end;

procedure TSpot.SetColor(const Value: TColor);
begin
  if FColor <> Value
     then begin
            FColor := Value;
            Changed(False)
          end
end;

{ TSpotCollection }

function TSpotCollection.Add: TSpot;
begin
  Result := TSpot(inherited Add)
end;

constructor TSpotCollection.Create(DappledShape: TDappledShape);
begin
  inherited Create(TSpot);
  FDappledShape := DappledShape
end;

procedure TSpotCollection.DoItemChange(Item: TCollectionItem);
begin
  if Assigned(FOnItemChange) then FOnItemChange(Item)
end;

function TSpotCollection.GetItem(Index: Integer): TSpot;
begin
  Result := TSpot(inherited GetItem(Index))
end;

function TSpotCollection.GetOwner: TPersistent;
begin
  Result := FDappledShape
end;

procedure TSpotCollection.SetItem(Index: Integer; const Value: TSpot);
begin
  inherited SetItem(Index, Value)
end;

procedure TSpotCollection.Update(Item: TCollectionItem);
begin
  inherited Update(Item);
  FDappledShape.Invalidate;
  DoItemChange(Item)
end;

{ TDappledShape }

constructor TDappledShape.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FSpots := TSpotCollection.Create(Self)
end;

destructor TDappledShape.Destroy;
begin
  FSpots.Free;
  inherited Destroy
end;

procedure TDappledShape.Paint;
var
  SaveColor: TColor;
  SaveStyle: TBrushStyle;
  i: integer;
begin
  inherited Paint;
  SaveColor := Canvas.Brush.Color;
  SaveStyle := Canvas.Brush.Style;
  Canvas.Brush.Style := bsSolid;
  for i := 0 to FSpots.Count - 1 do
    with FSpots.Items[i] do
      begin
        Canvas.Brush.Color := Color;
        Canvas.Ellipse(CenterX - 3, CenterY - 3, CenterX + 3, CenterY + 3)
      end;
  Canvas.Brush.Style := SaveStyle;
  Canvas.Brush.Color := SaveColor
end;

procedure TDappledShape.SetSpots(const Value: TSpotCollection);
begin
  FSpots.Assign(Value)
end;

end.
