unit CalcEdit;

interface

uses
  Windows, Messages, SysUtils, Classes, Controls, StdCtrls, Buttons, CalcFrm;

type
  TCalcEdit = class(TEdit)
  private
    { Private declarations }
    FAlignment: TAlignment;
    FButton: TSpeedButton;
    FCalcAutoSize: Boolean;
    function GetValue: Double;
    procedure SetValue(const aValue: Double);
    procedure SetAlignment(const Value: TAlignment);
  protected
    { Protected declarations }
    procedure ButtonClick(Sender: TObject);
    procedure CreateParams(var Params: TCreateParams); override;
    procedure WMSIZE(var Msg: TWMSize); message WM_SIZE;
  public
    { Public declarations }
    constructor Create(aOwner: TComponent); override;
    destructor Destroy; override;
  published
    { Published declarations }
    property Alignment: TAlignment read FAlignment write SetAlignment;
    property CalcAutoSize: Boolean read FCalcAutoSize write FCalcAutoSize;
    property Value: Double read GetValue write SetValue;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents('Additional', [TCalcEdit]);
end;

{ TCalcEdit }

procedure TCalcEdit.ButtonClick(Sender: TObject);
var
  frmCalc: TfrmCalc;
  P: TPoint;
  OldVal: Double;
  nWidth,nHeight: Integer;
begin
//  if csDesigning in ComponentState then Exit;
  if (Value = 0) and (Text <> '') and (Text <> '0') then Exit;
  if Text = '' then Text := '0';
  frmCalc := TfrmCalc.Create(nil);
  frmCalc.ValueTxt.Text := FloatToStr(Value);
  P := Point(Width,Height);
  P := ClientToScreen(P);
  frmCalc.Top := P.Y;
  frmCalc.Left := P.X;
  frmCalc.ValueTxt := Self;
  OldVal := Value;
  if FCalcAutoSize then
  begin //считаем новый размер
    nHeight := (frmCalc.Height*Width) div frmCalc.Width;
    nWidth := Width;

    if nWidth > 250 then //максимальный размер
    begin
      nHeight := (frmCalc.Height*250) div frmCalc.Width;
      nWidth := 250;
    end;

    if nWidth < 150 then //минимальный размер
    begin
      nHeight := (frmCalc.Height*150) div frmCalc.Width;
      nWidth := 150;
    end;

    frmCalc.Width := nWidth;
    frmCalc.Height := nHeight;
  end;

  frmCalc.Left := frmCalc.Left-frmCalc.Width;
  if frmCalc.ShowModal <> mrOK then Value := OldVal;
  frmCalc.Free;
end;

constructor TCalcEdit.Create(aOwner: TComponent);
begin
  inherited;
  FButton := TSpeedButton.Create(nil);
  FButton.Parent := Self;
  FButton.Top := 0;
  FButton.OnClick := ButtonClick;
  FButton.Caption := '...';
  FButton.Cursor := crArrow;
  Alignment := taRightJustify;
  Value := 0;
  CalcAutoSize := True;
end;

procedure TCalcEdit.CreateParams(var Params: TCreateParams);
const
  Alignments: array [TAlignment] of DWORD = (ES_LEFT, ES_RIGHT, ES_CENTER);
begin
  inherited;
  Params.Style := Params.Style or Alignments[FAlignment];
end;

destructor TCalcEdit.Destroy;
begin
  FButton.Free;
  SetLength(Stack,0);
  inherited;
end;

function TCalcEdit.GetValue: Double;
begin
  try
    Result := StrToFloat(Text);
  except
    Result := 0;
  end;
end;

procedure TCalcEdit.SetAlignment(const Value: TAlignment);
begin
  if Value <> FAlignment then
  begin
    FAlignment := Value;
    RecreateWnd;
  end;
end;

procedure TCalcEdit.SetValue(const aValue: Double);
begin
  Text := FloatToStr(aValue);
  Invalidate;
end;

procedure TCalcEdit.WMSIZE(var Msg: TWMSize);
begin
  inherited;
  FButton.Height := ClientHeight;
  FButton.Width := ClientHeight;
  FButton.Left := ClientWidth - ClientHeight;
  //чтобы область под кнопкой не использовалась для ввода
  PostMessage(Handle,EM_SETMARGINS,EC_RIGHTMARGIN,(FButton.Width shl 16));
end;

end.
