unit ExtEdit;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, DsgnIntf;

type

  TIntEdit = class(TCustomEdit)
  private
    FMinValue: LongInt;
    FMaxValue: LongInt;
    FDefaultValue: LongInt;
    FIncrement: LongInt;
    function GetValue: LongInt;
    function CheckValue (NewValue: LongInt): LongInt;
    procedure SetValue (NewValue: LongInt);
    procedure SetDefaultValue (NewValue: LongInt);
    procedure SetMaxValue(NewValue: LongInt);
    procedure SetMinValue(NewValue: LongInt);
    procedure CMExit(var Message: TCMExit);   message CM_EXIT;
  protected
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property AutoSelect;
    property AutoSize;
    property Color;
    property Ctl3D;
    property DefaultValue: LongInt read FDefaultValue write SetDefaultValue;
    property DragCursor;
    property DragMode;
    property Enabled;
    property Font;
    property Increment: LongInt read FIncrement write FIncrement;
    property MaxLength;
    property MaxValue: LongInt read FMaxValue write SetMaxValue;
    property MinValue: LongInt read FMinValue write SetMinValue;
    property ParentColor;
    property ParentCtl3D;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ReadOnly;
    property ShowHint;
    property TabOrder;
    property TabStop;
    property Value: LongInt read GetValue write SetValue;
    property Visible;
    property OnChange;
    property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
  end;

  TFloatEdit = class(TCustomEdit)
  private
    FMinValue: Extended;
    FMaxValue: Extended;
    FDefaultValue: Extended;
    FIncrement: Extended;
    FIncludeBounds: Boolean;
    function GetValue: Extended;
    function CheckValue (NewValue: Extended): Extended;
    procedure SetValue (NewValue: Extended);
    procedure SetDefaultValue(NewValue: Extended);
    procedure SetMaxValue(NewValue: Extended);
    procedure SetMinValue(NewValue: Extended);
    procedure SetIncludeBounds(NewValue: Boolean);
    procedure CMExit(var Message: TCMExit);   message CM_EXIT;
  protected
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
  public
    constructor Create(AOwner: TComponent); override;
  published
    property AutoSelect;
    property AutoSize;
    property Color;
    property Ctl3D;
    property DefaultValue: Extended read FDefaultValue write SetDefaultValue;
    property DragCursor;
    property DragMode;
    property Enabled;
    property Font;
    property IncludeBounds: Boolean read FIncludeBounds write SetIncludeBounds;
    property Increment: Extended read FIncrement write FIncrement;
    property MaxLength;
    property MaxValue: Extended read FMaxValue write SetMaxValue;
    property MinValue: Extended read FMinValue write SetMinValue;
    property ParentColor;
    property ParentCtl3D;
    property ParentFont;
    property ParentShowHint;
    property PopupMenu;
    property ReadOnly;
    property ShowHint;
    property TabOrder;
    property TabStop;
    property Value: Extended read GetValue write SetValue;
    property Visible;
    property OnChange;
    property OnClick;
    property OnDblClick;
    property OnDragDrop;
    property OnDragOver;
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    property OnMouseDown;
    property OnMouseMove;
    property OnMouseUp;
  end;

procedure Register;
//=======================================================
implementation
 {$R *.DCR}

const
  sDefValueError = 'DefaultValue must be between MinValue and MaxValue';

procedure Register;
begin
  RegisterComponents('Mike', [TIntEdit,TFloatEdit]);
end;

{-------------------------- TIntEdit ------------------------ }

constructor TIntEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle - [csSetCaption];
  FMaxValue := 0;
  FMinValue := 0;
  FDefaultValue := 0;
  Text := '0';
end;


procedure TIntEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
  if Key = VK_UP then Value := Value + FIncrement
  else
    if Key = VK_DOWN then Value := Value - FIncrement
    else
    inherited KeyDown(Key, Shift);
end;


