DDHSEMAL.PAS

unit DdhSemaL;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics,
  Controls, Forms, Dialogs, DdhLed, ExtCtrls;

{$R *.DCR}

  type
  // States enumeration
  TSemState = (scRed, scGreen, scYellow, scOff, scPulse);

  // method pointer type for events
  TLightClickEvent = procedure (
    Sender: TObject; var Active: Boolean) of object;

  TDdhLoadedSemaphore = class (TCustomControl)
  private
    // the three semaphore lights
    fGreenL, fYellowL, fRedL: TDDHLed;

    fSemState: TSemState; // status
    fTimer: TTimer; // timer for pulse
    fInterval: Integer; // timer interval

    // light click events
    fGreenClick, fRedClick, fYellowClick:
      TLightClickEvent;

    procedure TimerOnTimer (Sender: TObject);
    procedure TurnOff;
    procedure StartPulse;
    procedure StopPulse;

    // led click response methods
    procedure fGreenLedClick (Sender: TObject);
    procedure fRedLedClick (Sender: TObject);
    procedure fYellowLedClick (Sender: TObject);
  protected
    // property access methods
    procedure SetSemState (Value: TSemState);
    procedure SetInterval (Value: Integer);
  public
    constructor Create (Owner: TComponent); override;
    destructor Destroy; override;
    procedure Paint; override;
    procedure SetBounds (ALeft, ATop,
      AWidth, AHeight : Integer); override;
    procedure Loaded; override;
  published
    // new properties
    property SemState: TSemState
      read fSemState write SetSemState default scOff;
    property Interval: Integer
      read fInterval write SetInterval default 500;

    // inherited properties with defaults
    property Width default 30;
    property Height default 90;

    // custom events
    property GreenClick: TLightClickEvent
      read fGreenClick write fGreenClick;
    property RedClick: TLightClickEvent
      read fRedClick write fRedClick;
    property YellowClick: TLightClickEvent
      read fYellowClick write fYellowClick;
  end;

procedure Register;

implementation

constructor TDdhLoadedSemaphore.Create (Owner: TComponent);
begin
  inherited Create (Owner);

  // create the leds and set their color
  fGreenL := TDDHLed.Create (self);
  fGreenL.Parent := self;
  fGreenL.Color := clLime; // light green
  fGreenL.OnClick := fGreenLedClick;

  fYellowL := TDDHLed.Create (self);
  fYellowL.Parent := self;
  fYellowL.Color := clYellow;
  fYellowL.OnClick := fYellowLedClick;

  fRedL := TDDHLed.Create (self);
  fRedL.Parent := self;
  fRedL.Color := clRed;
  fRedL.OnClick := fRedLedClick;

  // set default values
  SetBounds (Left, Top, 30, 90);
  fSemState := scOff;
  TurnOff;
  fInterval := 500;
end;

procedure TDdhLoadedSemaphore.Paint;
var
  LedSize: Integer;
begin
  // compute the actual size
  // of the semaphore image
  if Width * 3 > Height then
    LedSize := Height div 3
  else
    LedSize := Width;

  // draw the background
  Canvas.Brush.Color := clBlack;
  Canvas.FillRect (Rect (0, 0,
    LedSize, LedSize * 3));
end;

procedure TDdhLoadedSemaphore.SetBounds (
  ALeft, ATop, AWidth, AHeight : Integer);
var
  LedSize: Integer;
begin
  // set a minimum size
  if AWidth < 20 then
    AWidth := 20;
  if AHeight < 60 then
    AHeight := 60;

  // compute the actual size
  // of the semaphore image
  if AWidth * 3 > AHeight then
    LedSize := AHeight div 3
  else
    LedSize := AWidth;

  // set component size
  if not (csReading in ComponentState) then
    inherited SetBounds (ALeft, ATop,
      LedSize, LedSize * 3)
  else
    inherited SetBounds (ALeft, ATop,
      AWidth, AHeight);

  // set the led position and size
  LedSize := LedSize - 2;
  fRedL.SetBounds (1, 1,
    LedSize, LedSize);
  fYellowL.SetBounds (1, LedSize + 3,
    LedSize, LedSize);
  fGreenL.SetBounds (1, LedSize * 2 + 5,
    LedSize, LedSize);
end;

procedure TDdhLoadedSemaphore.Loaded;
begin
  // double-check if size is OK
  if (Width * 3) <> Height then
    SetBounds (Left, Top, Width, Height);
end;

procedure TDdhLoadedSemaphore.SetSemState (Value: TSemState);
begin
  if Value <> fSemState then
  begin
    TurnOff;
    if fSemState = scPulse then
      StopPulse;
    case Value of
      scRed: fRedL.Status := lsOn;
      scGreen: fGreenL.Status := lsOn;
      scYellow: fYellowL.Status := lsOn;
      scPulse: StartPulse;
      // scOff: nothing to do
    end;
    fSemState := Value;
  end;
end;

procedure TDdhLoadedSemaphore.TurnOff;
begin
  fRedL.Status := lsOff;
  fGreenL.Status := lsOff;
  fYellowL.Status := lsOff;
end;

procedure TDdhLoadedSemaphore.StartPulse;
begin
  fTimer := TTimer.Create (self);
  fTimer.Interval := fInterval;
  fTimer.OnTimer := TimerOnTimer;
  fTimer.Enabled := True;
end;

procedure TDdhLoadedSemaphore.StopPulse;
begin
  fTimer.Enabled := False;
  fTimer.Free;
  fTimer := nil;
end;

procedure TDdhLoadedSemaphore.TimerOnTimer (Sender: TObject);
begin
  if fRedL.Status = lsOn then
    fRedL.Status := lsOff
  else
    fRedL.Status := lsOn;
end;

destructor TDdhLoadedSemaphore.Destroy;
begin
  if fSemState = scPulse then
    StopPulse;
  inherited Destroy;
end;

procedure TDdhLoadedSemaphore.SetInterval (Value: Integer);
begin
  if Value <> fInterval then
  begin
    fInterval := Value;
    if Assigned (fTimer) then
      fTimer.Interval := fInterval;
  end;
end;

// led Onclick event handlers,
// raising semaphore events

procedure TDdhLoadedSemaphore.fGreenLedClick (Sender: TObject);
var
  Status: Boolean;
begin
  if Assigned (fGreenClick) then
  begin
    Status := (fGreenL.Status = lsOn);
    fGreenClick (self, Status);
    if Status then
      SemState := scGreen;
  end;
end;

procedure TDdhLoadedSemaphore.fRedLedClick (Sender: TObject);
var
  Status: Boolean;
begin
  if Assigned (fRedClick) then
  begin
    Status := (fRedL.Status = lsOn);
    fRedClick (self, Status);
    if Status then
      SemState := scRed;
  end;
end;

procedure TDdhLoadedSemaphore.fYellowLedClick (Sender: TObject);
var
  Status: Boolean;
begin
  if Assigned (fYellowClick) then
  begin
    Status := (fYellowL.Status = lsOn);
    fYellowClick (self, Status);
    if Status then
      SemState := scYellow;
  end;
end;

procedure Register;
begin
  RegisterComponents ('DDHB', [TDdhLoadedSemaphore]);
end;

end.

Generated by PasToWeb, a tool by Marco Cantù.