home *** CD-ROM | disk | FTP | other *** search
/ Delphi 5 for Professionals / DELPHI5.iso / AddOns / Components / Essentials / SETUP.EXE / %MAINDIR% / Escalc.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-11-28  |  34.7 KB  |  1,349 lines

  1. {*********************************************************}
  2. {*                   ESCALC.PAS 1.05                     *}
  3. {*      Copyright (c) 1997-98 TurboPower Software Co     *}
  4. {*                 All rights reserved.                  *}
  5. {*********************************************************}
  6.  
  7. {$I ES.INC}
  8.  
  9. {$B-} {Complete Boolean Evaluation}
  10. {$I+} {Input/Output-Checking}
  11. {$P+} {Open Parameters}
  12. {$T-} {Typed @ Operator}
  13. {$W-} {Windows Stack Frame}
  14. {$X+} {Extended Syntax}
  15.  
  16. {$IFNDEF Win32}
  17. {$G+} {286 Instructions}
  18. {$N+} {Numeric Coprocessor}
  19.  
  20. {$C MOVEABLE,DEMANDLOAD,DISCARDABLE}
  21. {$ENDIF}
  22.  
  23. unit EsCalc;
  24.   {-calculator component}
  25.  
  26. interface
  27.  
  28. uses
  29.   {$IFDEF Win32} Windows, {$ELSE} WinTypes, WinProcs, {$ENDIF}
  30.   Buttons, Classes, ClipBrd, Controls, ExtCtrls, Forms, Graphics,
  31.   Menus, Messages, StdCtrls, SysUtils,
  32.   EsBase, EsConst, EsData, EsUtil;
  33.  
  34. const
  35.   {$IFDEF Win32}
  36.   calcDefBorderStyle       = bsNone;
  37.   {$ELSE}
  38.   calcDefBorderStyle       = bsSingle;
  39.   {$ENDIF Win32}
  40.   calcDefColor             = clBtnFace;                                {!!.01}
  41.   {$IFDEF Win32}
  42.   calcDefHeight            = 140;
  43.   {$ELSE}
  44.   calcDefHeight            = 160;
  45.   {$ENDIF Win32}
  46.   calcDefShowMemoryButtons = True;
  47.   calcDefTabStop           = True;
  48.   calcDefWidth             = 200;
  49.  
  50. type
  51.   TEsCalculatorButton = (
  52.     ccNone, ccBack, ccClearEntry, ccClear, ccAdd, ccSub, ccMul, ccDiv,
  53.     cc0, cc1, cc2, cc3, cc4, cc5,  cc6, cc7, cc8, cc9,
  54.     ccDecimal, ccEqual, ccInvert, ccChangeSign, ccPercent, ccSqrt,
  55.     ccMemClear, ccMemRecall, ccMemStore, ccMemAdd, ccMemSub);
  56.  
  57.   TEsButtonInfo = packed record
  58.     Position : TRect;      {position and size}
  59.     Caption  : string[10]; {button text}
  60.     Visible  : Boolean;    {true to display button}
  61.   end;
  62.  
  63.   TEsButtonArray = array[ccBack..ccMemSub] of TEsButtonInfo;
  64.   TEsCalcState = (csValid, csLocked, csClear);                         {!!.03}
  65.  
  66. type
  67.   TEsCalcColorArray = array[0..7] of TColor;
  68.   TEsCalcColorScheme = (csCustom, csWindows, csDark, csOcean, csPlain);
  69.   TEsCalcSchemeArray = array[TEsCalcColorScheme] of TEsCalcColorArray;
  70.  
  71. const
  72.   {DisabledMemoryButtons, Display, DisplayText, EditButtons,
  73.    FunctionButtons, MemoryButtons, NumberButtons, OperatorButtons}
  74.   CalcScheme : TEsCalcSchemeArray =
  75.     ((0, 0, 0, 0, 0, 0, 0, 0),
  76.      (clGray, clWindow, clWindowText, clMaroon, clNavy, clRed,  clBlue,   clRed),
  77.      (clGray, clBlack,  clAqua,       clBlack,  clTeal, clNavy, clMaroon, clBlue),
  78.      (clGray, clAqua,   clBlack,      clPurple, clNavy, clNavy, clAqua,   clBlue),
  79.      (clGray, clWhite,  clNavy,       clBlack,  clNavy, clNavy, clBlue,   clBlue)
  80.     );
  81.  
  82. type
  83.   TEsCalcColors = class(TPersistent)
  84.   private
  85.     {.Z+}
  86.     {property variables}
  87.     FUpdating     : Boolean;
  88.     FOnChange     : TNotifyEvent;
  89.  
  90.     {internal variables}
  91.     SettingScheme : Boolean;
  92.  
  93.     {internal methods}
  94.     procedure DoOnChange;
  95.  
  96.     {property methods}
  97.     function GetColor(Index : Integer) : TColor;
  98.     procedure SetColor(Index : Integer; Value : TColor);
  99.     procedure SetColorScheme(Value : TEsCalcColorScheme);
  100.     procedure SetDisplayText(Value : TColor);
  101.     {.Z-}
  102.   public
  103.     {.Z+}
  104.     {property variables}
  105.     FCalcColors   : TEsCalcColorArray;
  106.     FColorScheme  : TEsCalcColorScheme;
  107.  
  108.     procedure Assign(Source : TPersistent);
  109.       override;
  110.     procedure BeginUpdate;
  111.     procedure EndUpdate;
  112.  
  113.     property OnChange : TNotifyEvent
  114.       read FOnChange
  115.       write FOnChange;
  116.     {.Z-}
  117.  
  118.   published
  119.     property ColorScheme : TEsCalcColorScheme
  120.       read FColorScheme
  121.       write SetColorScheme;
  122.  
  123.     property DisabledMemoryButtons : TColor index 0
  124.       read GetColor
  125.       write SetColor;
  126.  
  127.     property Display : TColor index 1
  128.       read GetColor
  129.       write SetColor;
  130.  
  131.     property DisplayText : TColor
  132.       read FCalcColors[2]
  133.       write SetDisplayText
  134.       nodefault;
  135.  
  136.     property EditButtons : TColor index 3
  137.       read GetColor
  138.       write SetColor;
  139.  
  140.     property FunctionButtons : TColor index 4
  141.       read GetColor
  142.       write SetColor;
  143.  
  144.     property MemoryButtons : TColor index 5
  145.       read GetColor
  146.       write SetColor;
  147.  
  148.     property NumberButtons : TColor index 6
  149.       read GetColor
  150.       write SetColor;
  151.  
  152.     property OperatorButtons : TColor index 7
  153.       read GetColor
  154.       write SetColor;
  155.   end;
  156.  
  157. type
  158.   {.Z+}
  159.   TEsCalcPanel = class(TPanel)
  160.   protected
  161.     procedure Click;
  162.       override;
  163.   public
  164.   end;
  165.   {.Z-}
  166.  
  167. type
  168.   TButtonPressedEvent = procedure(Sender : TObject; Button : TEsCalculatorButton)
  169.     of object;
  170.  
  171.   TEsCustomCalculator = class(TEsBase)
  172.   protected {private}
  173.     {.Z+}
  174.     {property variables}
  175.     FBorderStyle        : TBorderStyle;
  176.     FColors             : TEsCalcColors;
  177.     FShowMemoryButtons  : Boolean;
  178.  
  179.     {event variables}
  180.     FOnButtonPressed    : TButtonPressedEvent;
  181.  
  182.     {internal variables}
  183.     cButtons            : TEsButtonArray;
  184.     cDisplay            : Extended;     {the calculated value}
  185.     cDisplayStr         : string;       {the string that is displayed}
  186.     cDownButton         : TEsCalculatorButton;
  187.     cLastButton         : TEsCalculatorButton;
  188.     cMargin             : Integer;
  189.     cMemory             : Extended;     {value stored in memory register}
  190.     cOperand            : Extended;     {the operand}
  191.     cOperation          : TEsCalculatorButton;
  192.     cPanel              : TEsCalcPanel;
  193.     cState              : set of TEsCalcState;                         {!!.03}
  194.     cPopup              : Boolean;      {true if being created as a popup}
  195.  
  196.     {internal methods}
  197.     procedure cAdjustHeight;
  198.     procedure cCalculateLook;
  199.     procedure cClearAll;
  200.     procedure cColorChange(Sender : TObject);
  201.     procedure cDisplayError;
  202.     procedure cDisplayValue(const Value : Extended);
  203.     procedure cDrawCalcButton(Button : TEsButtonInfo; Pressed : Boolean);
  204.     procedure cDrawFocusState;
  205.     procedure cEvaluate;
  206.     procedure cInvalidateIndicator;
  207.  
  208.     {property methods}
  209.     procedure SetBorderStyle(Value : TBorderStyle);
  210.     procedure SetShowMemoryButtons(Value : Boolean);
  211.  
  212.     {VCL control methods}
  213.     procedure CMCtl3DChanged(var Msg : TMessage);
  214.       message CM_CTL3DCHANGED;
  215.     procedure CMEnter(var Msg : TMessage);
  216.       message CM_ENTER;
  217.     procedure CMExit(var Msg : TMessage);
  218.       message CM_EXIT;
  219.     procedure CMFontChanged(var Msg : TMessage);
  220.       message CM_FONTCHANGED;
  221.  
  222.     {windows message handlers}
  223.     procedure WMEraseBkgnd(var Msg : TWMEraseBkgnd);
  224.       message WM_ERASEBKGND;
  225.     procedure WMGetText(var Msg : TWMGetText);
  226.       message WM_GETTEXT;
  227.     procedure WMGetTextLength(var Msg : TWMGetTextLength);
  228.       message WM_GETTEXTLENGTH;
  229.     procedure WMKeyDown(var Msg : TWMKeyDown);
  230.       message WM_KEYDOWN;
  231.     procedure WMSetText(var Msg : TWMSetText);
  232.       message WM_SETTEXT;
  233.     {.Z-}
  234.  
  235.   protected
  236.     {.Z+}
  237.     procedure CreateParams(var Params : TCreateParams);
  238.       override;
  239.     procedure CreateWnd;
  240.       override;
  241.     procedure KeyDown(var Key : Word; Shift : TShiftState);
  242.       override;
  243.     procedure KeyPress(var Key : Char);
  244.       override;
  245.     procedure MouseDown(Button : TMouseButton; Shift : TShiftState; X, Y : Integer);
  246.       override;
  247.     procedure MouseUp(Button : TMouseButton; Shift : TShiftState; X, Y : Integer);
  248.       override;
  249.     procedure Paint;
  250.       override;
  251.     {.Z-}
  252.  
  253.     {protected properties}
  254.     property BorderStyle : TBorderStyle
  255.       read FBorderStyle
  256.       write SetBorderStyle
  257.       default calcDefBorderStyle;
  258.  
  259.     property ShowMemoryButtons : Boolean
  260.       read FShowMemoryButtons
  261.       write SetShowMemoryButtons
  262.       default calcDefShowMemoryButtons;
  263.  
  264.     {protected events}
  265.     property OnButtonPressed : TButtonPressedEvent
  266.       read FOnButtonPressed
  267.       write FOnButtonPressed;
  268.  
  269.   public
  270.     {.Z+}
  271.     constructor Create(AOwner : TComponent);
  272.       override;
  273.     constructor CreateEx(AOwner : TComponent; AsPopup : Boolean);
  274.       virtual;
  275.     destructor Destroy;
  276.       override;
  277.     procedure SetBounds(ALeft, ATop, AWidth, AHeight : Integer);
  278.       override;
  279.     {.Z-}
  280.  
  281.     procedure CopyToClipboard;
  282.     procedure PasteFromClipboard;
  283.     procedure PressButton(Button : TEsCalculatorButton);
  284.  
  285.     {public properties}
  286.     property Colors : TEsCalcColors
  287.       read FColors
  288.       write FColors;
  289.  
  290.     property Memory : Extended {run-time}
  291.       read cMemory
  292.       write cMemory;
  293.  
  294.     property Text; {run-time}
  295.  
  296.     property Value : Extended  {run-time}
  297.       read cDisplay;
  298.   end;
  299.  
  300.   TEsCalculator = class(TEsCustomCalculator)
  301.   published
  302.     {properties}
  303.     property Font;  {must be prior to "Colors"}
  304.     property Align;
  305.     property BorderStyle;
  306.     property Ctl3D;
  307.     property Colors;
  308.     property Cursor;
  309.     property DragCursor;
  310.     property DragMode;
  311.     property Enabled;
  312.     property EsLabelInfo;
  313.     property ParentCtl3D;
  314.     property ParentFont;
  315.     property ParentShowHint;
  316.     property PopupMenu;
  317.     property ShowHint;
  318.     property ShowMemoryButtons;
  319.     property TabOrder;
  320.     property TabStop default calcDefTabStop;
  321.     property Version;
  322.     property Visible;
  323.  
  324.     {events}
  325.     property OnButtonPressed;
  326.     property OnDragDrop;
  327.     property OnDragOver;
  328.     property OnEndDrag;
  329.     property OnEnter;
  330.     property OnExit;
  331.     property OnKeyDown;
  332.     property OnKeyPress;
  333.     property OnKeyUp;
  334.     property OnMouseDown;
  335.     property OnMouseMove;
  336.     property OnMouseUp;
  337.     {$IFDEF Win32}
  338.     property OnStartDrag;
  339.     {$ENDIF Win32}
  340.   end;
  341.  
  342.  
  343. implementation
  344.  
  345.  
  346. {$IFDEF TRIALRUN}
  347. uses
  348.   EsTrial;
  349. {$I ESTRIALF.INC}
  350. {$ENDIF}
  351.  
  352.  
  353. {*** TEsCalcColors ***}
  354.  
  355. procedure TEsCalcColors.Assign(Source : TPersistent);
  356. begin
  357.   if Source is TEsCalcColors then begin
  358.     FCalcColors := TEsCalcColors(Source).FCalcColors;
  359.     FColorScheme := TEsCalcColors(Source).FColorScheme;
  360.   end else
  361.     inherited Assign(Source);
  362. end;
  363.  
  364. procedure TEsCalcColors.BeginUpdate;
  365. begin
  366.   FUpdating := True;
  367. end;
  368.  
  369. procedure TEsCalcColors.EndUpdate;
  370. begin
  371.   FUpdating := False;
  372.   DoOnChange;
  373. end;
  374.  
  375. procedure TEsCalcColors.DoOnChange;
  376. begin
  377.   if not FUpdating and Assigned(FOnChange) then
  378.     FOnChange(Self);
  379.  
  380.   if not SettingScheme then
  381.     FColorScheme := csCustom;
  382. end;
  383.  
  384. function TEsCalcColors.GetColor(Index : Integer) : TColor;
  385. begin
  386.   Result := FCalcColors[Index];
  387. end;
  388.  
  389. procedure TEsCalcColors.SetColor(Index : Integer; Value : TColor);
  390. begin
  391.   if Value <> FCalcColors[Index] then begin
  392.     FCalcColors[Index] := Value;
  393.     DoOnChange;
  394.   end;
  395. end;
  396.  
  397. procedure TEsCalcColors.SetColorScheme(Value : TEsCalcColorScheme);
  398. begin
  399.   if Value <> FColorScheme then begin
  400.     SettingScheme := True;
  401.     try
  402.       FColorScheme := Value;
  403.       if Value <> csCustom then begin
  404.         FCalcColors := CalcScheme[Value];
  405.         DoOnChange;
  406.       end;
  407.     finally
  408.       SettingScheme := False;
  409.     end;
  410.   end;
  411. end;
  412.  
  413. procedure TEsCalcColors.SetDisplayText(Value : TColor);
  414. begin
  415.   if Value <> FCalcColors[2] then begin
  416.     FCalcColors[2] := Value;
  417.     DoOnChange;
  418.   end;
  419. end;
  420.  
  421.  
  422. {*** TEsCalcPanel ***}
  423.  
  424. procedure TEsCalcPanel.Click;
  425. begin
  426.   (Owner as TEsCustomCalculator).SetFocus;
  427. end;
  428.  
  429.  
  430. {*** TEsCustomCalculator ***}
  431.  
  432. procedure TEsCustomCalculator.cAdjustHeight;
  433. var
  434.   DC         : hDC;
  435.   SaveFont   : hFont;
  436.   I          : Integer;
  437.   SysMetrics : TTextMetric;
  438.   Metrics    : TTextMetric;
  439. begin
  440.   DC := GetDC(0);
  441.   GetTextMetrics(DC, SysMetrics);
  442.   SaveFont := SelectObject(DC, Font.Handle);
  443.   GetTextMetrics(DC, Metrics);
  444.   SelectObject(DC, SaveFont);
  445.   ReleaseDC(0, DC);
  446.   if NewStyleControls then begin
  447.     if Ctl3D then I := 8 else I := 6;
  448.     I := GetSystemMetrics(SM_CYBORDER) * I;
  449.   end else begin
  450.     I := SysMetrics.tmHeight;
  451.     if I > Metrics.tmHeight then I := Metrics.tmHeight;
  452.     I := I div 4 + GetSystemMetrics(SM_CYBORDER) * 4;
  453.   end;
  454.   cPanel.Height := Metrics.tmHeight + I;
  455. end;
  456.  
  457. procedure TEsCustomCalculator.cCalculateLook;
  458. var
  459.   CW  : Integer;  {client width}
  460.   BW  : Integer;  {button width}
  461.   BH  : Integer;  {button height}
  462.   LBW : Integer;  {large button width}
  463.   M1  : Integer;  {margin between buttons}
  464.   M2  : Integer;  {left and right edge margins}
  465.   M3  : Integer;  {margin between panel and frst row of buttons}
  466.   M4  : Integer;  {margin between memory buttons and other buttons}
  467.   TM  : Integer;  {area where the panel is placed}
  468.   X   : Integer;
  469.   Y   : Integer;
  470.   PW  : Integer;  {panel width}
  471.   B   : TEsCalculatorButton;
  472. begin
  473.   if not HandleAllocated then
  474.     Exit;
  475.  
  476.   {set panel height based on font}
  477.   cAdjustHeight;
  478.  
  479.   for B := Low(cButtons) to High(cButtons) do
  480.     cButtons[B].Visible := True;
  481.  
  482.   CW := ClientWidth;
  483.  
  484.   if Width <= 200 then begin
  485.     M1 := 2;
  486.     M2 := 4;
  487.   end else begin
  488.     M1 := 4;
  489.     M2 := 6;
  490.   end;
  491.   {save left/right/top/bottom margin value}
  492.   cMargin := M2;
  493.  
  494.   M4 := M2;
  495.   if FShowMemoryButtons then begin
  496.     BW := (CW - 3*M2 - 4*M1) div 6;
  497.     M4 := CW - 2*M2 - 6*BW - 4*M1;
  498.   end else begin
  499.     BW := (CW - 2*M2 - 4*M1) div 5;
  500.     if (CW - 2*M2 - 4*M1) div 6 >= 4 then
  501.       Inc(M2, 2)
  502.     else if (CW - 2*M2 - 4*M1) div 6 >= 2 then
  503.       Inc(M2, 1);
  504.   end;
  505.  
  506.   {button height, using an estimate for TM}
  507.   TM := M2 + M2 + cPanel.Height;
  508.   BH := (ClientHeight - TM - M2 - 4*M1) div 5;
  509.  
  510.   {calculate actual area below panel}
  511.   M3 := ClientHeight - M2 - cPanel.Height - 5*BH - 4*M1 - M2;
  512.  
  513.   {calculate actual height of area above buttons}
  514.   TM := M2 + M3 + cPanel.Height;
  515.  
  516.   {large button width}
  517.   LBW := (4*BW + 3*M1 - 2*M1) div 3;
  518.  
  519.   {calculate the width of the edit window}
  520.   cMargin := M2;
  521.   if FShowMemoryButtons then
  522.     PW := 6*BW + M4 + 4*M1
  523.   else
  524.     PW := 5*BW + 4*M1;
  525.  
  526.   {position edit control}
  527.   cPanel.SetBounds(cMargin, cMargin, PW, cPanel.Height);
  528.  
  529.   {memory column}
  530.   if FShowMemoryButtons then begin
  531.     X := M2;
  532.     Y := TM;
  533.     cButtons[ccMemClear].Position := Rect(X, Y, X+BW, Y+BH);
  534.     cButtons[ccMemClear].Caption := 'MC';
  535.  
  536.     Y := TM + BH + M1;
  537.     cButtons[ccMemRecall].Position := Rect(X, Y, X+BW, Y+BH);
  538.     cButtons[ccMemRecall].Caption := 'MR';
  539.  
  540.     Y := TM + 2*BH + 2*M1;
  541.     cButtons[ccMemStore].Position := Rect(X, Y, X+BW, Y+BH);
  542.     cButtons[ccMemStore].Caption := 'MS';
  543.  
  544.     Y := TM + 3*BH + 3*M1;
  545.     cButtons[ccMemAdd].Position := Rect(X, Y, X+BW, Y+BH);
  546.     cButtons[ccMemAdd].Caption := 'M+';
  547.  
  548.     Y := TM + 4*BH + 4*M1;
  549.     cButtons[ccMemSub].Position := Rect(X, Y, X+BW, Y+BH);
  550.     cButtons[ccMemSub].Caption := 'M-';
  551.   end else
  552.     for B := ccMemClear to ccMemSub do
  553.       cButtons[B].Visible := False;
  554.  
  555.   {row 1 - large buttons}
  556.   Y := TM;
  557.   if FShowMemoryButtons then
  558.     X := 2*BW + M4 + M2 + M1
  559.   else
  560.     X := BW + M2 + M1;
  561.   cButtons[ccBack].Position := Rect(X, Y, X+LBW, Y+BH);
  562.   cButtons[ccBack].Caption := 'Back';
  563.  
  564.   Inc(X, LBW+M1);
  565.   cButtons[ccClearEntry].Position := Rect(X, Y, X+LBW, Y+BH);
  566.   cButtons[ccClearEntry].Caption := 'CE';
  567.  
  568.   Inc(X, LBW+M1);
  569.   cButtons[ccClear].Position := Rect(X, Y, X+LBW, Y+BH);
  570.   cButtons[ccClear].Caption := 'C';
  571.  
  572.   {row 2}
  573.   Y := TM + BH + M1;
  574.   if FShowMemoryButtons then
  575.     X := M2 + BW + M4
  576.   else
  577.     X := M2;
  578.   cButtons[cc7].Position := Rect(X, Y, X+BW, Y+BH);
  579.   cButtons[cc7].Caption := '7';
  580.  
  581.   Inc(X, BW+M1);
  582.   cButtons[cc8].Position := Rect(X, Y, X+BW, Y+BH);
  583.   cButtons[cc8].Caption := '8';
  584.  
  585.   Inc(X, BW+M1);
  586.   cButtons[cc9].Position := Rect(X, Y, X+BW, Y+BH);
  587.   cButtons[cc9].Caption := '9';
  588.  
  589.   Inc(X, BW+M1);
  590.   cButtons[ccDiv].Position := Rect(X, Y, X+BW, Y+BH);
  591.   cButtons[ccDiv].Caption := '/';
  592.  
  593.   Inc(X, BW+M1);
  594.   cButtons[ccSqrt].Position := Rect(X, Y, X+BW, Y+BH);
  595.   cButtons[ccSqrt].Caption := 'Sqrt';
  596.  
  597.   {row 3}
  598.   Y := TM + 2*BH + 2*M1;
  599.   if FShowMemoryButtons then
  600.     X := M2 + BW + M4
  601.   else
  602.     X := M2;
  603.   cButtons[cc4].Position := Rect(X, Y, X+BW, Y+BH);
  604.   cButtons[cc4].Caption := '4';
  605.  
  606.   Inc(X, BW+M1);
  607.   cButtons[cc5].Position := Rect(X, Y, X+BW, Y+BH);
  608.   cButtons[cc5].Caption := '5';
  609.  
  610.   Inc(X, BW+M1);
  611.   cButtons[cc6].Position := Rect(X, Y, X+BW, Y+BH);
  612.   cButtons[cc6].Caption := '6';
  613.  
  614.   Inc(X, BW+M1);
  615.   cButtons[ccMul].Position := Rect(X, Y, X+BW, Y+BH);
  616.   cButtons[ccMul].Caption := '*';
  617.  
  618.   Inc(X, BW+M1);
  619.   cButtons[ccPercent].Position := Rect(X, Y, X+BW, Y+BH);
  620.   cButtons[ccPercent].Caption := '%';
  621.  
  622.   {row 4}
  623.   Y := TM + 3*BH + 3*M1;
  624.   if FShowMemoryButtons then
  625.     X := M2 + BW + M4
  626.   else
  627.     X := M2;
  628.   cButtons[cc1].Position := Rect(X, Y, X+BW, Y+BH);
  629.   cButtons[cc1].Caption := '1';
  630.  
  631.   Inc(X, BW+M1);
  632.   cButtons[cc2].Position := Rect(X, Y, X+BW, Y+BH);
  633.   cButtons[cc2].Caption := '2';
  634.  
  635.   Inc(X, BW+M1);
  636.   cButtons[cc3].Position := Rect(X, Y, X+BW, Y+BH);
  637.   cButtons[cc3].Caption := '3';
  638.  
  639.   Inc(X, BW+M1);
  640.   cButtons[ccSub].Position := Rect(X, Y, X+BW, Y+BH);
  641.   cButtons[ccSub].Caption := '-';
  642.  
  643.   Inc(X, BW+M1);
  644.   cButtons[ccInvert].Position := Rect(X, Y, X+BW, Y+BH);
  645.   cButtons[ccInvert].Caption := '1/x';
  646.  
  647.   {row 5}
  648.   Y := TM + 4*BH + 4*M1;
  649.   if FShowMemoryButtons then
  650.     X := M2 + BW + M4
  651.   else
  652.     X := M2;
  653.   cButtons[cc0].Position := Rect(X, Y, X+BW, Y+BH);
  654.   cButtons[cc0].Caption := '0';
  655.  
  656.   Inc(X, BW+M1);
  657.   cButtons[ccChangeSign].Position := Rect(X, Y, X+BW, Y+BH);
  658.   cButtons[ccChangeSign].Caption := '+/-';
  659.  
  660.   Inc(X, BW+M1);
  661.   cButtons[ccDecimal].Position := Rect(X, Y, X+BW, Y+BH);
  662.   cButtons[ccDecimal].Caption := DecimalSeparator;
  663.  
  664.   Inc(X, BW+M1);
  665.   cButtons[ccAdd].Position := Rect(X, Y, X+BW, Y+BH);
  666.   cButtons[ccAdd].Caption := '+';
  667.  
  668.   Inc(X, BW+M1);
  669.   cButtons[ccEqual].Position := Rect(X, Y, X+BW, Y+BH);
  670.   cButtons[ccEqual].Caption := '=';
  671. end;
  672.  
  673. procedure TEsCustomCalculator.cColorChange(Sender : TObject);
  674. begin
  675.   {update panel background color}
  676.   if Assigned(cPanel) then begin
  677.     cPanel.Color := FColors.Display;
  678.     cPanel.Font.Color := FColors.DisplayText;
  679.     {update the main font color}
  680.     if not (csLoading in ComponentState) and (Font <> nil) then
  681.       Font.Color := FColors.DisplayText;
  682.   end;
  683.  
  684.   Invalidate;
  685. end;
  686.  
  687. procedure TEsCustomCalculator.cDisplayError;
  688. begin
  689.   cPanel.Caption := '****** ';
  690.   cState := [csLocked]; {user will have to clear this}
  691.   MessageBeep(0);
  692. end;
  693.  
  694. procedure TEsCustomCalculator.cDisplayValue(const Value : Extended);
  695. begin
  696.   try
  697.     if cPanel.HandleAllocated then
  698.       cPanel.Caption := Format('%g',[Value]) + ' ';
  699.   except
  700.     cDisplayError;
  701.   end;
  702. end;
  703.  
  704. procedure TEsCustomCalculator.cClearAll;
  705. begin
  706.   cDisplay := 0;
  707.   cOperand := 0;
  708.   cOperation := ccEqual;
  709.   cDisplayStr := '0';
  710.   cDisplayValue(cDisplay);
  711.   cState := [csValid, csClear];
  712. end;
  713.  
  714. procedure TEsCustomCalculator.cDrawCalcButton(Button : TEsButtonInfo; Pressed : Boolean);
  715. var
  716.   TR  : TRect;
  717.   Buf : array[0..255] of Char;
  718. begin
  719.   if Button.Visible then begin
  720.     TR := DrawButtonFace(Canvas, Button.Position, 1, bsNew, False, Pressed, False);
  721.     StrPLCopy(Buf, Button.Caption, 255);
  722.     DrawText(Canvas.Handle, Buf, Length(Button.Caption), TR, DT_CENTER or DT_VCENTER or DT_SINGLELINE);
  723.  
  724.     if Focused and (Button.Caption = '=') then
  725.       cDrawFocusState;
  726.   end;
  727. end;
  728.  
  729. procedure TEsCustomCalculator.cDrawFocusState;
  730. var
  731.   R : TRect;
  732. begin
  733.   R := cButtons[ccEqual].Position;
  734.   InflateRect(R, -3, -3);
  735.   Canvas.DrawFocusRect(R);
  736. end;
  737.  
  738. procedure TEsCustomCalculator.cEvaluate;
  739. begin
  740.   if csValid in cState then begin
  741.     try
  742.       {evaluate the expression}
  743.       case cOperation of
  744.         ccAdd : cDisplay := cDisplay + cOperand;
  745.         ccSub : cDisplay := cDisplay - cOperand;
  746.         ccMul : cDisplay := cDisplay * cOperand;
  747.         ccDiv : cDisplay := cDisplay / cOperand;
  748.         ccEqual : cDisplay := cOperand;
  749.       end;
  750.       cDisplayValue(cDisplay);
  751.       cDisplayStr := '0';
  752.       cOperand := 0;
  753.     except
  754.       cDisplayError;
  755.     end;
  756.   end;
  757. end;
  758.  
  759. procedure TEsCustomCalculator.cInvalidateIndicator;
  760. begin
  761.   InvalidateRect(Handle, @cButtons[ccMemRecall].Position, False);
  762.   InvalidateRect(Handle, @cButtons[ccMemClear].Position, False);
  763. end;
  764.  
  765. procedure TEsCustomCalculator.CMCtl3DChanged(var Msg : TMessage);
  766. begin
  767.   inherited;
  768.  
  769.   if (csLoading in ComponentState) or not HandleAllocated then
  770.     Exit;
  771.  
  772.   {$IFDEF Win32}
  773.   if NewStyleControls and (FBorderStyle = bsSingle) then
  774.     RecreateWnd;
  775.   {$ENDIF}
  776.  
  777.   Invalidate;
  778. end;
  779.  
  780. procedure TEsCustomCalculator.CMEnter(var Msg : TMessage);
  781. var
  782.   R : TRect;
  783. begin
  784.   inherited;
  785.  
  786.   {invalidate the "=" button to ensure that the focus rect is painted}
  787.   R := cButtons[ccEqual].Position;
  788.   InvalidateRect(Handle, @R, False);
  789. end;
  790.  
  791. procedure TEsCustomCalculator.CMExit(var Msg : TMessage);
  792. var
  793.   R : TRect;
  794. begin
  795.   inherited;
  796.  
  797.   {invalidate the "=" button to ensure that the focus rect is painted}
  798.   R := cButtons[ccEqual].Position;
  799.   InvalidateRect(Handle, @R, False);
  800. end;
  801.  
  802. procedure TEsCustomCalculator.CMFontChanged(var Msg : TMessage);
  803. begin
  804.   inherited;
  805.  
  806.   if not (csLoading in ComponentState) and Assigned(cPanel) then begin
  807.     cPanel.Color := FColors.Display;
  808.     cPanel.Font.Color := FColors.DisplayText;
  809.     FColors.FCalcColors[2] := Font.Color;
  810.   end;
  811.  
  812.   cCalculateLook;
  813.   Invalidate;
  814. end;
  815.  
  816. procedure TEsCustomCalculator.CopyToClipboard;
  817. begin
  818.   Clipboard.AsText := Text;
  819. end;
  820.  
  821. constructor TEsCustomCalculator.Create(AOwner : TComponent);
  822. {$IFDEF TRIALRUN}
  823. var
  824.   X : Integer;
  825. {$ENDIF}
  826. begin
  827.   inherited Create(AOwner);
  828.  
  829.   if cPopup then
  830.     ControlStyle := ControlStyle + [csClickEvents, csFramed] - [csCaptureMouse]
  831.   else
  832.     ControlStyle := ControlStyle + [csClickEvents, csFramed, csCaptureMouse];
  833.  
  834.   Color      := calcDefColor;
  835.   Height     := calcDefHeight;
  836.   TabStop    := calcDefTabStop;
  837.   Width      := calcDefWidth;
  838.  
  839.   {create edit control}
  840.   cPanel := TEsCalcPanel.Create(Self);
  841.   cPanel.Parent := Self;
  842.   cPanel.ParentFont := True;
  843.   cPanel.ParentCtl3D := True;
  844.   cPanel.Alignment := taRightJustify;
  845.   cPanel.BevelOuter := bvLowered;
  846.   cPanel.BorderStyle := bsNone;
  847.   cPanel.Color := clWindow;
  848.   cPanel.BevelWidth := 2;
  849.   cPanel.Caption := '0 ';
  850.  
  851.   {set property defaults}
  852.   FBorderStyle       := calcDefBorderStyle;
  853.   FShowMemoryButtons := calcDefShowMemoryButtons;
  854.  
  855.   FColors := TEsCalcColors.Create;
  856.   FColors.OnChange := cColorChange;
  857.  
  858.   {assign default color scheme}
  859.   FColors.FCalcColors := CalcScheme[csWindows];
  860.  
  861.   cLastButton := ccEqual;
  862.  
  863. {$IFDEF TRIALRUN}
  864.   X := _CC_;
  865.   if (X < ccRangeLow) or (X > ccRangeHigh) then Halt;
  866.   X := _VC_;
  867.   if (X < ccRangeLow) or (X > ccRangeHigh) then Halt;
  868. {$ENDIF}
  869. end;
  870.  
  871. constructor TEsCustomCalculator.CreateEx(AOwner : TComponent; AsPopup : Boolean);
  872. begin
  873.   cPopup := AsPopup;
  874.   Create(AOwner);
  875. end;
  876.  
  877. procedure TEsCustomCalculator.CreateParams(var Params : TCreateParams);
  878. const
  879.   BorderStyles : array[TBorderStyle] of DWord = (0, WS_BORDER);        {!!.05}
  880. begin
  881.   inherited CreateParams(Params);
  882.  
  883.   with Params do begin
  884.     Style := Style or BorderStyles[FBorderStyle];
  885.     {!!.02} {block revised}
  886.     if cPopup then begin
  887.       Style := WS_POPUP or WS_BORDER;
  888.       WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
  889.       {$IFDEF Win32}
  890.       Ctl3D := False;
  891.       if NewStyleControls then
  892.         ExStyle := WS_EX_TOOLWINDOW or WS_EX_CLIENTEDGE;
  893.       {$ENDIF Win32}
  894.     end;
  895.   end;
  896.  
  897.   {$IFDEF Win32}
  898.   if NewStyleControls and Ctl3D and (FBorderStyle = bsSingle) then begin
  899.     Params.Style := Params.Style and not WS_BORDER;
  900.     Params.ExStyle := Params.ExStyle or WS_EX_CLIENTEDGE;
  901.   end;
  902.   {$ENDIF}
  903. end;
  904.  
  905. procedure TEsCustomCalculator.CreateWnd;
  906. begin
  907.   inherited CreateWnd;
  908.  
  909.   cCalculateLook;
  910.   cClearAll;
  911.  
  912.   cPanel.Color := FColors.Display;
  913. end;
  914.  
  915. destructor TEsCustomCalculator.Destroy;
  916. begin
  917.   cPanel.Free;
  918.   cPanel := nil;
  919.  
  920.   FColors.Free;
  921.   FColors := nil;
  922.  
  923.   inherited Destroy;
  924. end;
  925.  
  926. procedure TEsCustomCalculator.KeyDown(var Key : Word; Shift : TShiftState);
  927. begin
  928.   inherited KeyDown(Key, Shift);
  929.  
  930.   case Key of
  931.     VK_DELETE : if Shift = [] then
  932.                   PressButton(ccClearEntry);
  933.     VK_F9     : if Shift = [] then
  934.                   PressButton(ccChangeSign);
  935.   end;
  936. end;
  937.  
  938. procedure TEsCustomCalculator.KeyPress(var Key : Char);
  939. begin
  940.   inherited KeyPress(Key);
  941.  
  942.   case Key of
  943.     '0' : PressButton(cc0);
  944.     '1' : PressButton(cc1);
  945.     '2' : PressButton(cc2);
  946.     '3' : PressButton(cc3);
  947.     '4' : PressButton(cc4);
  948.     '5' : PressButton(cc5);
  949.     '6' : PressButton(cc6);
  950.     '7' : PressButton(cc7);
  951.     '8' : PressButton(cc8);
  952.     '9' : PressButton(cc9);
  953.  
  954.     '+' : PressButton(ccAdd);
  955.     '-' : PressButton(ccSub);
  956.     '*' : PressButton(ccMul);
  957.     '/' : PressButton(ccDiv);
  958.  
  959.     '.' : PressButton(ccDecimal);
  960.     '=' : PressButton(ccEqual);
  961.     'r' : PressButton(ccInvert);
  962.     '%' : PressButton(ccPercent);
  963.     '@' : PressButton(ccSqrt);
  964.  
  965.     ^L  : PressButton(ccMemClear);  {^L}
  966.     ^R  : PressButton(ccMemRecall); {^R}
  967.     ^P  : PressButton(ccMemAdd);    {^P}
  968.     ^S  : PressButton(ccMemSub);    {^S}
  969.  
  970.     ^C  : CopyToClipboard;          {^C}{copy}
  971.     ^V  : PasteFromClipboard;       {^V}{paste}
  972.  
  973.     #8  : PressButton(ccBack);      {backspace}
  974.     #27 : PressButton(ccClear);     {esc}
  975.   else
  976.     if Key = DecimalSeparator then
  977.       PressButton(ccDecimal);
  978.   end;
  979. end;
  980.  
  981. procedure TEsCustomCalculator.MouseDown(Button : TMouseButton; Shift : TShiftState; X, Y : Integer);
  982. var
  983.   B : TEsCalculatorButton;
  984. begin
  985.   SetFocus;
  986.  
  987.   if Button = mbLeft then begin
  988.     cDownButton := ccNone;
  989.     for B := Low(cButtons) to High(cButtons) do
  990.       if PtInRect(cButtons[B].Position, Point(X,Y)) then begin
  991.         if (B in [ccMemClear, ccMemRecall]) and (cMemory = 0) then
  992.           Exit;
  993.         cDownButton := B;
  994.         InvalidateRect(Handle, @cButtons[cDownButton].Position, False);
  995.         Break;
  996.       end;
  997.   end;
  998.  
  999.   inherited MouseDown(Button, Shift, X, Y);
  1000. end;
  1001.  
  1002. procedure TEsCustomCalculator.MouseUp(Button : TMouseButton; Shift : TShiftState; X, Y : Integer);
  1003. begin
  1004.   if cDownButton = ccNone then
  1005.     Exit;
  1006.  
  1007.   InvalidateRect(Handle, @cButtons[cDownButton].Position, False);
  1008.  
  1009.   {if still over the button...}
  1010.   if PtInRect(cButtons[cDownButton].Position, Point(X,Y)) then
  1011.     PressButton(cDownButton);
  1012.  
  1013.   cDownButton := ccNone;
  1014.  
  1015.   inherited MouseUp(Button, Shift, X, Y);
  1016. end;
  1017.  
  1018. procedure TEsCustomCalculator.PasteFromClipboard;
  1019. var
  1020.   I : Integer;
  1021.   C : AnsiChar;
  1022.   S : string;
  1023. begin
  1024.   S := Clipboard.AsText;
  1025.   if S > '' then begin
  1026.     cClearAll;
  1027.     for I := 1 to Length(S) do begin
  1028.       C := S[I];
  1029.       if (C in ['0'..'9', DecimalSeparator, '.', '+', '-', '*', '/', '=', '%']) then
  1030.         KeyPress(C);
  1031.     end;
  1032.   end;
  1033. end;
  1034.  
  1035. {!!.03} {revised}
  1036. procedure TEsCustomCalculator.PressButton(Button : TEsCalculatorButton);
  1037. var
  1038.   Ch   : AnsiChar;
  1039.   Sign : Integer;
  1040.   D    : Extended;
  1041. begin
  1042.   if not HandleAllocated then
  1043.     Exit;
  1044.  
  1045.   {simulate a button down if needed}
  1046.   if cDownButton = ccNone then begin
  1047.     cDownButton := Button;
  1048.     InvalidateRect(Handle, @cButtons[cDownButton].Position, False);
  1049.     Update;
  1050.   end;
  1051.  
  1052.   try
  1053.     case Button of
  1054.       ccClear :
  1055.         begin
  1056.           cClearAll;
  1057.           cDisplayValue(cDisplay);
  1058.         end;
  1059.     end;
  1060.  
  1061.     if (csLocked in cState) then begin
  1062.       MessageBeep(0);
  1063.       Exit;
  1064.     end;
  1065.  
  1066.     case Button of
  1067.       cc0..cc9 :
  1068.         begin
  1069.           if cLastButton = ccEqual then begin
  1070.             {clear pending operations if last command was =}
  1071.             cClearAll;
  1072.           end;
  1073.  
  1074.           if csClear in cState then
  1075.             cDisplayStr := '';
  1076.  
  1077.           cLastButton := Button;
  1078.  
  1079.           Ch := cButtons[Button].Caption[1];
  1080.           if cOperand < 0 then
  1081.             Sign := -1
  1082.           else
  1083.             Sign := 1;
  1084.           cDisplayStr := cDisplayStr + Ch;
  1085.  
  1086.           try
  1087.             D := StrToFloat(cDisplayStr) * Sign;
  1088.             cOperand := D;
  1089.             if (D <> 0) or
  1090.                (Pos(DecimalSeparator, cDisplayStr) > 0) then begin
  1091.               cPanel.Caption := cDisplayStr + ' ';
  1092.               cState := [csValid];
  1093.             end else begin
  1094.               cDisplayStr := '0';
  1095.               cDisplayValue(D);
  1096.               cState := [csValid, csClear];
  1097.             end;
  1098.           except
  1099.             cDisplayError;
  1100.           end;
  1101.         end;
  1102.       ccDecimal :
  1103.         {check if there is already a decimal separator in the string}
  1104.         if Pos(DecimalSeparator, cDisplayStr) = 0 then begin
  1105.           try
  1106.             cDisplayStr := cDisplayStr + DecimalSeparator;
  1107.             D := StrToFloat(cDisplayStr);
  1108.             cPanel.Caption := cDisplayStr + ' ';
  1109.             cOperand := D;
  1110.             cState := [csValid];
  1111.           except
  1112.             cDisplayError;
  1113.           end;
  1114.         end;
  1115.       ccAdd,
  1116.       ccSub,
  1117.       ccMul,
  1118.       ccDiv :
  1119.         begin
  1120.           cEvaluate;
  1121.           cState := [csValid, csClear];
  1122.           cOperation := Button;
  1123.         end;
  1124.       ccEqual :
  1125.         begin
  1126.           cEvaluate;
  1127.           cOperand := cDisplay;
  1128.           cState := [csValid];
  1129.           cOperation := ccEqual;
  1130.         end;
  1131.       ccBack :
  1132.         try
  1133.           if Length(cDisplayStr) > 1 then begin
  1134.             cDisplayStr := Copy(cDisplayStr, 1, Length(cDisplayStr)-1);
  1135.             cOperand := StrToFloat(cDisplayStr);
  1136.             cPanel.Caption := cDisplayStr + ' ';
  1137.           end else begin
  1138.             cOperand := 0;
  1139.             cDisplayValue(cOperand);
  1140.             cState := [csValid, csClear];
  1141.           end;
  1142.         except
  1143.           cDisplayError;
  1144.         end;
  1145.       ccClearEntry :
  1146.         begin
  1147.           cDisplayStr := '';
  1148.           cOperand := 0;
  1149.           cDisplayValue(cOperand);
  1150.         end;
  1151.       ccMemStore :
  1152.         begin
  1153.           if (cMemory = 0) and (cOperand <> 0) then
  1154.             cInvalidateIndicator;
  1155.           cMemory := cOperand;
  1156.           Include(cState, csClear);
  1157.         end;
  1158.       ccMemRecall :
  1159.         begin
  1160.           cOperand := cMemory;
  1161.           cDisplayValue(cOperand);
  1162.           cState := [csValid, csClear];
  1163.         end;
  1164.       ccMemClear :
  1165.         begin
  1166.           if cMemory <> 0 then
  1167.             cInvalidateIndicator;
  1168.           cMemory := 0;
  1169.         end;
  1170.       ccMemAdd,
  1171.       ccMemSub :
  1172.         begin
  1173.           D := cMemory;
  1174.           try
  1175.             if Button = ccMemAdd then
  1176.               cMemory := cMemory + cOperand
  1177.             else
  1178.               cMemory := cMemory - cOperand;
  1179.           except
  1180.             cDisplayError;
  1181.             cMemory := 0;
  1182.           end;
  1183.           if ((D = 0) and (cMemory <> 0)) or
  1184.              ((D <> 0) and (cMemory = 0)) then
  1185.           cInvalidateIndicator;
  1186.           Include(cState, csClear);
  1187.         end;
  1188.       ccChangeSign :
  1189.         try
  1190.           cOperand := -cOperand;
  1191.           cDisplayValue(cOperand);
  1192.         except
  1193.           cDisplayError;
  1194.         end;
  1195.       ccInvert :
  1196.         try
  1197.           cDisplayStr := '';
  1198.           cOperand := 1 / cOperand;
  1199.           cDisplayValue(cOperand);
  1200.         except
  1201.           cDisplayError;
  1202.         end;
  1203.       ccPercent :
  1204.         try
  1205.           if cOperation in [ccAdd, ccSub] then
  1206.             cOperand := (cOperand / 100) * cDisplay  {do markup/down}
  1207.           else
  1208.             cOperand := cOperand / 100;              {as a percentage}
  1209.           cEvaluate;
  1210.           cOperand := cDisplay;
  1211.           cState := [csValid, csClear];
  1212.           cOperation := ccEqual;
  1213.         except
  1214.           cDisplayError;
  1215.         end;
  1216.       ccSqrt :
  1217.         try
  1218.           cOperand := Sqrt(cOperand);
  1219.           cDisplayValue(cOperand);
  1220.         except
  1221.           cDisplayError;
  1222.         end;
  1223.     end;
  1224.   finally
  1225.     {record button press}
  1226.     cLastButton := Button;
  1227.  
  1228.     {simulate a button up, if the mouse button is up or we aren't focused}
  1229.     if not Focused or (GetAsyncKeyState(GetLeftButton) and $8000 = 0) then begin
  1230.       InvalidateRect(Handle, @cButtons[cDownButton].Position, False);
  1231.       cDownButton := ccNone;
  1232.       Update;
  1233.     end;
  1234.   end;
  1235.  
  1236.   if Assigned(FOnButtonPressed) then
  1237.     FOnButtonPressed(Self, Button);
  1238. end;
  1239.  
  1240. procedure TEsCustomCalculator.Paint;
  1241. var
  1242.   B  : TEsCalculatorButton;
  1243. begin
  1244.   Canvas.Font := Font;
  1245.   Canvas.Brush.Color := calcDefColor;
  1246.   Canvas.FillRect(ClientRect);
  1247.  
  1248.   if Ctl3D then begin
  1249.     cPanel.BevelOuter := bvLowered;
  1250.     cPanel.BorderStyle := bsNone;
  1251.   end else begin
  1252.     cPanel.BevelOuter := bvNone;
  1253.   cPanel.BorderStyle := bsSingle;
  1254.   end;
  1255.  
  1256.   {draw buttons}
  1257.   for B := Low(cButtons) to High(cButtons) do begin
  1258.     if (B in [ccMemClear, ccMemRecall, ccMemStore, ccMemAdd, ccMemSub]) then begin
  1259.       if (B in [ccMemClear, ccMemRecall]) and (cMemory = 0) then
  1260.         Canvas.Font.Color := FColors.DisabledMemoryButtons
  1261.       else
  1262.         Canvas.Font.Color := FColors.MemoryButtons;
  1263.     end else if (B in [ccBack, ccClearEntry, ccClear]) then
  1264.       Canvas.Font.Color := FColors.EditButtons
  1265.     else if (B in [ccAdd, ccSub, ccMul, ccDiv, ccEqual]) then
  1266.       Canvas.Font.Color := FColors.OperatorButtons
  1267.     else if (B in [cc0..cc9, ccDecimal]) then
  1268.       Canvas.Font.Color := FColors.NumberButtons
  1269.     else if (B in [ccInvert, ccChangeSign, ccPercent, ccSqrt]) then
  1270.       Canvas.Font.Color := FColors.FunctionButtons;
  1271.  
  1272.     cDrawCalcButton(cButtons[B], (B = cDownButton));
  1273.   end;
  1274. end;
  1275.  
  1276. procedure TEsCustomCalculator.SetBorderStyle(Value : TBorderStyle);
  1277. begin
  1278.   if Value <> FBorderStyle then begin
  1279.     FBorderStyle := Value;
  1280.     RecreateWnd;
  1281.   end;
  1282. end;
  1283.  
  1284. procedure TEsCustomCalculator.SetBounds(ALeft, ATop, AWidth, AHeight : Integer);
  1285. begin
  1286.   inherited Setbounds(ALeft, ATop, AWidth, AHeight);
  1287.  
  1288.   cCalculateLook;
  1289. end;
  1290.  
  1291. procedure TEsCustomCalculator.SetShowMemoryButtons(Value : Boolean);
  1292. begin
  1293.   if Value <> FShowMemoryButtons then begin
  1294.     FShowMemoryButtons := Value;
  1295.     cCalculateLook;
  1296.     Invalidate;
  1297.   end;
  1298. end;
  1299.  
  1300. procedure TEsCustomCalculator.WMEraseBkgnd(var Msg : TWMEraseBkgnd);
  1301. begin
  1302.   Msg.Result := 1;   {don't erase background, just say we did}
  1303. end;
  1304.  
  1305. procedure TEsCustomCalculator.WMGetText(var Msg : TWMGetText);
  1306. begin
  1307.   if not cPanel.HandleAllocated then
  1308.     Exit;
  1309.  
  1310.   Msg.Result := SendMessage(cPanel.Handle, WM_GETTEXT,
  1311.     TMessage(Msg).wParam, TMessage(Msg).lParam);
  1312. end;
  1313.  
  1314. procedure TEsCustomCalculator.WMGetTextLength(var Msg : TWMGetTextLength);
  1315. begin
  1316.   if not cPanel.HandleAllocated then
  1317.     Exit;
  1318.  
  1319.   Msg.Result := SendMessage(cPanel.Handle, WM_GETTEXTLENGTH,
  1320.     TMessage(Msg).wParam, TMessage(Msg).lParam);
  1321. end;
  1322.  
  1323. procedure TEsCustomCalculator.WMKeyDown(var Msg : TWMKeyDown);
  1324. begin
  1325.   if Msg.CharCode = Ord('M') then begin
  1326.     if (GetAsyncKeyState(VK_CONTROL) and $8000) <> 0 then begin
  1327.       PressButton(ccMemStore);
  1328.     end;
  1329.   end else if Msg.CharCode = VK_RETURN then
  1330.     PressButton(ccEqual);
  1331.  
  1332.   inherited;
  1333. end;
  1334.  
  1335. procedure TEsCustomCalculator.WMSetText(var Msg : TWMSetText);
  1336. var
  1337.   I : Integer;
  1338.   C : AnsiChar;
  1339. begin
  1340.   cClearAll;
  1341.   for I := 0 to Pred(StrLen(Msg.Text)) do begin
  1342.     C := Msg.Text[I];
  1343.     KeyPress(C);
  1344.   end;
  1345.   Msg.Result := 1{true};
  1346. end;
  1347.  
  1348. end.
  1349.