procedure TIntEdit.KeyPress(var Key: Char);
begin
  if not ( Key in ['+', '-', '0'..'9', #0..#31] ) then
  begin
    Key := #0;
    MessageBeep(0);
  end
  else inherited KeyPress(Key);
end;


function TIntEdit.GetValue: LongInt;
begin
  if Text = '' then GetValue := FDefaultValue
  else
  try
    GetValue := StrToInt(Text);
  except
    on E: Exception do
    begin
      if not ( csDesigning in ComponentState ) then SetFocus;
      raise EPropertyError.Create(E.Message);
    end;
  end;
end;

procedure TIntEdit.SetValue(NewValue: LongInt);
begin
  Text := IntToStr(CheckValue(NewValue));
end;

procedure TIntEdit.SetDefaultValue (NewValue: LongInt);
begin
  if NewValue <> FDefaultValue then
    if NewValue = CheckValue(NewValue) then FDefaultValue := NewValue
    else raise EPropertyError.Create(sDefValueError);
end;

procedure TIntEdit.SetMaxValue (NewValue: LongInt);
begin
  if FMaxValue <> NewValue then
  begin
    FMaxValue := NewValue;
    Text := IntToStr(CheckValue(Value));
    FDefaultValue := CheckValue(FDefaultValue);
  end;
end;

procedure TIntEdit.SetMinValue (NewValue: LongInt);
begin
  if FMinValue <> NewValue then
  begin
    FMinValue := NewValue;
    Text := IntToStr(CheckValue(Value));
    FDefaultValue := CheckValue(FDefaultValue);
  end;
end;

function TIntEdit.CheckValue (NewValue: LongInt): LongInt;
begin
  Result := NewValue;
  if (FMaxValue <> FMinValue) then
  begin
    if NewValue < FMinValue then
      Result := FMinValue
    else
    if NewValue > FMaxValue then
      Result := FMaxValue;
  end;
end;


procedure TIntEdit.CMExit(var Message: TCMExit);
begin
  inherited;
  if Text <> '' then
  try
    SetValue(CheckValue(Value));
  except
    on E: Exception do
    begin
      SetFocus;
      raise EPropertyError.Create(E.Message);
    end;
  end;
end;

{----------------------- TFloatEdit -----------------------}

constructor TFloatEdit.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle - [csSetCaption];
  FMaxValue := 0;
  FMinValue := 0;
  FDefaultValue := 0;
  FIncludeBounds := True;
  Text := '0';
end;

procedure TFloatEdit.KeyDown(var Key: Word; Shift: TShiftState);
begin
  if Key = VK_UP then Value := Value + FIncrement
  else
    if Key = VK_DOWN then Value := Value - FIncrement
    else inherited KeyDown(Key, Shift);
end;


procedure TFloatEdit.KeyPress(var Key: Char);
begin
  if not ( Key in [DecimalSeparator, '+', '-', '0'..'9', #0..#31] ) then
  begin
    Key := #0;
    MessageBeep($FFFF)
  end
  else inherited KeyPress(Key);
end;


function TFloatEdit.GetValue: Extended;
begin
  if Text = '' then GetValue := FDefaultValue
  else
  try
    GetValue := StrToFloat(Text);
  except
    on E: Exception do
    begin
      if not ( csDesigning in ComponentState ) then SetFocus;
      raise EPropertyError.Create(E.Message);
    end;
  end;
end;

procedure TFloatEdit.SetValue(NewValue: Extended);
begin
  Text := FloatToStr(CheckValue(NewValue));
end;

procedure TFloatEdit.SetDefaultValue(NewValue: Extended);
begin
  if NewValue <> FDefaultValue  then
    if NewValue = CheckValue(NewValue) then FDefaultValue := NewValue
    else raise EPropertyError.Create(sDefValueError);
end;

procedure TFloatEdit.SetMaxValue (NewValue: Extended);
begin
  if FMaxValue <> NewValue then
  begin
    FMaxValue := NewValue;
    SetValue(CheckValue(Value));
    FDefaultValue := CheckValue(FDefaultValue);
  end;
end;

procedure TFloatEdit.SetMinValue (NewValue: Extended);
begin
  if FMinValue <> NewValue then
  begin
    FMinValue := NewValue;
    SetValue(CheckValue(Value));
    FDefaultValue := CheckValue(FDefaultValue);
  end;
end;

function TFloatEdit.CheckValue (NewValue: Extended): Extended;
begin
  Result := NewValue;
  if (FMaxValue <> FMinValue) then
  if FIncludeBounds then
  begin
    if NewValue < FMinValue then Result := FMinValue
    else
      if NewValue > FMaxValue then Result := FMaxValue;
  end
  else
  if ( NewValue <= FMinValue ) or ( NewValue >= FMaxValue ) then
    Result := FMinValue + ( FMaxValue - FMinValue ) / 2;
end;

procedure TFloatEdit.SetIncludeBounds(NewValue: Boolean);
begin
  if NewValue <> FIncludeBounds then
  begin
    FIncludeBounds := NewValue;
    SetValue(CheckValue(Value));
  end;
end;


procedure TFloatEdit.CMExit(var Message: TCMExit);
begin
  inherited;
  if Text <> '' then
  try
    SetValue(CheckValue(Value));
  except
    on E: Exception do
    begin
      SetFocus;
      raise EPropertyError.Create(E.Message);
    end;
  end;
end;

end.
