fcCalculator.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:69k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. unit fcCalculator;
  2. {
  3. //
  4. // Components : TfcCalculator
  5. //
  6. // Copyright (c) 2001 by Woll2Woll Software
  7. //
  8. // Changes:
  9. // 12/12/2001-Fixed bug with button remaining down when shift op happens sometimes.
  10. // 3/1/2002-PYW-Added support for TDBCtrlGrid.
  11. // 3/1/2002-PYW-Added code to handle very large numbers with Exponential notation.
  12. // 3/1/2002-PYW-Use new function to handle num pad keys in windows 98.
  13. }
  14. //Change from TBitBtn to TSpeedButton and remove tabstops from other controls.
  15. //Replace other controls with TLabel and TBevels and TShape.
  16. //Calculator when hitting 3*3**** should not keep multiplying itself.
  17. //Add custom button capability.
  18. //Add OnDrawCalcButton to allow custom button overriding.
  19. interface
  20. uses
  21.   Windows, messages, Sysutils, Forms, Classes, Controls, StdCtrls, extctrls, ComCtrls, Graphics, Buttons, fccombo, fcframe,
  22.   fccommon,dialogs;
  23. type
  24.   TfcCalcButtonType = (btNone,bt0, bt1, bt2, bt3, bt4, bt5, bt6, bt7,
  25.     bt8, bt9, btDecimal, btPlusMinus, btMultiply, btDivide,
  26.     btAdd, btSubtract, btEquals, btSqrt, btPercent, btInverse,
  27.     btBackspace, btClear, btClearAll, btMRecall, btMStore, btMClear,
  28.     btMAdd);
  29.   TfcCalculator=class;
  30.   TfcSetButtonAttributesEvent = procedure (Calc: TfcCalculator;
  31.     var AType:TfcCalcButtonType;
  32.     var ACaption:String;
  33.     var AFontColor:TColor;
  34.     var AButtonColor:TColor;
  35.     var AHint:String) of object;
  36.   TCalcState = (csNone, csAdd, csSubtract, csMultiply, csDivide);
  37.   TfcCalcOption = (cboHotTrackButtons, cboFlatButtons, cboHideBorder, cboHideEditor,
  38.      cboShowStatus, cboHideMemory, cboSelectOnEquals, cboShowDecimal, cboSimpleCalc,
  39.      cboFlatDrawStyle, cboRoundedButtons, cboDigitGrouping, cboCloseOnEquals);
  40.   TfcCalcOptions = set of TfcCalcOption;
  41.   TfcCalcBitmapDrawStyle = (cbdStretch, cbdTile, cbdTopLeft, cbdCenter);
  42.   TfcCalcBevel = class(TBevel)
  43.   public
  44.     FColor:TColor;
  45.   protected
  46.     procedure Paint; override;
  47.   end;
  48.   TfcCalcLabel = class(TLabel)
  49.   private
  50.     FCalc:TfcCalculator;
  51.     procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
  52.     procedure WMRButtonUp(var Message: TWMRButtonUp); message WM_RBUTTONUP;
  53.   public
  54.     constructor Create(AOwner: TComponent); override;
  55.   end;
  56.   TfcCalcStatusLabel = class(TLabel)
  57.     procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  58.   end;
  59.   TfcCalcButton = class(TSpeedButton)
  60.   private
  61.     FDrawKeyDown:Boolean;
  62.     FCalc:TfcCalculator;
  63.     ButtonColor:TColor;
  64.     ButtonFontColor:TColor;
  65. //    FCalcOptions: TfcCalcOptions;
  66.     FTransparent:Boolean;
  67.     FBtnType:TfcCalcButtonType;
  68.     procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
  69.     procedure CMMouseEnter(var Message: TMessage); message CM_MOUSEENTER;
  70.     procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
  71.     procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBkgnd;
  72.     procedure WMRButtonDown(var Message: TWMRButtonDown); message WM_RBUTTONDOWN;
  73.     procedure WMRButtonUp(var Message: TWMRButtonUp); message WM_RBUTTONUP;
  74.     function GetCalcOptions: TfcCalcOptions;
  75.   protected
  76.     procedure Paint; override;
  77.     property DrawKeyDown:boolean read FDrawKeyDown write FDrawKeyDown;
  78.   public
  79.     property CalcOptions: TfcCalcOptions read GetCalcOptions;
  80.     constructor Create(AOwner: TComponent); override;
  81.     destructor Destroy; override;
  82.   end;
  83.   TButtonRecord = record
  84.     Top: Integer;
  85.     Left: Integer;
  86.     Width: Integer;
  87.     Height: Integer;
  88.     Caption: string;
  89.     Hint:string;
  90.     Color: TColor;
  91.     ButtonColor: TColor;
  92.     BtnType:TfcCalcButtonType;
  93.   end;
  94.   TfcCalculator = class(TCustomPanel)
  95.    private
  96.     FResultEdit: TEdit; // Need to make this right-aligned editing still
  97.     FCalcEdit:TCustomEdit;
  98.     FStatusLabel: TLabel;
  99.     FMemoryValue: Double;
  100.     FLastValue: Double;
  101.     FCurrentValue: Double;
  102.     FResultValue: Double;
  103.     FLastOperand: Double;
  104.     FLastOP:TfcCalcButtonType;
  105.     FNextToLastOp:TfcCalcButtonType;
  106.     FDecimalEntered:Boolean;
  107.     FClearOnNextKey:Boolean;
  108.     FLastOperatorEquals:Boolean;
  109.     FLastStatus:String;
  110.     FClearStatus:Boolean;
  111.     FDecimalPlaces:integer;
  112.     FLastButtonType:TfcCalcButtonType;
  113.     F3D:Boolean;
  114.     FStatusBevel: TfcCalcBevel;
  115.     FMemoryBevel: TfcCalcBevel;
  116.     FMemoryStatus: TfcCalcLabel;
  117.     FPanelColor:TColor;
  118.     FBackSpaceValid: Boolean;
  119.     FOptions: TfcCalcOptions;
  120.     FBackgroundBitmap: TPicture;
  121.     FPaintBitmap: TBitmap;
  122.     FOnSetButtonAttributes: TfcSetButtonAttributesEvent;
  123.     OldBoundsRect: TRect;
  124.     FMargin:integer;
  125.     FBackgroundBitmapDrawStyle: TfcCalcBitmapDrawStyle;
  126.     FCalcPrecision:Integer;
  127.     InitBitmapsFlag: boolean;
  128.     OpPressedWithShiftFlag: boolean;
  129.     procedure SetOptions(Value: TfcCalcOptions);
  130.     procedure SetPanelColor(Value: TColor);
  131.     procedure SetMargin(Value: Integer);
  132.     procedure SetBackgroundBitmapDrawStyle(Value: TfcCalcBitmapDrawStyle);
  133.     procedure SetBackgroundBitmap(Value: TPicture);
  134.     procedure SetBorder3D(const Value:Boolean);
  135.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  136.     procedure WMEraseBkgnd(var Message: TWmEraseBkgnd); message WM_ERASEBkgnd;
  137.    protected
  138.      Btns: array [TfcCalcButtonType] of TButtonRecord;
  139.      procedure CalcButtons; virtual;
  140.      procedure Compute(Sender: TObject); virtual;
  141.      function GetText : string; virtual;
  142.      procedure SetText(const Value : string); virtual;
  143.      function GetCalcEdit : TCustomEdit; virtual;
  144.      procedure SetCalcEdit(const Value : TCustomEdit); virtual;
  145.      function ButtonRecord(btnType:TfcCalcButtonType;
  146.         aTop, aLeft, aWidth, aHeight: Integer; aCaption: string;
  147.         aFontColor: TColor = clBlack; aHint:string = ''): TButtonRecord; virtual;
  148.      procedure Loaded; override;
  149.      property CalcPrecision:Integer read FCalcPrecision write FCalcPrecision;
  150.    public
  151.      constructor Create(AOwner: TComponent); override;
  152.      destructor Destroy; override;
  153.      procedure FullRepaint; virtual;
  154.      procedure RefreshSummary; virtual;
  155.      procedure Paint; override;
  156.      function IsBinaryOperator(ButtonType:TfcCalcButtonType):boolean; virtual;
  157.      procedure Reset; virtual;
  158.      function OpToChar(aOp:TfcCalcButtonType):Char; virtual;
  159.      function CharToButton(c:Char;Ctrl:Boolean):TfcCalcButton;
  160.      function OpToButton(op:TfcCalcButtonType):TfcCalcButton;
  161.      function CharToOp(c:Char;Ctrl:Boolean):TfcCalcButtonType; virtual;
  162.      procedure ResultKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); virtual;
  163.      procedure ResultKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); virtual;
  164.      procedure DoCalc(ButtonType:TfcCalcButtonType); virtual;
  165.      procedure DoCreateButton(Calc: TfcCalculator;var AType:TfcCalcButtonType;var ACaption:String;
  166.        var AFontColor:TColor; var AButtonColor:TColor; var AHint:String); virtual;
  167.      property Value : Double read FCurrentValue write FCurrentValue;
  168.      property PaintBitmap: TBitmap read FPaintBitmap write FPaintBitmap;
  169.      property ResultEdit: TEdit read FResultEdit write FResultEdit;
  170.      property StatusLabel: TLabel read FStatusLabel write FStatusLabel;
  171.      property MemoryStatus:TfcCalcLabel read FMemoryStatus write FMemoryStatus;
  172.      property MemoryValue:Double read FMemoryValue write FMemoryValue;
  173.      property CalcEdit:TCustomEdit read GetCalcEdit write SetCalcEdit;
  174.      property LastOp:TfcCalcButtonType read FLastOp;
  175.      property LastOperatorEquals:Boolean read FLastOperatorEquals;
  176.    published
  177.      property Align;
  178.      property BackgroundBitmap: TPicture read FBackgroundBitmap write SetBackgroundBitmap;
  179.      property BackgroundBitmapDrawStyle: TfcCalcBitmapDrawStyle read FBackgroundBitmapDrawStyle write SetBackgroundBitmapDrawStyle;
  180.      property Border3D: Boolean read F3D write SetBorder3D default False;
  181.      property ButtonMargin: integer read FMargin write SetMargin default 3;
  182.      property FixedDecimalPlaces:integer read FDecimalPlaces write FDecimalPlaces default -1;
  183.      property Font;
  184.      property Options: TfcCalcOptions read FOptions write SetOptions default [];
  185.      property PanelColor: TColor read FPanelColor write SetPanelColor default clBtnFace;
  186.      property Text : string read GetText write SetText;
  187.      property OnSetButtonAttributes: TfcSetButtonAttributesEvent read FOnSetButtonAttributes write FOnSetButtonAttributes;
  188.      property Visible;
  189.    end;
  190. //procedure Register;
  191. implementation
  192. type
  193.   TRightEdit = class (TEdit)
  194.   protected
  195.     procedure CreateParams(var Params: TCreateParams); override;
  196.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  197.   end;
  198. procedure TRightEdit.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
  199. begin
  200.   inherited;
  201.   Windows.HideCaret(self.handle);
  202. end;
  203. procedure TRightEdit.CreateParams(var Params: TCreateParams);
  204. begin
  205.    inherited CreateParams(Params);
  206.    Params.ExStyle := Params.ExStyle or WS_EX_RIGHT
  207. end;
  208. procedure GetColorByteValues(AColor: TColor; var Reserved, Blue, Green, Red: Byte);
  209.   var WinColor: COLORREF;
  210. begin
  211.   WinColor := ColorToRGB(AColor);
  212.   Reserved := ($FF000000 and WinColor) Shr 24;
  213.   Blue := ($00FF0000 and WinColor) Shr 16;
  214.   Green := ($0000FF00 and WinColor) Shr 8;
  215.   Red := ($000000FF and WinColor);
  216. end;
  217. function changecolor(acolor:TCOlor;brighten:boolean):TColor;
  218. var  red,green,blue,dummy:Byte;
  219.      dr,dg,db:integer;
  220. begin
  221.    GetColorByteValues(acolor,dummy,blue,green,red);
  222.    dr:=red;dg:=green;db:=blue;
  223.    if brighten then begin
  224.       red:=fcMin(255,dr+Trunc((255-dr)*0.50)) ;
  225.       green:=fcMin(255,dg+Trunc((255-dg)*0.50)) ;
  226.       blue:=fcMin(255,db+Trunc((255-db)*0.50)) ;
  227.    end
  228.    else begin
  229.       red:=fcMax(0,Trunc(dr*0.50)) ;
  230.       green:=fcMax(0,Trunc(dg*0.50)) ;
  231.       blue:=fcMax(0,Trunc(db*0.50)) ;
  232.    end;
  233.    result := TColor(RGB(red, Green, Blue))
  234. end;
  235. procedure Frame3D(Canvas: TCanvas; var Rect: TRect; TopColor, BottomColor: TColor;
  236.   Width: Integer);
  237.   procedure DoRect;
  238.   var
  239.     TopRight, BottomLeft: TPoint;
  240.   begin
  241.     with Canvas, Rect do
  242.     begin
  243.       TopRight.X := Right;
  244.       TopRight.Y := Top;
  245.       BottomLeft.X := Left;
  246.       BottomLeft.Y := Bottom;
  247.       Pen.Color := TopColor;
  248.       PolyLine([BottomLeft, TopLeft, TopRight]);
  249.       Pen.Color := BottomColor;
  250.       Dec(BottomLeft.X);
  251.       PolyLine([TopRight, BottomRight, BottomLeft]);
  252.     end;
  253.   end;
  254. begin
  255.   Canvas.Pen.Width := 1;
  256.   Dec(Rect.Bottom); Dec(Rect.Right);
  257.   while Width > 0 do
  258.   begin
  259.     Dec(Width);
  260.     DoRect;
  261.     InflateRect(Rect, -1, -1);
  262.   end;
  263.   Inc(Rect.Bottom); Inc(Rect.Right);
  264. end;
  265. procedure TfcCalcStatusLabel.CMTextChanged(var Message: TMessage);
  266. begin
  267.   Hint := Caption;
  268.   inherited;
  269. end;
  270. function TfcCalculator.ButtonRecord(btnType:TfcCalcButtonType;
  271.   aTop, aLeft, aWidth, aHeight: Integer; aCaption: string;
  272.   aFontColor: TColor = clBlack; aHint:string = ''): TButtonRecord;
  273. var aButtonColor:TColor;
  274. begin
  275.   aButtonColor := PanelColor;
  276.   DoCreateButton(Self, btnType, ACaption, AFontColor, AButtonColor, AHint);
  277.   Result.btnType := btnType;
  278.   Result.Top := aTop;
  279.   Result.Left := aLeft;
  280.   Result.Width := aWidth;
  281.   Result.Height := aHeight;
  282.   Result.Caption := aCaption;
  283.   Result.Color := aFontColor;
  284.   Result.Hint := aHint;
  285.   Result.ButtonColor := aButtonColor;
  286. end;
  287. {procedure TfcCalcButton.CreateParams(var Params: TCreateParams);
  288. begin
  289.   inherited CreateParams(Params);
  290. //  with Params do Style := Style or BS_OWNERDRAW;
  291. end;}
  292. { TfcCalcBevel }
  293. procedure TfcCalcBevel.Paint;
  294. var R:TRect;
  295.     BtnShadow,BtnLight:TColor;
  296. begin
  297.    R:= Rect(0,0,Width,Height);
  298.    Frame3D(Canvas, R, clBlack, clWhite, 1);
  299.    BtnShadow:= changeColor(FColor,False);
  300.    BtnLight := changeColor(FColor,True);
  301.    R:= Rect(1,1,Width-1,Height-1);
  302.    Frame3D(Canvas, R, BtnShadow, BtnLight, 1);
  303. end;
  304. { TfcCalcButton }
  305. constructor TfcCalcButton.Create(AOwner: TComponent);
  306. begin
  307.   inherited Create(AOwner);
  308.   FCalc := AOwner as TfcCalculator;
  309.   ControlStyle := ControlStyle + [csCaptureMouse, csDoubleClicks, csReflector];
  310.   //3/1/2002-PYW-Add support for TDBCtrlGrid
  311.   ControlStyle := ControlStyle + [csReplicatable];
  312.   ButtonColor := clBtnFace;
  313.   ButtonFontColor := clWindowText;
  314. end;
  315. destructor TfcCalcButton.Destroy;
  316. begin
  317.   inherited Destroy;
  318. end;
  319. procedure TfcCalcButton.WMRButtonDown(var Message: TWMRButtonDown);
  320. begin
  321.   inherited;
  322.   if FCalc.StatusLabel <> nil then
  323.      FCalc.statuslabel.Caption := Self.Hint;
  324. end;
  325. procedure TfcCalcButton.WMRButtonUp(var Message: TWMRButtonUp);
  326. begin
  327.   inherited;
  328.   FCalc.RefreshSummary;
  329. end;
  330. constructor TfcCalcLabel.Create(AOwner: TComponent);
  331. begin
  332.   inherited Create(AOwner);
  333.   FCalc := AOwner as TfcCalculator;
  334. end;
  335. procedure TfcCalcLabel.WMRButtonDown(var Message: TWMRButtonDown);
  336. begin
  337.   inherited;
  338.   if FCalc.StatusLabel <> nil then
  339.      FCalc.statuslabel.Caption := FloatToStr(FCalc.MemoryValue);
  340. end;
  341. procedure TfcCalcLabel.WMRButtonUp(var Message: TWMRButtonUp);
  342. begin
  343.   inherited;
  344.   FCalc.RefreshSummary;
  345. end;
  346. procedure TfcCalcButton.WMEraseBkgnd(var Message: TWmEraseBkgnd);
  347. begin
  348.   Message.result:= 1;
  349. end;
  350. procedure TfcCalcButton.Paint;
  351. var
  352.   IsDown: Boolean;
  353.   R: TRect;
  354.   P:TPoint;
  355.   MouseinButton:BOolean;
  356.   Btnlight,Btnshadow:TColor;
  357.   SaveFontColor,SaveBrushColor,SavePenColor:TColor;
  358.   StateFlags:integer;
  359. begin
  360.   SaveFontColor:=Canvas.Font.Color;
  361.   SaveBrushColor:=Canvas.Brush.Color;
  362.   SavePenColor:=Canvas.Pen.Color;
  363.   try
  364.      Canvas.Lock;
  365.      if (csDesigning in COmponentState) and
  366.         (csNoDesignVisible in ControlStyle) then exit;
  367.      R := ClientRect;
  368.      GetCursorPos(P);
  369.      P:=(screenToClient(p));
  370.      if PtInRect(r,p) then
  371.         MouseInButton := True
  372.      else MouseInButton := False;
  373.      IsDown := FDrawKeyDown or ((csLButtonDown in ControlState) and MouseInButton);
  374.      Canvas.Font := Self.Font;
  375.      Canvas.Pen.Color := clBlack;
  376.      Canvas.Font.Color := ButtonFontColor;
  377.      Canvas.Brush.Color := ButtonColor;
  378.      if FTransparent then begin
  379.         Canvas.CopyRect(ClientRect,(Parent as TfcCalculator).PaintBitmap.Canvas,
  380.           Rect(Left,Top,Left+WIdth,Top+Height));
  381.      end
  382.      else Canvas.FillRect(r);
  383.      if MouseInButton and (cboHotTrackButtons in CalcOptions) and
  384.         not (cboFlatButtons in CalcOptions) and not (cboFlatDrawStyle in CalcOptions) then
  385.      begin
  386.         Canvas.Pen.Color := clWindowFrame;
  387.         Canvas.Pen.Width := 1;
  388.         Canvas.Brush.Style := bsClear;
  389.         if not (cboRoundedButtons in CalcOptions) then begin
  390.            Canvas.Rectangle(R.Left, R.Top, R.Right, R.Bottom);
  391.   //       else Canvas.RoundRect(R.Left,R.Top,R.Right,R.Bottom,20,20);
  392.       { DrawFrameControl must draw within this border }
  393.        InflateRect(R, -1, -1);
  394.        end;
  395.      end;
  396.      Canvas.Pen.Color := clBtnShadow;
  397.      Canvas.Pen.Width := 1;
  398.      Canvas.Brush.Color := ButtonColor;
  399.      BTnShadow:= changeColor(ButtonColor,False);
  400.      BtnLight := changeColor(ButtonColor,True);
  401.   { DrawFrameControl does not draw a pressed button correctly }
  402.   if IsDown then
  403.   begin
  404.     if (cboFlatDrawStyle in CalcOptions) then begin
  405.       StateFlags:=DFCS_BUTTONPUSH or DFCS_PUSHED or DFCS_CHECKED;
  406.       StateFlags:= StateFlags + DFCS_FLAT;
  407.       DrawFrameControl(Canvas.Handle,R,DFC_BUTTON, StateFlags);
  408.     end
  409.     else begin
  410.       if (cboRoundedButtons in CalcOptions) then begin
  411.          if MouseInButton and (cboHotTrackButtons in CalcOptions) and not (cboFlatButtons in CalcOptions) then begin
  412.             InflateRect(R, -1, -1);
  413.             Canvas.Pen.Width := 2;
  414.          end;
  415.          Canvas.RoundRect(R.Left,R.Top,R.Right,R.Bottom,20,20);
  416.          if MouseInButton and (cboHotTrackButtons in CalcOptions) and not (cboFlatButtons in CalcOptions) then begin
  417.            Canvas.Pen.Color := clWindowFrame;
  418.            Canvas.Pen.Width := 1;
  419.            Canvas.RoundRect(R.Left,R.Top,R.Right,R.Bottom,20,20);
  420.          end;
  421.       end
  422.       else begin
  423.         Canvas.Brush.Style := bsClear;
  424.         Canvas.Rectangle(R.Left, R.Top, R.Right, R.Bottom);
  425.         Canvas.Pen.Color := BtnShadow;
  426.         Canvas.Polyline([Point(r.left,r.bottom),Point(r.left,r.top),Point(r.right,r.top)]);
  427.         Canvas.Pen.Color := clBlack;
  428.         Canvas.Polyline([Point(r.left+1,r.bottom-1),Point(r.left+1,r.top+1),Point(r.right-1,r.top+1)]);
  429.         Canvas.Pen.Color := BtnLight;
  430.         Canvas.Polyline([Point(r.left+2,r.bottom-2),Point(r.right-2,r.bottom-2),Point(r.right-2,r.top+2)]);
  431.         Canvas.Pen.Color := clWhite;
  432.         Canvas.Polyline([Point(r.left+1,r.bottom-1),Point(r.right-1,r.bottom-1),Point(r.right-1,r.top+1)]);
  433.       end;
  434.       InflateRect(R, -1, -1);
  435.     end;
  436.   end
  437.   else
  438.   begin
  439.     if not (cboFlatButtons in CalcOptions) or
  440.        (PtInRect(r,p) and ((cboHotTrackButtons in CalcOptions))) then begin
  441.       if (cboFlatDrawStyle in CalcOptions) then begin
  442.          StateFlags:=DFCS_BUTTONPUSH;
  443.          StateFlags:= StateFlags + DFCS_FLAT;
  444.          DrawFrameControl(Canvas.Handle,R,DFC_BUTTON, StateFlags);
  445.       end
  446.       else begin
  447.          Canvas.Brush.Style := bsClear;
  448.          if (cboRoundedButtons in CalcOptions) then begin
  449.            if MouseInButton and (cboHotTrackButtons in CalcOptions) and not (cboFlatButtons in CalcOptions) then begin
  450.               InflateRect(R, -1, -1);
  451.               Canvas.Pen.Width := 2;
  452.            end;
  453.            Canvas.RoundRect(R.Left,R.Top,R.Right,R.Bottom,20,20);
  454.            if MouseInButton and (cboHotTrackButtons in CalcOptions) and not (cboFlatButtons in CalcOptions) then begin
  455.              Canvas.Pen.Color := clWindowFrame;
  456.              Canvas.Pen.Width := 1;
  457.              Canvas.RoundRect(R.Left,R.Top,R.Right,R.Bottom,20,20);
  458.            end;
  459.          end
  460.          else begin
  461.            Canvas.Rectangle(R.Left, R.Top, R.Right, R.Bottom);
  462.            Canvas.Pen.Color := BtnLight;
  463.            Canvas.Polyline([Point(r.left,r.bottom),Point(r.left,r.top),Point(r.right,r.top)]);
  464.            Canvas.Pen.Color := clWhite;
  465.            Canvas.Polyline([Point(r.left+1,r.bottom-1),Point(r.left+1,r.top+1),Point(r.right-1,r.top+1)]);
  466.            Canvas.Pen.Color := BtnShadow;
  467.            Canvas.Polyline([Point(r.left+2,r.bottom-2),Point(r.right-2,r.bottom-2),Point(r.right-2,r.top+1)]);
  468.            Canvas.Pen.Color := clBlack;
  469.            Canvas.Polyline([Point(r.left+1,r.bottom-1),Point(r.right-1,r.bottom-1),Point(r.right-1,r.top)]);
  470.          end;
  471.        end;
  472.     end;
  473. //    InflateRect(R, -1, -1);
  474.   end;
  475.   if PtInRect(r,p) and False then
  476.   begin
  477.     R := ClientRect;
  478.     InflateRect(R, -1, -1);
  479.   end;
  480.   if IsDown then
  481.     OffsetRect(R, 1, 1);
  482.   Canvas.Brush.Style := bsClear;
  483.   DrawText(Canvas.Handle,PChar(Caption),length(caption),R,DT_CENTER or DT_VCENTER or DT_SINGLELINE);
  484. { if PtInRect(r,p) or False then
  485.   begin
  486.     R := ClientRect;
  487.     InflateRect(R, -4, -4);
  488.     Canvas.Pen.Color := clWindowFrame;
  489.     Canvas.Brush.Color := clBtnFace;
  490. //    DrawFocusRect(Canvas.Handle, R);
  491.   end;}
  492.   finally
  493.      Canvas.Font.COlor := SaveFontColor;
  494.      Canvas.Brush.Color := SaveBrushColor;
  495.      Canvas.Pen.COlor := SavePenColor;
  496.      Canvas.Unlock;
  497.   end;
  498. end;
  499. procedure TfcCalcButton.CMMouseEnter(var Message: TMessage);
  500. begin
  501.   inherited;
  502.   if (cboHotTrackButtons in CalcOptions) and not (cboFlatDrawStyle in CalcOptions) then
  503.      Invalidate;
  504. end;
  505. procedure TfcCalcButton.CMMouseLeave(var Message: TMessage);
  506. begin
  507.   inherited;
  508.   if (cboHotTrackButtons in CalcOptions) and not (cboFlatDrawStyle in CalcOptions) then
  509.      Invalidate;
  510. end;
  511. procedure TfcCalcButton.CMEnabledChanged(var Message: TMessage);
  512. begin
  513.   inherited;
  514.   Invalidate;
  515. end;
  516. { TfcCalculator }
  517. constructor TfcCalculator.Create(AOwner: TComponent);
  518. begin
  519.   inherited Create(AOwner);
  520.   SetBounds(0,0,250,200);
  521.   FCalcPrecision := 15;
  522.   FMemoryValue := 0;
  523.   FCurrentValue := 0;
  524.   FLastValue := 0;
  525.   Caption := '';
  526.   FDecimalPlaces := -1;
  527.   FMargin := 3;
  528.   FOptions := [];
  529. //  BorderStyle := bsRaisedPanel;
  530.   FPanelColor := clBtnFace;
  531.   FPaintBitmap:= TBitmap.create;
  532.   FBackgroundBitmap:= TPicture.create;
  533.   F3D := False;
  534.   FCalcEdit :=nil;
  535.   FLastButtonType := btNone;
  536. end;
  537. destructor TfcCalculator.Destroy;
  538. begin
  539.   inherited Destroy;
  540.   FPaintBitmap.Free;
  541.   FBackGroundBitmap.Free;
  542. end;
  543. procedure TfcCalculator.DoCreateButton(Calc: TfcCalculator;
  544.     var AType:TfcCalcButtonType;
  545.     var ACaption:String;
  546.     var AFontColor:TColor;
  547.     var AButtonColor:TColor;
  548.     var AHint:String);
  549. begin
  550.    inherited;
  551.    if Assigned(FOnSetButtonAttributes) then
  552.       FOnSetButtonAttributes(Self, AType, ACaption, AFontColor, AButtonColor, AHint);
  553. end;
  554. procedure TfcCalculator.Loaded;
  555. var i:integer;
  556. begin
  557.   inherited;
  558.   CalcButtons;
  559.   if BackGroundBitmap.Graphic.empty then begin
  560.      for i:= 0 to ControlCount-1 do begin
  561.        if COntrols[i] is TfcCalcButton then
  562.          TfcCalcButton(controls[i]).FTransparent := False;
  563.      end;
  564.   end
  565.   else begin
  566.     for i:= 0 to ControlCount-1 do begin
  567.        if COntrols[i] is TfcCalcButton then
  568.          TfcCalcButton(controls[i]).FTransparent := True;
  569.     end;
  570.     InitBitmapsFlag := True;
  571.   end;
  572. end;
  573. function TfcCalculator.CharToButton(c:Char;Ctrl:Boolean):TfcCalcButton;
  574. var i:integer;
  575. begin
  576.   result := nil;
  577.   for i:=0 to Controlcount-1 do begin
  578.     if TfcCalcButton(Controls[i]).FBtnType = CharToOp(c,ctrl) then begin
  579.        result := TfcCalcButton(Controls[i]);
  580.        break;
  581.     end;
  582.   end;
  583. end;
  584. function TfcCalculator.OpToButton(op:TfcCalcButtonType):TfcCalcButton;
  585. var i:integer;
  586. begin
  587.   result := nil;
  588.   for i:=0 to Controlcount-1 do begin
  589.     if TfcCalcButton(Controls[i]).FBtnType = op then begin
  590.        result := TfcCalcButton(Controls[i]);
  591.        break;
  592.     end;
  593.   end;
  594. end;
  595. function TfcCalculator.CharToOp(c:Char;Ctrl:Boolean):TfcCalcButtonType;
  596. begin
  597.   Result := btNone;
  598.   case c of
  599.       '0':Result :=bt0;
  600.       '1':Result :=bt1;
  601.       '2':Result :=bt2;
  602.       '3':Result :=bt3;
  603.       '4':Result :=bt4;
  604.       '5':Result :=bt5;
  605.       '6':Result :=bt6;
  606.       '7':Result :=bt7;
  607.       '8':Result :=bt8;
  608.       '9':Result :=bt9;
  609.       ',','.':Result:=btDecimal;
  610.       '_':Result := btPlusMinus;
  611.       '*':Result := btMultiply;
  612.       '/':Result := btDivide;
  613.       '+':Result := btAdd;
  614.       '-':Result := btSubtract;
  615.       '=':Result := btEquals;
  616.       '@':Result := btSqrt;
  617.       '%':Result := btPercent;
  618.       'r','R': if not Ctrl then Result := btInverse
  619.            else Result := btMRecall;
  620.       'c','C': if not Ctrl then Result := btClear
  621.            else Result := btMClear;
  622.       'e','E': Result := btClearAll;
  623.       'm','M': if Ctrl then Result := btMStore;
  624.       'p','P': if Ctrl then Result := btMAdd;
  625.       'b','B': Result := btBackSpace;
  626.     end;
  627. end;
  628. procedure TfcCalculator.ResultKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
  629. var c:Char;
  630.     fb:TfcCalcButton;
  631. begin
  632.   if Key=vk_Return then c:='='
  633.   else if Key=vk_Delete then c:='c'
  634.   else if Key=vk_Back then c:='b'
  635.   else if Key=vk_Escape then c:='e'
  636.   else begin
  637.     // Code := MapVirtualKey(Key, 2);
  638.     // c:=char(Code);
  639.     // 3/1/2002-PYW-Use new function to handle num pad keys in windows 98.
  640.     c:=fcMessageCodeToChar(key);
  641.     if (ssShift in Shift) or OpPressedWithShiftFlag then begin
  642.        if c in ['=', '2', '5', '8', '-'] then
  643.           OpPressedWithShiftFlag := False;
  644.        case c of
  645.        '=':c:='+';
  646.        '2':c:='@';
  647.        '5':c:='%';
  648.        '8':c:='*';
  649.        '-':c:='_';
  650.        end;
  651.     end;
  652.   end;
  653.   fb:= CharToButton(c,ssctrl in shift);
  654.   if fb<>nil then begin
  655.     fb.DrawKeyDown := False;
  656.     fb.invalidate;
  657.   end;
  658.   inherited;
  659. end;
  660. procedure TfcCalculator.ResultKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  661. var c:Char;
  662.     fb:TfcCalcButton;
  663. begin
  664.   if {(OpPressedWithShiftFlag) or }(Key=16) then begin
  665.     inherited;
  666.     exit;
  667.   end;
  668.   if Key=vk_Return then c:='='
  669.   else if Key=vk_Delete then c:='c'
  670.   else if Key=vk_Back then c:='b'
  671.   else if Key=vk_Escape then c:='e'
  672.   else begin
  673.   //  Code := MapVirtualKey(Key, 2);
  674.   //  c:=char(Code);
  675.     //3/1/2002-PYW-Use new function to handle num pad keys in windows 98.
  676.     c:=fcMessageCodeToChar(key);
  677.     if (ssShift in Shift) then begin
  678.        OpPressedWithShiftFlag:= true;
  679.        case c of
  680.        '=':c:='+';
  681.        '2':c:='@';
  682.        '5':c:='%';
  683.        '8':c:='*';
  684.        '-':c:='_';
  685.        else
  686.          OpPressedWithShiftFlag := False;
  687.        end;
  688.     end;
  689.   end;
  690.   fb:= CharToButton(c,ssctrl in shift);
  691.   if fb<>nil then begin
  692.     fb.DrawKeyDown := True;
  693.     fb.invalidate;
  694.   end;
  695.   DoCalc(CharToOp(c,(ssCtrl in Shift)));
  696.   inherited;
  697.   CalcEdit.SelStart := Length(CalcEdit.Text);
  698. end;
  699. function TfcCalculator.OpToChar(aOp:TfcCalcButtonType):Char;
  700. begin
  701.   Result := ' ';
  702.     case aOP of
  703.         btNone : Result := ' ';
  704.         bt0 : Result := '0';
  705.         bt1 : Result := '1';
  706.         bt2 : Result := '2';
  707.         bt3 : Result := '3';
  708.         bt4 : Result := '4';
  709.         bt5 : Result := '5';
  710.         bt6 : Result := '6';
  711.         bt7 : Result := '7';
  712.         bt8 : Result := '8';
  713.         bt9 : Result := '9';
  714.         btDecimal : Result := DecimalSeparator;
  715.         btPlusMinus : Result := '_';
  716.         btMultiply: Result := '*';
  717.         btDivide: Result := '/';
  718.         btAdd: Result := '+';
  719.         btSubtract: Result := '-';
  720.         btEquals:Result :='=';
  721.         btSqrt:Result := '@';
  722.         btPercent:Result :='%';
  723.         btInverse:Result := 'i';
  724.         btBackspace:Result := 'b';
  725.         btClear :Result := 'd';
  726.         btClearAll: Result := 'e';
  727.         btMRecall: Result := 'R';
  728.         btMStore: Result := 'm';
  729.         btMClear: Result := 'c';
  730.         btMAdd: Result := 'a';
  731.     end;
  732. end;
  733. procedure TfcCalculator.WMSize(var Message: TWMSize);
  734. var NewBoundsRect: TRect;
  735.   function sameRect(rect1, rect2: TRect): boolean;
  736.   begin
  737.      result:=
  738.       (rect1.left = rect2.left) and
  739.       (rect1.right = rect2.right) and
  740.       (rect1.top = rect2.top) and
  741.       (rect1.bottom = rect2.bottom);
  742.   end;
  743. begin
  744.   inherited;
  745.   NewboundsRect:= Rect(0, 0, BoundsRect.right-BoundsRect.left, BoundsRect.bottom-BoundsRect.top);
  746.   if SameRect(OldBoundsRect, NewBoundsRect) then exit;
  747.   OldboundsRect:= NewBoundsRect;
  748.   InitBitmapsFlag:= True;
  749.   if csLoading in COmponentState then exit;
  750.   CalcButtons;
  751. end;
  752. procedure TfcCalculator.Paint;
  753. const
  754.   Alignments: array[TAlignment] of Longint = (DT_LEFT, DT_RIGHT, DT_CENTER);
  755. var NewboundsRect: TRect;
  756.     ARect: TRect;
  757.     TopColor, BottomColor: TColor;
  758.     i,j:integer;
  759.     BtnShadow,BtnLight:TColor;
  760.     procedure AdjustColors(Bevel: TPanelBevel);
  761.     begin
  762.       TopColor := clBtnHighlight;
  763.       if Bevel = bvLowered then TopColor := clBtnShadow;
  764.       BottomColor := clBtnShadow;
  765.       if Bevel = bvLowered then BottomColor := clBtnHighlight;
  766.     end;
  767. begin
  768.   if InitBitmapsFlag and ((not BackGroundBitmap.Bitmap.Empty) or (not BackGroundBitmap.Graphic.Empty)) then begin
  769.      NewboundsRect:= Rect(0, 0, BoundsRect.right-BoundsRect.left, BoundsRect.bottom-BoundsRect.top);
  770.      PaintBitmap.Width := NewBoundsRect.right;
  771.      PaintBitmap.Height:= NewBoundsRect.Bottom;
  772.      PaintBitmap.TransparentMode := tmFixed;
  773.      PaintBitmap.TransparentColor := clNone;
  774.      case BackgroundBitmapDrawStyle of
  775.         cbdTile:
  776.              begin
  777.                 with BackgroundBitmap do begin
  778.                   i := 0;
  779.                   while i < Self.Width do begin
  780.                     j := 0;
  781.                     while j < Self.Height do begin
  782.                        PaintBitmap.Canvas.Draw(i,j,Graphic);
  783.                       // r:=rect(i,j,i+Bitmap.width,j+Bitmap.height);
  784.                       // PaintBitmap.canvas.CopyRect(r,backgroundbitmap.bitmap.canvas,r);
  785.                        inc(j, Bitmap.Height);
  786.                     end;
  787.                     inc(i, Bitmap.Width);
  788.                   end;
  789.                 end
  790.              end;
  791.         cbdTopLeft:
  792.              begin
  793.                 with BackgroundBitmap do
  794.                    PaintBitmap.Canvas.Draw(0, 0, Graphic);
  795.              end;
  796.         cbdCenter:
  797.              begin
  798.                 with BackgroundBitmap do
  799.                    PaintBitmap.Canvas.Draw((self.width-Width)div 2,
  800.                                (self.Height-Height) div 2, Graphic);
  801.              end;
  802.         cbdStretch:
  803.              begin
  804.                 with BackgroundBitmap do
  805.                    PaintBitmap.Canvas.StretchDraw(Rect(0, 0, newBoundsRect.right, NewBoundsRect.bottom), Graphic);
  806.              end;
  807.    end;
  808.    InitBitmapsFlag:= False;
  809.   end;
  810.   ARect := GetClientRect;
  811.   if ((not BackGroundBitmap.Bitmap.Empty) or (not BackGroundBitmap.Graphic.Empty)) then
  812.      Canvas.CopyRect(ARect,PaintBitmap.Canvas,Rect(0,0,Width,Height))
  813.   else
  814.   begin
  815.     with Canvas do
  816.     begin
  817.       Brush.Color := PanelColor;
  818.       FillRect(ARect);
  819.     end;
  820.   end;
  821.   if cboHideBorder in Options then exit;
  822.   if Border3D then begin
  823.     BtnShadow:= changeColor(Color,False);
  824.     BtnLight := changeColor(Color,True);
  825.     Frame3D(Canvas, ARect, BtnLight, clBlack, 1);
  826.     Frame3D(Canvas, ARect, clWhite, BtnShadow, 1);
  827.   end
  828.   else begin
  829.     Frame3D(Canvas, ARect, clWhite, clBlack, 1);
  830.   end;
  831. end;
  832. procedure TfcCalculator.CalcButtons;
  833. var
  834.   j: integer;
  835.   i:TfcCalcButtonType;
  836.   BtnWidth,BtnHeight :integer;
  837.   clrbtnw,clrbtnh:integer;
  838.   numbuttonsx,numbuttonsy:integer;
  839.   row:integer;
  840.   x,y:integer;
  841.   aleft,statuspaneloffset,diff:integer;
  842.   pad,simplecalcflag:integer;
  843.   flag:boolean;
  844. begin
  845.   statuspaneloffset :=0;
  846.   numbuttonsx:=6; // Number of Columns
  847.   if cboHideMemory in Options then dec(numbuttonsx);
  848.   //Number of Rows
  849.   numbuttonsy:=5;
  850.   if not (cboHideEditor in Options) then inc(numbuttonsy);
  851.   //Add another row for space for summary status panel.
  852.   if False and (cboShowStatus in Options) then begin
  853.     inc(numbuttonsy);
  854.     statuspaneloffset :=1;
  855.   end;
  856.   if cboSimpleCalc in Options then begin
  857.      numbuttonsx:=4;
  858.   end;
  859.   if (cboSimpleCalc in Options) or (cboHideMemory in Options) then
  860.      x:= Width-ButtonMargin*(numbuttonsx-1)-(5+5)
  861.   else x:= Width-ButtonMargin*(numbuttonsx-1)-(5+5+5);
  862.   y:= Height-ButtonMargin*(numbuttonsy-1)-10;
  863.   btnWidth := x div numbuttonsx;
  864.   btnHeight := y div numbuttonsy;
  865.   if (not (cboHideMemory in Options)) and not (cboSimpleCalc in Options) then begin
  866.     if (cboHideEditor in Options) then row := 1
  867.     else row := 2;
  868.     Btns[btMClear] := ButtonRecord(btMClear,5+row*(btnheight+ButtonMargin), 5, BtnWidth, btnHeight, 'MC',clRed,'Clears any number stored in memory.'+#13#10+#13#10+'Keyboard equivalent = CTRL + L');
  869.     inc(row);
  870.     Btns[btMRecall] := ButtonRecord(btMRecall,5+row*(btnheight+ButtonMargin), 5, btnwidth, btnHeight, 'MR',clRed,'Recalls the number stored in memory.');
  871.     inc(row);
  872.     Btns[btMStore] := ButtonRecord(btMStore,5+row*(btnheight+ButtonMargin), 5, btnwidth, btnHeight, 'MS',clRed,'Stores the displayed number in memory.');
  873.     inc(row);
  874.     Btns[btMAdd] := ButtonRecord(btMAdd,5+row*(btnheight+ButtonMargin), 5, btnwidth, btnHeight, 'M+',clRed,'Adds displayed number to number in memory.');
  875.     clrbtnw := (width - 15 - btnwidth - ButtonMargin*3) div 3;
  876.     pad := ((Width-5-BtnWidth)-4*(BtnWidth+ButtonMargin)) - (Width-5-clrbtnw-2*(clrbtnw+ButtonMargin));
  877.   end
  878.   else begin
  879.     if csDesigning in ComponentState then begin
  880.         if (cboHideEditor in Options) then row := 1
  881.         else row := 2;
  882.         Btns[btMClear] := ButtonRecord(btMClear,5+row*(btnheight+ButtonMargin), 5, BtnWidth, btnHeight, 'MC',clRed,'Clears any number stored in memory.'+#13#10+#13#10+'Keyboard equivalent = CTRL + L');
  883.         inc(row);
  884.         Btns[btMRecall] := ButtonRecord(btMRecall,5+row*(btnheight+ButtonMargin), 5, btnwidth, btnHeight, 'MR',clRed,'Recalls the number stored in memory.');
  885.         inc(row);
  886.         Btns[btMStore] := ButtonRecord(btMStore,5+row*(btnheight+ButtonMargin), 5, btnwidth, btnHeight, 'MS',clRed,'Stores the displayed number in memory.');
  887.         inc(row);
  888.         Btns[btMAdd] := ButtonRecord(btMAdd,5+row*(btnheight+ButtonMargin), 5, btnwidth, btnHeight, 'M+',clRed,'Adds displayed number to number in memory.');
  889.     end;
  890.     clrbtnw := (width - ButtonMargin*3) div 3;
  891.     pad := 5;
  892.   end;
  893.   if cboHideEditor in Options then clrbtnh:=5
  894.   else clrbtnh:=5+btnheight+ButtonMargin;
  895.   if not (cboSimpleCalc in Options) then begin
  896.     diff := abs((Width-5-clrbtnw-2*(clrbtnw+ButtonMargin))-5);
  897.     if (cboHideMemory in Options) then
  898.        Btns[btBackspace] := ButtonRecord(btBackSpace,clrbtnh,5, clrbtnw-diff, btnHeight, 'Back',clRed,'Deletes last digit of displayed number.')
  899.     else Btns[btBackspace] := ButtonRecord(btBackSpace,clrbtnh,Width-5-clrbtnw-2*(clrbtnw+ButtonMargin), clrbtnw, btnHeight, 'Back',clRed,'Deletes last digit of displayed number.');
  900.     Btns[btClear] := ButtonRecord(btClear,clrbtnh, Width-5-(clrbtnw+ButtonMargin)-clrbtnw, clrbtnw, btnHeight, 'CE', clRed,'Clears displayed number.');
  901.     Btns[btClearAll] := ButtonRecord(btClearAll,clrbtnh, Width-5-clrbtnw, clrbtnw, btnHeight, 'C', clRed,'Clears the current calculation.');
  902.   end
  903.   else begin
  904.     Btns[btBackspace] := ButtonRecord(btBackSpace,5+(numbuttonsy-1-statuspaneloffset)*(btnheight+ButtonMargin),Width-5-clrbtnw-(clrbtnw+ButtonMargin), clrbtnw, btnHeight, 'Back',clRed,'Deletes last digit of displayed number.');
  905. //    Btns[btClearAll] := ButtonRecord(btClearAll,5+(numbuttonsy-1-statuspaneloffset)*(btnheight+ButtonMargin), Width-5-clrbtnw-2*(clrbtnw+ButtonMargin), clrbtnw, btnHeight, 'C', clRed,'Clears the current calculation.');
  906.     diff := abs((Width-5-clrbtnw-2*(clrbtnw+ButtonMargin))-5);
  907.     Btns[btClearAll] := ButtonRecord(btClearAll,5+(numbuttonsy-1-statuspaneloffset)*(btnheight+ButtonMargin), 5, clrbtnw-diff, btnHeight, 'C', clRed,'Clears the current calculation.');
  908.     Btns[btEquals] := ButtonRecord(btEquals,5+(numbuttonsy-1-statuspaneloffset)*(btnheight+ButtonMargin), Width-5-clrbtnw, clrbtnw, btnHeight, '=',clRed,'Performs any operation on previous numbers.');
  909.     if csDesigning in ComponentState then
  910.        Btns[btClear] := ButtonRecord(btClear,clrbtnh, Width-5-(clrbtnw+ButtonMargin)-clrbtnw, clrbtnw, btnHeight, 'CE', clRed,'Clears displayed number.');
  911.   end;
  912. //  pad := ((Width-5-BtnWidth)-4*(BtnWidth+ButtonMargin)) - (Width-5-clrbtnw-2*(clrbtnw+ButtonMargin));
  913.   if pad <= 0 then pad := 0;
  914.   if cboHideEditor in Options then row := 1
  915.   else row := 2;
  916.   simplecalcflag := 0;
  917.   if cboSimpleCalc in Options then begin
  918.     simplecalcflag := 1;
  919.     dec(row);
  920.   end;
  921. //  diff := abs((Width-5-clrbtnw-2*(clrbtnw+ButtonMargin))-5);
  922.   if (cboHideMemory in Options) or (cboSimpleCalc in Options) then aLeft := 5
  923.   else aLeft := -pad+ (Width-5-BtnWidth)-(4-simplecalcflag)*(BtnWidth+ButtonMargin);
  924.   Btns[bt7] := ButtonRecord(bt7,5+row*(btnheight+ButtonMargin),aLeft  , BtnWidth, btnHeight, '7',clBlue,'Puts this number in display.');
  925.   inc(row);
  926.   Btns[bt4] := ButtonRecord(bt4,5+row*(btnheight+ButtonMargin),aLeft   , BtnWidth, btnHeight, '4',clBlue,'Puts this number in display.');
  927.   inc(row);
  928.   Btns[bt1] := ButtonRecord(bt1,5+row*(btnheight+ButtonMargin),aLeft   , BtnWidth, btnHeight, '1',clBlue,'Puts this number in display.');
  929.   inc(row);
  930.   Btns[bt0] := ButtonRecord(bt0,5+row*(btnheight+ButtonMargin),aLeft   , BtnWidth, btnHeight, '0',clBlue,'Puts this number in display.');
  931. {
  932.   Btns[bt7] := ButtonRecord(bt7,5+row*(btnheight+ButtonMargin),-pad+ (Width-5-BtnWidth)-(4-simplecalcflag)*(BtnWidth+ButtonMargin), BtnWidth, btnHeight, '7',clBlue,'Puts this number in display.');
  933.   inc(row);
  934.   Btns[bt4] := ButtonRecord(bt4,5+row*(btnheight+ButtonMargin),-pad+ (Width-5-BtnWidth)-(4-simplecalcflag)*(BtnWidth+ButtonMargin), BtnWidth, btnHeight, '4',clBlue,'Puts this number in display.');
  935.   inc(row);
  936.   Btns[bt1] := ButtonRecord(bt1,5+row*(btnheight+ButtonMargin),-pad+ (Width-5-BtnWidth)-(4-simplecalcflag)*(BtnWidth+ButtonMargin), BtnWidth, btnHeight, '1',clBlue,'Puts this number in display.');
  937.   inc(row);
  938.   Btns[bt0] := ButtonRecord(bt0,5+row*(btnheight+ButtonMargin),-pad+ (Width-5-BtnWidth)-(4-simplecalcflag)*(BtnWidth+ButtonMargin), BtnWidth, btnHeight, '0',clBlue,'Puts this number in display.');
  939. }
  940.   if cboHideEditor in Options then row := 1
  941.   else row := 2;
  942.   if cboSimpleCalc in Options then dec(row);
  943.   if (cboHideMemory in Options) or (cboSimpleCalc in Options) then aLeft := 5+BtnWidth+ButtonMargin
  944.   else aLeft := -pad+ (Width-5-BtnWidth)-(3-simplecalcflag)*(BtnWidth+ButtonMargin);
  945.   Btns[bt8] := ButtonRecord(bt8,5+row*(btnheight+ButtonMargin),aLeft, BtnWidth, btnHeight, '8',clBlue,'Puts this number in display.');
  946.   inc(row);
  947.   Btns[bt5] := ButtonRecord(bt5,5+row*(btnheight+ButtonMargin),aLeft, BtnWidth, btnHeight, '5',clBlue,'Puts this number in display.');
  948.   inc(row);
  949.   Btns[bt2] := ButtonRecord(bt2,5+row*(btnheight+ButtonMargin),aLeft, BtnWidth, btnHeight, '2',clBlue,'Puts this number in display.');
  950.   if cboSimpleCalc in Options then begin
  951.     inc(row);
  952.     Btns[btDecimal] := ButtonRecord(btDecimal,5+row*(btnheight+ButtonMargin),aLeft, BtnWidth, btnHeight, DecimalSeparator,clBlue,'Inserts a decimal point.');
  953.   end
  954.   else begin
  955.     inc(row);
  956.     Btns[btPlusMinus] := ButtonRecord(btPlusMinus,5+row*(btnheight+ButtonMargin),aLeft, BtnWidth, btnHeight, '+/-',clBlue,'Changes sign of displayed number.');
  957.   end;
  958.   if cboHideEditor in Options then row := 1
  959.   else row := 2;
  960.   if cboSimpleCalc in Options then dec(row);
  961.   if (cboHideMemory in Options) or (cboSimpleCalc in Options) then aLeft := 5+2*(BtnWidth+ButtonMargin)
  962.   else aLeft := -pad+ (Width-5-BtnWidth)-(2-simplecalcflag)*(BtnWidth+ButtonMargin);
  963.   Btns[bt9] := ButtonRecord(bt9,5+row*(btnheight+ButtonMargin),aLeft, BtnWidth, btnHeight, '9',clBlue,'Puts this number in display.');
  964.   inc(row);
  965.   Btns[bt6] := ButtonRecord(bt6,5+row*(btnheight+ButtonMargin),aLeft, BtnWidth, btnHeight, '6',clBlue,'Puts this number in display.');
  966.   inc(row);
  967.   Btns[bt3] := ButtonRecord(bt3,5+row*(btnheight+ButtonMargin),aLeft, BtnWidth, btnHeight, '3',clBlue,'Puts this number in display.');
  968.   if cboSimpleCalc in Options then begin
  969.     inc(row);
  970.     Btns[btPlusMinus] := ButtonRecord(btPlusMinus,5+row*(btnheight+ButtonMargin),aLeft, BtnWidth, btnHeight, '+/-',clBlue,'Changes sign of displayed number.');
  971.   end
  972.   else begin
  973.     inc(row);
  974.     Btns[btDecimal] := ButtonRecord(btDecimal,5+row*(btnheight+ButtonMargin),aLeft, BtnWidth, btnHeight, DecimalSeparator,clBlue,'Inserts a decimal point.');
  975.   end;
  976.   
  977.   if cboHideEditor in Options then row := 1
  978.   else row := 2;
  979.   if cboSimpleCalc in Options then dec(row);
  980.   Btns[btDivide] := ButtonRecord(btDivide,5+row*(btnheight+ButtonMargin), (Width-5-BtnWidth)-(1-simplecalcflag)*(BtnWidth+ButtonMargin), BtnWidth, btnHeight, '/',clRed,'Divides.');
  981.   inc(row);
  982.   Btns[btMultiply] := ButtonRecord(btMultiply,5+row*(btnheight+ButtonMargin), (Width-5-BtnWidth)-(1-simplecalcflag)*(BtnWidth+ButtonMargin), BtnWidth, btnHeight, '*',clRed,'Multiplies.');
  983.   inc(row);
  984.   Btns[btSubtract] := ButtonRecord(btSubtract,5+row*(btnheight+ButtonMargin), (Width-5-BtnWidth)-(1-simplecalcflag)*(BtnWidth+ButtonMargin), BtnWidth, btnHeight, '-',clRed,'Subtracts.');
  985.   inc(row);
  986.   Btns[btAdd] := ButtonRecord(btAdd,5+row*(btnheight+ButtonMargin), (Width-5-BtnWidth)-(1-simplecalcflag)*(BtnWidth+ButtonMargin), BtnWidth, btnHeight, '+',clRed,'Adds.');
  987.   if (csDesigning in ComponentState) or not (cboSimpleCalc in Options) then begin
  988.       if cboHideEditor in Options then row := 1
  989.       else row := 2;
  990.       Btns[btsqrt] := ButtonRecord(btsqrt,5+row*(btnheight+ButtonMargin), (Width-5-BtnWidth)-0*(BtnWidth+ButtonMargin), BtnWidth, btnHeight, 'sqrt',clBlue,'Calculates squareroot of number.');
  991.       inc(row);
  992.       Btns[btPercent] := ButtonRecord(btPercent,5+row*(btnheight+ButtonMargin), (Width-5-BtnWidth)-0*(BtnWidth+ButtonMargin), BtnWidth, btnHeight, '%',clBlue,'Calculates Percentage');
  993.       inc(row);
  994.       Btns[btInverse] := ButtonRecord(btInverse,5+row*(btnheight+ButtonMargin), (Width-5-BtnWidth)-0*(BtnWidth+ButtonMargin), BtnWidth, btnHeight, '1/x',clBlue,'Calculates the reciprocal.');
  995.       inc(row);
  996.   end;
  997.   if not (cboSimpleCalc in Options) then
  998.      Btns[btEquals] := ButtonRecord(btEquals,5+row*(btnheight+ButtonMargin), (Width-5-BtnWidth)-0*(BtnWidth+ButtonMargin), BtnWidth, btnHeight, '=',clRed,'Performs any operation on previous numbers.');
  999.   flag := False;
  1000.   for j:= 0 to ControlCount-1 do
  1001.     if COntrols[j] is TfcCalcButton then flag := True;
  1002.   if flag then begin
  1003.     for j:= 0 to ControlCount-1 do
  1004.     if COntrols[j] is TfcCalcButton then
  1005.       with  TfcCalcButton(Controls[j]) do begin
  1006.          SetBounds(Btns[fbtntype].Left, Btns[fbtntype].Top, Btns[fbtntype].Width,Btns[fbtntype].Height);
  1007.          ButtonFontColor := Btns[fbtntype].Color;
  1008.          ButtonColor := Btns[fbtntype].ButtonColor;
  1009. //         ButtonColor := PanelColor;
  1010.          Hint := Btns[fbtnType].Hint;
  1011. //         FCalcOptions := Options;
  1012.          Font.Height := self.Font.Height;
  1013.          Font.Name := self.Font.Name;
  1014.          Font.Style := self.Font.Style;
  1015.          OnClick := Compute;
  1016.          if (FBackGroundBitmap <> nil) and (FBackGroundBitmap.Graphic <> nil) and not FBackgroundbitmap.Graphic.empty then
  1017.             FTransparent := True
  1018.          else FTransparent := False;
  1019.          case TfcCalcButtonType(Tag) of
  1020.             btMRecall..btMAdd: begin
  1021.                if (cboHideMemory in Options) or (cboSimpleCalc in Options) then
  1022.                   ControlStyle := ControlStyle + [csNoDesignVisible]
  1023.                else ControlStyle := ControlStyle - [csNoDesignVisible];
  1024.             end;
  1025.             btSqrt,btPercent,btInverse,btClear:
  1026.                begin
  1027.                  if cboSimpleCalc in Options then
  1028.                     ControlStyle := ControlStyle + [csNoDesignVisible]
  1029.                  else ControlStyle := ControlStyle - [csNoDesignVisible];
  1030.                end;
  1031.          end;
  1032.       end;
  1033.   end
  1034.   else begin
  1035.     for i := Low(TfcCalcButtonType) to High(TfcCalcButtonType) do
  1036.     begin
  1037.       with TfcCalcButton.Create(Self) do begin
  1038.         Parent := Self;
  1039.         SetBounds(Btns[i].Left, Btns[i].Top, Btns[i].Width,Btns[i].Height);
  1040.         fBtnType:=Btns[i].BtnType;
  1041.         Hint := Btns[i].Hint;
  1042.         Caption := Btns[i].Caption;
  1043.         ButtonFontColor := Btns[i].Color;
  1044. //        ButtonColor := PanelColor;
  1045.         ButtonColor := Btns[i].ButtonColor;
  1046.         OnClick := Compute;
  1047. //        FCalcOptions := Options;
  1048.         Font.Height := self.Font.Height;
  1049.         Font.Name := self.Font.Name;
  1050.         Font.Style := self.Font.Style;
  1051.         if (FBackGroundBitmap <> nil) and (FBackGroundBitmap.Graphic <> nil) and not FBackgroundbitmap.Graphic.empty then
  1052.            FTransparent := True
  1053.         else FTransparent := False;
  1054.         Tag := Ord(i);
  1055.         case TfcCalcButtonType(Tag) of
  1056.             btMRecall..btMAdd: begin
  1057.                if (cboHideMemory in Options) or (cboSimpleCalc in Options) then
  1058.                   ControlStyle := ControlStyle + [csNoDesignVisible]
  1059.                else ControlStyle := ControlStyle - [csNoDesignVisible];
  1060.             end;
  1061.             btSqrt,btPercent,btInverse,btClear:
  1062.                begin
  1063.                  if cboSimpleCalc in Options then
  1064.                     ControlStyle := ControlStyle + [csNoDesignVisible]
  1065.                  else ControlStyle := ControlStyle - [csNoDesignVisible];
  1066.                end;
  1067.         end;
  1068.       end;
  1069.     end;
  1070.   end;
  1071.   if (not (cboHideMemory in Options)) and not (cboSimpleCalc in Options) then begin
  1072.     if FMemoryBevel = nil then begin
  1073.       FMemoryBevel := TfcCalcBevel.Create(Self);
  1074.       FMemoryBevel.Parent := Self;
  1075.     end;
  1076.     with FMemoryBevel do begin
  1077.       Parent := Self;
  1078.       SetBounds(5,clrBtnh+1,BtnWidth,BtnHeight-1);
  1079.       FColor := PanelColor;
  1080.     end;
  1081.     if FMemoryStatus = nil then begin
  1082.       FMemoryStatus := TfcCalcLabel.Create(Self);
  1083.       with FMemoryStatus do begin
  1084.          Parent := Self;
  1085.          Autosize := False;
  1086.          Transparent := True;
  1087.          Alignment := taCenter;
  1088.       end;
  1089.     end;
  1090.     j := clrbtnh;
  1091.     with FMemoryStatus do begin
  1092.       Font.Height := self.Font.Height;
  1093.       Font.Name := self.Font.Name;
  1094.       Font.Style := self.Font.Style;
  1095.       SetBounds(5,j+((BtnHeight-FMemoryStatus.Canvas.textheight('M'))div 2),BtnWidth,BtnHeight);
  1096.     end;
  1097.   end
  1098.   else begin
  1099.     if FMemoryBevel <> nil then begin
  1100.        FMemoryBevel.Free;
  1101.        FMemoryBevel:=nil;
  1102.     end;
  1103.   end;
  1104.   if FResultEdit = nil then begin
  1105.      FResultEdit := TRightEdit.Create(Self);
  1106.      with FResultEdit do begin
  1107.        //3/1/2002-PYW-Add support for TDBCtrlGrid     
  1108.        ControlStyle := ControlStyle + [csReplicatable];
  1109.        Parent := Self;
  1110.        Visible := not (cboHideEditor in Options);
  1111.        AutoSize := False;
  1112. //       EditAlignment := eaRightAlignEditing;
  1113.        TLabel(FResultEdit).Alignment := taRightJustify;
  1114.        Font.Height := -13;
  1115.        Font.Name := 'Arial';
  1116.        Font.Style := [];
  1117.        Text := '0';
  1118.        ReadOnly := True;
  1119.        OnKeyDown := ResultKeyDown;
  1120.        OnKeyUp := ResultKeyUp;
  1121.      end;
  1122.      if cboShowDecimal in Options then
  1123.         Windows.HideCaret(FResultEdit.handle);
  1124.   end;
  1125.   if (cboHideEditor in Options) then FResultEdit.Visible := False
  1126.   else if (csDesigning in ComponentState) then FResultEdit.Visible := True;
  1127.   if not FResultEdit.Visible and (csDesigning in ComponentState) then
  1128.      FResultEdit.SetBounds(5, 5, 0, 0)
  1129.   else FResultEdit.SetBounds(5, 5, Width-10, btnHeight);
  1130.   if False and (cboShowStatus in Options) then begin
  1131.     if (FStatusBevel = nil) then begin
  1132.        FStatusBevel := TfcCalcBevel.Create(Self);
  1133.        FStatusBevel.Parent := Self;
  1134.     end;
  1135.     if (FStatusLabel = nil) then begin
  1136.        FStatusLabel := TfcCalcStatusLabel.Create(Self);
  1137.        with FStatusLabel do begin
  1138.           Parent := Self;
  1139.           Autosize := False;
  1140.           Transparent := True;
  1141.           Alignment := taLeftJustify;
  1142.           ShowHint := True;
  1143.           Font.Height := self.Font.Height;
  1144.           Font.Name := self.Font.Name;
  1145.           Font.Style := self.Font.Style;
  1146.        end;
  1147.     end;
  1148.     FStatusBevel.SetBounds(5, Height-5-btnHeight, Width-10,btnHeight);
  1149.     FStatusLabel.SetBounds(9, Height-5-btnHeight+((BtnHeight-FStatusLabel.Canvas.textheight('M'))div 2), Width-16,btnHeight-4);
  1150.   end
  1151.   else begin
  1152.     if FStatusBevel <> nil then begin
  1153.        FStatusBevel.Visible := False;
  1154.        FStatusBevel.SetBounds(5, Height-5-FStatusBevel.height, 0,0);
  1155.        FStatusBevel.Free;
  1156.        FStatusBevel := nil;
  1157.     end;
  1158.     if FStatusLabel <> nil then begin
  1159.        FStatusLabel.Visible := False;
  1160.        FStatusLabel.SetBounds(7, Height-5-btnHeight+2,0,0);
  1161.        FStatusLabel.Free;
  1162.        FStatusLabel := nil;
  1163.     end;
  1164.   end;
  1165.   FullRepaint;
  1166. end;
  1167. procedure TfcCalculator.WMEraseBkgnd(var Message: TWmEraseBkgnd);
  1168. begin
  1169.   Message.result:= 1;
  1170. end;
  1171. Procedure TfcCalculator.Reset; {Clear everything out}
  1172. begin
  1173.     FCurrentValue := 0.0;
  1174.     CalcEdit.Text := '0';
  1175.     FResultValue:=0.0;
  1176.     if FStatusLabel <> nil then FStatusLabel.Caption:='';
  1177.     FClearOnNextKey:=false;
  1178.     FLastOp:=btNone;
  1179.     FNextToLastOp:=btNone;
  1180.     FLastStatus:='';
  1181.     FLastOperatorEquals := false;
  1182.     FLastOperand:=0.0;
  1183.     FClearStatus:=False;
  1184.     FDecimalEntered := False;
  1185.     FLastButtonType:=btNone;
  1186. end;
  1187. procedure TfcCalculator.Compute(Sender: TObject);
  1188. begin
  1189.   DoCalc(TfcCalcButtonType(TSpeedButton(Sender).Tag));
  1190. end;
  1191. type EfcCalcException = Class(Exception);
  1192. procedure TfcCalculator.DoCalc(ButtonType:TfcCalcButtonType);
  1193. const
  1194.   MemoryStoreMap: array [Boolean] of string = (' M','');
  1195. var
  1196.   Temp,teststr: string;
  1197.   TempValue: Double;
  1198.   index,digits:integer;
  1199.   selectallflag:boolean;
  1200.   function DecimalInStr(str:string): boolean;
  1201.   begin
  1202.     result := false;
  1203.     if Pos(DecimalSeparator,str)>0 then
  1204.        result := true;
  1205.   end;
  1206.   function GetFormattedtext(val:extended;showdecimal:boolean=False):string;
  1207.   var s,fmtstr:string;
  1208.       i,places:integer;
  1209.   begin
  1210.     result :='';
  1211.     if cboDigitGrouping in Options then begin
  1212.         if showdecimal and (FDecimalPlaces > -1) then begin
  1213.           places := FDecimalPlaces;
  1214.           fmtstr := '#,##0.';
  1215.           for i:=1 to places do
  1216.              fmtstr := fmtstr+'0';
  1217.           result := FormatFloat(fmtstr,Val);
  1218.         end
  1219.         // 3/1/2002-PYW-Added code to handle very large numbers with Exponential notation.
  1220.         else if (Frac(Val)=0) then begin //(Val - Trunc(Val)) = 0.0 then begin
  1221.            if (FDecimalPlaces < 0) or (not showdecimal) then
  1222.               result := FormatFloat('#,##0',Val)
  1223.            else begin
  1224.               places := FDecimalPlaces;
  1225.               fmtstr := '#,##0.';
  1226.               for i:=1 to places do
  1227.                  fmtstr := fmtstr+'0';
  1228.               result := FormatFloat(fmtstr,Val);
  1229.            end;
  1230.         end
  1231.         else begin
  1232.            // Limit to 15 significant digits
  1233.            s:= FloatToStrF(Val, ffFixed, 15, 15);
  1234.            // Now val is accurate to 15 digits precision, so now lets get it in our format
  1235.            Val:= StrtoFloat(s);
  1236.            s:= FormatFloat('#.##############', Val);
  1237.            places := length(s)-pos(DecimalSeparator,S);
  1238.            fmtstr := '#,##0.';
  1239.            for i:=1 to places do
  1240.               fmtstr := fmtstr+'0';
  1241.            result := FormatFloat(fmtstr,Val);
  1242.         end;
  1243.     end
  1244.     else begin
  1245.         if showdecimal and (FDecimalPlaces > -1) then begin
  1246.           places := FDecimalPlaces;
  1247.           fmtstr := '###0.';
  1248.           for i:=1 to places do
  1249.              fmtstr := fmtstr+'0';
  1250.           result := FormatFloat(fmtstr,Val);
  1251.         end
  1252.         // 3/1/2002-PYW-Added code to handle very large numbers with Exponential notation.
  1253.         else if (Frac(Val)=0) then begin//Val - Trunc(Val)) = 0.0 then begin
  1254.            if (FDecimalPlaces < 0) or (not showdecimal) then
  1255.               result := FormatFloat('###0',Val)
  1256.            else begin
  1257.               places := FDecimalPlaces;
  1258.               fmtstr := '###0.';
  1259.               for i:=1 to places do
  1260.                  fmtstr := fmtstr+'0';
  1261.               result := FormatFloat(fmtstr,Val);
  1262.            end;
  1263.         end
  1264.         else begin
  1265.            // Limit to 15 significant digits
  1266.            s:= FloatToStrF(Val, ffFixed, 15, 15);
  1267.            // Now val is accurate to 15 digits precision, so now lets get it in our format
  1268.            Val:= StrtoFloat(s);
  1269.            s:= FormatFloat('#.##############', Val);
  1270.            places := length(s)-pos(DecimalSeparator,S);
  1271.            fmtstr := '###0.';
  1272.            for i:=1 to places do
  1273.               fmtstr := fmtstr+'0';
  1274.            result := FormatFloat(fmtstr,Val);
  1275.         end;
  1276.     end;
  1277.   end;
  1278. begin
  1279. //  Options := Options+ [cboDigitGrouping];
  1280.   selectallflag := false;
  1281.   try
  1282.    case ButtonType of
  1283.     bt0..bt9:
  1284.       begin
  1285.         if FClearOnNextKey then begin
  1286.            if FLastOperatorEquals or FClearStatus then Reset
  1287.            else CalcEdit.Text := '0';
  1288.            FDecimalEntered := False;
  1289.         end;
  1290.         FClearOnNextKey := false;
  1291.         teststr := CalcEdit.Text;
  1292.         digits := 0;
  1293.         for index := 1 to length(teststr) do
  1294.         begin
  1295.            case teststr[index] of
  1296.            '0'..'9':inc(digits);
  1297.            end;
  1298.         end;
  1299.         if digits >= CalcPrecision then begin
  1300.           beep;
  1301.           exit;
  1302.         end;
  1303.         if (not FDecimalEntered) and //(not DecimalInStr(CalcEdit.Text)) and
  1304.           ((CalcEdit.Text = '0'+decimalseparator) or (CalcEdit.Text = '0') or (FCurrentValue = 0)) then
  1305.            CalcEdit.Text := '';
  1306.         teststr := DecimalSeparator;
  1307.         if Copy(CalcEdit.Text,Length(CalcEdit.Text),1)=teststr then
  1308.         if not FDecimalEntered then //DecimalInStr(CalcEdit.Text) then
  1309.            CalcEdit.Text := Copy(CalcEdit.Text,1,Length(CalcEdit.Text)-1);
  1310.         FBackSpaceValid := True;
  1311.         CalcEdit.Text := CalcEdit.Text + Btns[ButtonType].Caption;
  1312.         FCurrentValue := fcStrToFloat(CalcEdit.Text);
  1313.         if not (DecimalInStr(CalcEdit.Text) and (Btns[ButtonType].Caption = '0')) then
  1314.            CalcEdit.Text := GetformattedText(FCurrentValue);
  1315.         CalcEdit.SelStart := Length(CalcEdit.Text);
  1316.         if (FStatusLabel <> nil) then
  1317.            FStatusLabel.Caption:=FStatusLabel.Caption+OpToChar(ButtonType);
  1318.         FLastButtonType := ButtonType;
  1319.      end;
  1320.     btDecimal:
  1321.      begin
  1322.         if FClearOnNextKey then begin
  1323.            if FLastOperatorEquals then Reset
  1324.            else CalcEdit.Text := '0';
  1325.         end;
  1326.         FClearOnNextKey := false;
  1327.         if (CalcEdit.Text = '0'+decimalseparator) or (CalcEdit.Text = '0') or (FCurrentValue = 0) then
  1328.            CalcEdit.Text := '0';
  1329.         If not FDecimalEntered then begin//DecimalinStr(CalcEdit.Text) then begin
  1330.            FCurrentValue := fcStrToFloat(CalcEdit.Text);
  1331.            teststr := DecimalSeparator;
  1332.            if Copy(CalcEdit.Text,Length(CalcEdit.Text),1)<>teststr then
  1333.               CalcEdit.Text := CalcEdit.Text + Btns[ButtonType].Caption;
  1334.            if (FStatusLabel <> nil) then
  1335.               FStatusLabel.Caption:=FStatusLabel.Caption+OpToChar(ButtonType);
  1336.         end
  1337.         else if FLastButtonType=btDecimal then Beep;
  1338.         FDecimalEntered := True;
  1339.         FLastButtonType := ButtonType;
  1340.      end;
  1341.     btPlusMinus:
  1342.      begin
  1343.       FLastButtonType := ButtonType;
  1344.       FCurrentValue := fcStrToFloat(CalcEdit.Text) * -1;
  1345.       CalcEdit.Text := FloatToStr(FCurrentValue);
  1346.       CalcEdit.SelStart := Length(CalcEdit.Text);
  1347.       if FStatusLabel <> nil then begin
  1348.          if FClearOnNextKey then
  1349.            FStatusLabel.Caption := '0'
  1350.          else
  1351.            FStatusLabel.Caption := FLastStatus+CalcEdit.Text;
  1352.       end;
  1353.      end;
  1354.     btClearAll:
  1355.      begin
  1356.       Reset;
  1357.      end;
  1358.     btClear:
  1359.      begin
  1360.       FCurrentValue := 0;
  1361.       CalcEdit.Text := '0';
  1362.       if FStatusLabel <> nil then begin
  1363.          if FClearOnNextKey then
  1364.            FStatusLabel.Caption := '0'
  1365.          else
  1366.            FStatusLabel.Caption := FLastStatus;
  1367.       end;
  1368.       FDecimalEntered := False;
  1369.      end;
  1370.     btPercent,btAdd,btSubtract,btDivide,btMultiply,btEquals:
  1371.      begin
  1372.        TempValue := fcStrToFloat(CalcEdit.Text);
  1373.        if (Length(CalcEdit.Text) > 0) and (ButtonType <> btEquals) then begin
  1374.           if (FLastOperatorEquals) then begin
  1375.               FLastOperand := TempValue;
  1376.               FLastOp := ButtonType;
  1377.               FLastOperatorEquals := False;
  1378.               if FStatusLabel <> nil then
  1379.                  FStatusLabel.Caption:=FLastStatus+OpToChar(ButtonType);
  1380.               FLastStatus := FStatusLabel.Caption;
  1381.               FCurrentValue := 0;
  1382.               FClearOnNextKey := True;
  1383.           end
  1384.           else if not(FLastOp in [btMultiply,btDivide,btAdd,btSubtract,btPercent]) then
  1385.           begin
  1386.              FLastOperand := TempValue;
  1387.              FNextToLastOp := FLastOp;
  1388.              FLastOp := ButtonType;
  1389.              FResultValue:=tempvalue;
  1390.              FClearOnNextKey := True;
  1391.              if FStatusLabel <> nil then begin
  1392.                 if FStatusLabel.Caption = '' then FStatusLabel.Caption := '0';
  1393.                 FLastStatus := FStatusLabel.Caption;
  1394.                 FStatusLabel.Caption:=FStatusLabel.Caption+OpToChar(ButtonType);
  1395.              end;
  1396.              FCurrentValue := 0;
  1397.           end
  1398.           else if (FLastOp in [btMultiply,btDivide,btAdd,btSubtract]) then begin
  1399.              if ButtonType = btPercent then begin
  1400.                 fLastOperand := fResultValue * (TempValue/100.0);
  1401.              end
  1402.              else begin
  1403.                if FLastButtonType in [btMultiply,btDivide,btAdd,btSubtract] then exit; //10/05/2001-Shouldn't do anything if hit key more than once.
  1404.                FClearOnNextKey := True;
  1405.                case FLastOp of
  1406.                  btMultiply: fResultValue := fResultValue * TempValue;
  1407.                  btDivide: begin
  1408.                   try
  1409.                     fResultValue := fResultValue / TempValue;
  1410.                   except
  1411.                     on E: Exception do begin   //**** Need Translation for Strings like below
  1412.                        if TempValue = 0.0 then
  1413.                           raise EfcCalcException.Create('Cannot divide by zero')
  1414.                        else raise;
  1415.                     end;
  1416.                   end;
  1417.                  end;
  1418.                  btAdd: fResultValue := fResultValue + TempValue;
  1419.                  btSubtract: fResultValue := fResultValue - TempValue;
  1420.                end;
  1421.                FLastOperand := TempValue;
  1422.              end;
  1423.              if (FStatusLabel <> nil) then begin
  1424.                 If (ButtonType=btPercent) then
  1425.                    FStatusLabel.Caption:='('+FStatusLabel.Caption+OpToChar(ButtonType)+')'
  1426.                 else if (((ButtonType = btMultiply) or (ButtonType=btDivide))
  1427.                   and ((FLastOp = btAdd) or (FLastOp=btSubtract))) then
  1428.                       FStatusLabel.Caption:='('+FStatusLabel.Caption+')'
  1429.                 else begin
  1430.                    FStatusLabel.Caption := FLastStatus+OpToChar(ButtonType)+FloatToStr(TempValue);
  1431.                 end;
  1432. //!!!!! Try 3** to see problem.  Also test 3*5%% and 3*5%* to test functionality with percent.
  1433.                 FLastStatus := FStatusLabel.Caption;
  1434.                 if ButtonType <> btPercent then
  1435.                    FStatusLabel.Caption := FStatusLabel.Caption+OpToChar(ButtonType);
  1436.             {    if ButtonType = btPercent then begin  //!!!! Status not right
  1437.                    FLastStatus := FStatusLabel.Caption;
  1438.                    FStatusLabel.Caption := FlastStatus+OpToChar(btEquals) + FloatToStr(FResultValue);
  1439.                 end;     }
  1440.              end;
  1441.              FCurrentValue := 0;
  1442.           end;
  1443.           FNextToLastOp := FLastOp;
  1444.           FLastOp:=ButtonType;
  1445.           if buttontype=btPercent then
  1446.              CalcEdit.Text := Getformattedtext(FLastOperand)
  1447.           else begin
  1448.              CalcEdit.Text := Getformattedtext(FResultValue);
  1449.           end;
  1450.           FCurrentValue := 0;
  1451.        end
  1452.        else if (Length(CalcEdit.Text) > 0)then begin
  1453.           if FLastOperatorEquals or (FLastOp = btPercent) then TempValue := FLastOperand
  1454.           else FLastOperand := TempValue;
  1455.           case FLastOp of
  1456.             btPercent:
  1457.                 begin
  1458.                     case FNextToLastOp of
  1459.                        btMultiply: fResultValue := fResultValue * TempValue;
  1460.                        btDivide: fResultValue := fResultValue / TempValue;
  1461.                        btAdd: fResultValue := fResultValue + TempValue;
  1462.                        btSubtract: fResultValue := fResultValue - TempValue;
  1463.                     end;
  1464.                 end;
  1465.             btMultiply: fResultValue := fResultValue * TempValue;
  1466.             btDivide: begin
  1467.                   try
  1468. //                     if TempValue <> 0.0 then
  1469.                     fResultValue := fResultValue / TempValue;
  1470.                   except
  1471.                     on E: Exception do begin   //**** Need Translation for Strings like below
  1472.                        if TempValue = 0.0 then
  1473.                           raise EfcCalcException.Create('Cannot divide by zero')
  1474.                        else raise;
  1475.                     end;
  1476.                   end;
  1477.                end;
  1478.             btAdd: fResultValue := fResultValue + TempValue;
  1479.             btSubtract: fResultValue := fResultValue - TempValue;
  1480.             btNone:fResultValue := TempValue;
  1481.           end;
  1482. //!!!!
  1483.           if (StatusLabel <> nil) then
  1484.              if (FLastOp<>btNone) then begin
  1485.                  if FLastOperatorEquals then begin
  1486.                     FStatusLabel.Caption := FLastStatus;
  1487.                     FStatusLabel.Caption := FStatusLabel.Caption + OpToChar(FLastOp) + FloatToStr(FLastOperand);
  1488.                     FStatusLabel.Caption:='('+FStatusLabel.Caption+')';
  1489.                  end
  1490.                  else if FLastOp = btPercent then begin
  1491.                     FStatusLabel.Caption := FLastStatus;
  1492.                  end
  1493.                  else begin
  1494.                     FStatusLabel.Caption := FLastStatus;
  1495.                     FStatusLabel.Caption:=FStatusLabel.Caption+OpToChar(FLastOp)+FloatToStr(TempValue);
  1496.                     FStatusLabel.Caption:='('+FStatusLabel.Caption+')';
  1497.                  end;
  1498.                  FLastStatus := FStatusLabel.Caption;
  1499.                  FStatusLabel.Caption := FStatusLabel.Caption+OpToChar(ButtonType);
  1500.                  FStatusLabel.Caption := FStatusLabel.Caption + FloatToStr(FResultValue);
  1501.              end
  1502.              else FLastStatus:=FStatusLabel.Caption;
  1503.           FLastOperatorEquals := True;
  1504.           CalcEdit.Text := Getformattedtext(FResultValue,True);
  1505.           if cboSelectOnEquals in Options then begin
  1506.              CalcEdit.SelectAll;
  1507.              selectallflag := True;
  1508.           end
  1509.           else CalcEdit.SelStart := Length(CalcEdit.Text);
  1510.           FClearOnNextKey := True;
  1511.           FBackSpaceValid := False;
  1512.           FCurrentValue := 0;
  1513.        end
  1514.        else Beep;
  1515.        FLastButtonType := ButtonType;
  1516.     end;
  1517.     btBackSpace:
  1518.      if FBackSpaceValid then begin
  1519.       Temp := CalcEdit.Text;
  1520.       if True or ((not (cboShowDecimal in Options)) and (Temp[Length(Temp)] in ['0'..'9'])) or
  1521.          ((cboShowDecimal in Options) and ((Length(Temp)-1) >= 0) and (Temp[Length(Temp)-1] in ['0'..'9'])) then
  1522.       begin
  1523.         if (Length(Temp)-1>=0) and (Temp[Length(Temp)]=DecimalSeparator) then
  1524.         begin
  1525.            Delete(Temp, Length(Temp)-1,2);
  1526.            if FStatusLabel <> nil then begin
  1527.               Temp := FStatusLabel.Caption;
  1528.               Delete(Temp, Length(Temp),1);
  1529.               FStatusLabel.Caption := Temp;
  1530.            end;
  1531.            FDecimalEntered := False;
  1532.         end
  1533.         else Delete(Temp, Length(Temp),1);
  1534.         {        if cboShowDecimal in Options then
  1535.           Delete(Temp, Length(Temp)-1,1)
  1536.         else
  1537.         Delete(Temp, Length(Temp),1);}
  1538.         if not DecimalInStr(Temp) then FDecimalEntered := False;
  1539.         if Temp = '' then begin
  1540.           FBackSpaceValid := False;
  1541.           Temp := '0';
  1542.         end;
  1543.         if (AnsiPos(DecimalSeparator,Temp)> 0) and
  1544.            (AnsiPos(DecimalSeparator,Temp)< CalcEdit.selstart) then CalcEdit.Text := Temp
  1545.         else begin
  1546.           FCurrentValue := fcStrToFloat(Temp);
  1547.           CalcEdit.Text := getFormattedText(FCurrentValue);//FloatToStr(FCurrentValue);
  1548.         end;
  1549.         if FStatusLabel <> nil then begin
  1550.            Temp := FStatusLabel.Caption;
  1551.            Delete(Temp, Length(Temp),1);
  1552.            FStatusLabel.Caption := Temp;
  1553.         end;
  1554.       end
  1555.       else begin
  1556.         if FStatusLabel <> nil then begin
  1557.            Temp := FStatusLabel.Caption;
  1558.            if Temp[Length(Temp)] = DecimalSeparator then begin
  1559.               FDecimalEntered := False;
  1560.               Delete(Temp, Length(Temp),1);
  1561.               FStatusLabel.Caption := Temp;
  1562.            end
  1563.            else FBackSpaceValid := False;
  1564.         end;
  1565.       end;
  1566.      end
  1567.      else Beep;
  1568.     btInverse:
  1569.      begin
  1570.       try
  1571.          if cboDigitGrouping in Options then FCurrentValue := 1 / fcStrToFloat(CalcEdit.Text)
  1572.          else FCurrentValue := 1 / fcStrToFloat(CalcEdit.Text);
  1573.       except
  1574.          on E: Exception do begin   //**** Need Translation for Strings like below
  1575.             if fcStrToFloat(CalcEdit.Text) = 0.0 then
  1576.                raise EfcCalcException.Create('Cannot divide by zero')
  1577.             else raise;
  1578.          end;
  1579.       end;
  1580.       CalcEdit.Text := getformattedText(FCurrentValue);//FloatToStr(FCurrentValue);
  1581.       CalcEdit.SelStart := Length(CalcEdit.Text);
  1582.       if FStatusLabel <> nil then begin
  1583.          if FClearOnNextKey then
  1584.            FStatusLabel.Caption := '0'
  1585.          else
  1586.            FStatusLabel.Caption := FLastStatus+CalcEdit.Text;
  1587.       end;
  1588.       FCurrentValue := 0;
  1589.       FClearOnNextKey := True;
  1590.       FBackSpaceValid := False;
  1591.       FClearStatus := True;
  1592.       FLastButtonType := ButtonType;
  1593.     end;
  1594.     btSqrt:
  1595.      begin
  1596.       FCurrentValue := Sqrt(fcStrToFloat(CalcEdit.Text));
  1597.       CalcEdit.Text := getformattedText(FCurrentValue);//FloatToStr(FCurrentValue);
  1598.       CalcEdit.SelStart := Length(CalcEdit.Text);
  1599.       if FStatusLabel <> nil then begin
  1600.          if FClearOnNextKey then
  1601.            FStatusLabel.Caption := '0'
  1602.          else
  1603.            FStatusLabel.Caption := FLastStatus+CalcEdit.Text;
  1604.       end;
  1605.       FCurrentValue := 0;
  1606.       FClearOnNextKey := True;
  1607.       FBackSpaceValid := False;
  1608.       FClearStatus := True;
  1609.       FLastButtonType := ButtonType;
  1610.      end;
  1611.     btMStore:
  1612.      begin
  1613.       FMemoryValue := fcStrToFloat(CalcEdit.Text);
  1614.       FMemoryValue := FMemoryValue * 1;
  1615.       FCurrentValue := 0;
  1616.       FClearOnNextKey := True;
  1617.       FClearStatus := True;
  1618.       FBackSpaceValid := False;
  1619.      end;
  1620.     btMAdd:
  1621.      begin
  1622.       TempValue := FMemoryValue;
  1623.       FMemoryValue := fcStrToFloat(CalcEdit.Text);
  1624.       FMemoryValue := (FMemoryValue * 1) + TempValue;
  1625.      end;
  1626.     btMRecall:
  1627.      begin
  1628.       CalcEdit.Text := getformattedtext(FMemoryValue);//FloatToStr(FMemoryValue);
  1629.       CalcEdit.SelStart := Length(CalcEdit.Text);
  1630.       FCurrentValue := 0;
  1631.      end;
  1632.     btMClear:
  1633.      begin
  1634.       FMemoryValue := 0;
  1635.      end;
  1636.    end;   // case  ButtonType of...
  1637.    except
  1638.      on E: Exception do begin
  1639.       OpToButton(ButtonType).DrawKeyDown := False;
  1640.       OpToButton(ButtonType).Invalidate;
  1641.       Reset;
  1642.       CalcEdit.Text := E.Message;
  1643.      end;
  1644.    end;
  1645.   if cboShowDecimal in Options then begin
  1646.      if not DecimalinStr(CalcEdit.Text) then
  1647.        CalcEdit.Text := CalcEdit.Text+DecimalSeparator;
  1648.      if selectallflag then calcedit.selectall;
  1649.   end;
  1650.   if FMemoryStatus <> nil then
  1651.      FMemoryStatus.Caption := MemoryStoreMap[FMemoryValue = 0];
  1652. end;
  1653. function TfcCalculator.IsBinaryOperator(ButtonType: TfcCalcButtonType):boolean;
  1654. begin
  1655.  result := False;
  1656.  case ButtonType of
  1657.  btMultiply,btDivide,btAdd,btSubtract,btEquals: result := True;
  1658.  end;
  1659. end;
  1660. procedure TfcCalculator.SetBackgroundBitmapDrawStyle(Value: TfcCalcBitmapDrawStyle);
  1661. begin
  1662.    if Value<>FBackgroundBitmapDrawStyle then
  1663.    begin
  1664.       FBackgroundBitmapDrawStyle:= Value;
  1665.       FullRepaint;
  1666.    end
  1667. end;
  1668. procedure TfcCalculator.SetBackgroundBitmap(Value: TPicture);
  1669. var i:integer;
  1670. begin
  1671.    if (Value = nil) or (Value.Graphic=nil) or Value.Graphic.Empty then begin
  1672.      for i:= 0 to ControlCount-1 do begin
  1673.        if COntrols[i] is TfcCalcButton then
  1674.          TfcCalcButton(controls[i]).FTransparent := False;
  1675.      end;
  1676.    end
  1677.    else begin
  1678.     for i:= 0 to ControlCount-1 do begin
  1679.        if COntrols[i] is TfcCalcButton then
  1680.          TfcCalcButton(controls[i]).FTransparent := True;
  1681.     end;
  1682.    end;
  1683.    FBackGroundBitmap.Assign(Value);
  1684.    FPaintBitmap.FreeImage;
  1685.    InitBitmapsFlag := True;
  1686.    FullRepaint;
  1687. end;
  1688. function TfcCalculator.GetText: string;
  1689. begin
  1690.   Result := CalcEdit.Text;
  1691. end;
  1692. function TfcCalculator.GetCalcEdit: TCustomEdit;
  1693. begin
  1694.   if FCalcEdit <> nil then
  1695.     Result := FCalcEdit
  1696.   else Result := FResultEdit;
  1697. end;
  1698. procedure TfcCalculator.SetBorder3D(const Value: Boolean);
  1699. begin
  1700.   if F3D <> Value then begin
  1701.     F3D := Value;
  1702.     invalidate;
  1703.   end;
  1704. end;
  1705. procedure TfcCalculator.SetText(const Value: string);
  1706. begin
  1707.   if CalcEdit <> nil then
  1708.      CalcEdit.Text := Value;
  1709. end;
  1710. procedure TfcCalculator.SetCalcEdit(const Value: TCustomEdit);
  1711. begin
  1712. //  if FCalcEdit <> nil then
  1713.      FCalcEdit := Value;
  1714. end;
  1715. procedure TfcCalculator.SetOptions(Value: TfcCalcOptions);
  1716. var ChangedOptions: TfcCalcOptions;
  1717. begin
  1718.   if FOptions <> Value then
  1719.   begin
  1720.     ChangedOptions := (FOptions - Value) + (Value - FOptions);
  1721.     FOptions := Value;
  1722.     if ChangedOptions <> [] then begin
  1723. {       for i:= 0 to ControlCount-1 do begin
  1724.          if COntrols[i] is TfcCalcButton then begin
  1725.            TfcCalcButton(controls[i]).FOptions := Value;
  1726.            if (FBackGroundBitmap <> nil) and (FBackGroundBitmap.Graphic <> nil) and not FBackgroundbitmap.Graphic.empty then
  1727.               TfcCalcButton(controls[i]).FTransparent := True
  1728.            else TfcCalcButton(controls[i]).FTransparent := False;
  1729.          end;
  1730.        end;}
  1731.        CalcButtons;
  1732.        FullRepaint;
  1733.     end;
  1734.   end;
  1735. end;
  1736. procedure TfcCalculator.RefreshSummary;
  1737. begin
  1738.   if StatusLabel <> nil then begin
  1739.      FStatusLabel.Caption := 'Calculator';
  1740.   end;
  1741. end;
  1742. procedure TfcCalculator.FullRepaint;
  1743. var i:integer;
  1744. begin
  1745.   InitBitmapsFlag:= True;
  1746.   invalidate;
  1747.   for i:= 0 to ControlCount-1 do begin
  1748.      controls[i].invalidate;
  1749.   end;
  1750. end;
  1751. procedure TfcCalculator.SetMargin(Value: Integer);
  1752. begin
  1753.   if FMargin <> Value then
  1754.   begin
  1755.      FMargin := Value;
  1756.      CalcButtons;
  1757.   end;
  1758. end;
  1759. procedure TfcCalculator.SetPanelColor(Value: TColor);
  1760. var i:integer;
  1761. begin
  1762.   if FPanelColor <> Value then
  1763.   begin
  1764.     FPanelColor := Value;
  1765.     Color := Value;
  1766.     if FMemoryStatus<>nil then
  1767.        FMemoryStatus.Color := Value;
  1768.     if FMemoryBevel <> nil then
  1769.        FMemoryBevel.FColor := Value;
  1770.     for i:= 0 to ControlCount-1 do begin
  1771.        if COntrols[i] is TfcCalcButton then
  1772.          TfcCalcButton(controls[i]).ButtonColor := Value;
  1773.     end;
  1774.     FullRepaint;
  1775.   end;
  1776. end;
  1777. function TfcCalcButton.GetCalcOptions: TfcCalcOptions;
  1778. begin
  1779.   result:= FCalc.Options;
  1780. end;
  1781. {
  1782. procedure Register;
  1783. begin
  1784.   RegisterComponents('Samples', [TfcCalculator]);
  1785. end;
  1786. }
  1787. end.