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

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************************}
  2. {                                                                   }
  3. {       Almediadev Visual Component Library                         }
  4. {       BusinessSkinForm                                            }
  5. {       Version 1.98                                                }
  6. {                                                                   }
  7. {       Copyright (c) 2000-2003 Almediadev                          }
  8. {       ALL RIGHTS RESERVED                                         }
  9. {                                                                   }
  10. {       Home:  http://www.almdev.com                                }
  11. {       Support: support@almdev.com                                 }
  12. {                                                                   }
  13. {*******************************************************************}
  14. unit bscalc;
  15. interface
  16. uses Windows, SysUtils, {$IFDEF VER 140}Variants,{$ENDIF}
  17.      {$IFDEF VER 150}Variants,{$ENDIF}
  18.   Messages, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Menus,
  19.   ExtCtrls, Buttons, bsSkinCtrls, Clipbrd, BusinessSkinForm, bsSkinData,
  20.   bsSkinBoxCtrls;
  21. const
  22.   DefCalcPrecision = 15;
  23. type
  24.   TbsCalcState = (csFirst, csValid, csError);
  25.   TbsCalculatorForm = class;
  26. { TbsSkinCalculator }
  27.   TbsSkinCalculator = class(TComponent)
  28.   private
  29.     FAlphaBlend: Boolean;
  30.     FAlphaBlendAnimation: Boolean;
  31.     FAlphaBlendValue: Byte;
  32.     FSD: TbsSkinData;
  33.     FCtrlFSD: TbsSkinData;
  34.     FButtonSkinDataName: String;
  35.     FDisplayLabelSkinDataName: String;
  36.     FDefaultFont: TFont;
  37.     FValue: Double;
  38.     FTitle: String;
  39.     FMemory: Double;
  40.     FPrecision: Byte;
  41.     FBeepOnError: Boolean;
  42.     FHelpContext: THelpContext;
  43.     FCalc: TbsCalculatorForm;
  44.     FOnChange: TNotifyEvent;
  45.     FOnCalcKey: TKeyPressEvent;
  46.     FOnDisplayChange: TNotifyEvent;
  47.     function GetDisplay: Double;
  48.     function GetTitle: string;
  49.     procedure SetTitle(const Value: string);
  50.     procedure SetDefaultFont(Value: TFont);
  51.     function TitleStored: Boolean;
  52.   protected
  53.     procedure Change; dynamic;
  54.     procedure CalcKey(var Key: Char); dynamic;
  55.     procedure DisplayChange; dynamic;
  56.     procedure Notification(AComponent: TComponent;  Operation: TOperation); override;
  57.   public
  58.     constructor Create(AOwner: TComponent); override;
  59.     destructor Destroy; override;
  60.     function Execute: Boolean;
  61.     property CalcDisplay: Double read GetDisplay;
  62.     property Memory: Double read FMemory;
  63.   published
  64.     property AlphaBlend: Boolean read FAlphaBlend write FAlphaBlend;
  65.     property AlphaBlendAnimation: Boolean
  66.       read FAlphaBlendAnimation write FAlphaBlendAnimation;
  67.     property AlphaBlendValue: Byte read FAlphaBlendValue write FAlphaBlendValue;
  68.     property SkinData: TbsSkinData read FSD write FSD;
  69.     property CtrlSkinData: TbsSkinData read FCtrlFSD write FCtrlFSD;
  70.     property ButtonSkinDataName: String
  71.       read FButtonSkinDataName write FButtonSkinDataName;
  72.     property DisplayLabelSkinDataName: String
  73.       read FDisplayLabelSkinDataName write FDisplayLabelSkinDataName;
  74.     property DefaultFont: TFont read FDefaultFont write SetDefaultFont;  
  75.     property BeepOnError: Boolean read FBeepOnError write FBeepOnError default True;
  76.     property HelpContext: THelpContext read FHelpContext write FHelpContext default 0;
  77.     property Precision: Byte read FPrecision write FPrecision default DefCalcPrecision;
  78.     property Title: string read GetTitle write SetTitle stored TitleStored;
  79.     property Value: Double read FValue write FValue;
  80.     property OnCalcKey: TKeyPressEvent read FOnCalcKey write FOnCalcKey;
  81.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  82.     property OnDisplayChange: TNotifyEvent read FOnDisplayChange write FOnDisplayChange;
  83.   end;
  84. { TbsCalculatorForm }
  85.   TbsCalculatorForm = class(TForm)
  86.   private
  87.     FPasteItem: TMenuItem;
  88.     procedure FormKeyPress(Sender: TObject; var Key: Char);
  89.     procedure PopupMenuPopup(Sender: TObject);
  90.     procedure CopyItemClick(Sender: TObject);
  91.     procedure PasteItemClick(Sender: TObject);
  92.   protected
  93.     procedure OkClick(Sender: TObject);
  94.     procedure CancelClick(Sender: TObject);
  95.     procedure CalcKey(Sender: TObject; var Key: Char);
  96.     procedure DisplayChange(Sender: TObject);
  97.   public
  98.     BSF: TbsBusinessSkinForm;
  99.     FCalcPanel: TbsSkinPanel;
  100.     FDisplayLabel: TbsSkinLabel;
  101.     constructor Create(AOwner: TComponent); override;
  102.   end;
  103.   TbsSkinCalcEdit = class;
  104.   TbsPopupCalculatorForm = class(TbsSkinPanel)
  105.   protected
  106.     procedure WMMouseActivate(var Message: TMessage); message WM_MOUSEACTIVATE;
  107.     procedure CreateParams(var Params: TCreateParams); override;
  108.     procedure OkClick(Sender: TObject);
  109.     procedure CancelClick(Sender: TObject);
  110.   public
  111.     CalcEdit: TbsSkinCalcEdit;
  112.     FCalcPanel: TbsSkinPanel;
  113.     FDisplayLabel: TbsSkinLabel;
  114.     constructor Create(AOwner: TComponent); override;
  115.     destructor Destroy; override;
  116.     procedure Show(X, Y: Integer);
  117.     procedure Hide;
  118.   end;
  119.   TbsSkinCalcEdit = class(TbsSkinCustomEdit)
  120.   private
  121.     FMemory: Double;
  122.     FPrecision: Byte;
  123.     FCalc: TbsPopupCalculatorForm;
  124.     StopCheck: Boolean;
  125.     FDecimal: Byte;
  126.     FMinValue, FMaxValue, FIncrement: Double;
  127.     FValueType: TbsValueType;
  128.     FValue: Double;
  129.     FCalcButtonSkinDataName: String;
  130.     FCalcDisplayLabelSkinDataName: String;
  131.     FAlphaBlend: Boolean;
  132.     FAlphaBlendAnimation: Boolean;
  133.     FAlphaBlendValue: Byte;
  134.     procedure SetValue(AValue: Double);
  135.     procedure SetMinValue(AValue: Double);
  136.     procedure SetMaxValue(AValue: Double);
  137.     procedure SetValueType(NewType: TbsValueType);
  138.     procedure SetDecimal(NewValue: Byte);
  139.     procedure ButtonClick(Sender: TObject);
  140.     procedure DropDown;
  141.     procedure CloseUp;
  142.   protected
  143.     function CheckValue(NewValue: Double): Double;
  144.     procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
  145.     procedure CMCancelMode(var Message: TCMCancelMode); message CM_CANCELMODE;
  146.     procedure KeyPress(var Key: Char); override;
  147.     function IsValidChar(Key: Char): Boolean;
  148.     procedure Change; override;
  149.     procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
  150.     property Text;
  151.   public
  152.     constructor Create(AOwner: TComponent); override;
  153.     destructor Destroy; override;
  154.     function IsNumText(AText: String): Boolean;
  155.     property Memory: Double read FMemory;
  156.   published
  157.     property AlphaBlend: Boolean read FAlphaBlend write FAlphaBlend;
  158.     property AlphaBlendAnimation: Boolean
  159.       read FAlphaBlendAnimation write FAlphaBlendAnimation;
  160.     property AlphaBlendValue: Byte read FAlphaBlendValue write FAlphaBlendValue;
  161.     property CalcButtonSkinDataName: String
  162.       read FCalcButtonSkinDataName
  163.       write FCalcButtonSkinDataName;
  164.     property CalcDisplayLabelSkinDataName: String
  165.       read FCalcDisplayLabelSkinDataName
  166.       write FCalcDisplayLabelSkinDataName;
  167.     property Precision: Byte read FPrecision write FPrecision default DefCalcPrecision;
  168.     property ValueType: TbsValueType read FValueType write SetValueType;
  169.     property Decimal: Byte read FDecimal write SetDecimal default 2;
  170.      property Align;
  171.     property MinValue: Double read FMinValue write SetMinValue;
  172.     property MaxValue: Double read FMaxValue write SetMaxValue;
  173.     property Value: Double read FValue write SetValue;
  174.     property Increment: Double read FIncrement write FIncrement;
  175.         property DefaultFont;
  176.     property DefaultWidth;
  177.     property DefaultHeight;
  178.     property ButtonMode;
  179.     property SkinData;
  180.     property SkinDataName;
  181.     property EditPasswordChar;
  182.     property OnMouseEnter;
  183.     property OnMouseLeave;
  184.     property ReadOnly;
  185.     property Font;
  186.     property Anchors;
  187.     property AutoSelect;
  188.     property BiDiMode;
  189.     property CharCase;
  190.     property Constraints;
  191.     property DragCursor;
  192.     property DragKind;
  193.     property DragMode;
  194.     property Enabled;
  195.     property HideSelection;
  196.     property ImeMode;
  197.     property ImeName;
  198.     property MaxLength;
  199.     property OEMConvert;
  200.     property ParentBiDiMode;
  201.     property ParentColor;
  202.     property ParentCtl3D;
  203.     property ParentFont;
  204.     property ParentShowHint;
  205.     property PopupMenu;
  206.     property ShowHint;
  207.     property TabOrder;
  208.     property TabStop;
  209.     property Visible;
  210.     property OnButtonClick;
  211.     property OnChange;
  212.     property OnClick;
  213.     property OnDblClick;
  214.     property OnDragDrop;
  215.     property OnDragOver;
  216.     property OnEndDock;
  217.     property OnEndDrag;
  218.     property OnEnter;
  219.     property OnExit;
  220.     property OnKeyDown;
  221.     property OnKeyPress;
  222.     property OnKeyUp;
  223.     property OnMouseDown;
  224.     property OnMouseMove;
  225.     property OnMouseUp;
  226.     property OnStartDock;
  227.     property OnStartDrag;
  228.   end;
  229. function CreateCalculatorForm(AOwner: TComponent; AHelpContext: THelpContext): TbsCalculatorForm;
  230. implementation
  231.  {$R bscalc}
  232. uses bsUtils;
  233. const
  234.   SCalculator = 'Calculator';
  235.   SError = 'Error';
  236.   WS_EX_LAYERED = $80000;
  237.   
  238. type
  239.   TCalcBtnKind =
  240.    (cbNone, cbNum0, cbNum1, cbNum2, cbNum3, cbNum4, cbNum5, cbNum6,
  241.     cbNum7, cbNum8, cbNum9, cbSgn, cbDcm, cbDiv, cbMul, cbSub,
  242.     cbAdd, cbSqr, cbPcnt, cbRev, cbEql, cbBck, cbClr, cbMP,
  243.     cbMS, cbMR, cbMC, cbOk, cbCancel);
  244. function CreateCalculatorForm(AOwner: TComponent; AHelpContext: THelpContext): TbsCalculatorForm;
  245. begin
  246.   Result := TbsCalculatorForm.Create(AOwner);
  247.   with Result do
  248.   try
  249.     HelpContext := AHelpContext;
  250.     if HelpContext <> 0 then BorderIcons := BorderIcons + [biHelp];
  251.     if Screen.PixelsPerInch <> 96 then begin { scale to screen res }
  252.       ScaleBy(Screen.PixelsPerInch, 96);
  253.       Left := (Screen.Width div 2) - (Width div 2);
  254.       Top := (Screen.Height div 2) - (Height div 2);
  255.     end;
  256.   except
  257.     Free;
  258.     raise;
  259.   end;
  260. end;
  261. { TCalcButton }
  262. type
  263.   TCalcButton = class(TbsSkinSpeedButton)
  264.   private
  265.     FKind: TCalcBtnKind;
  266.   protected
  267.   public
  268.     constructor CreateKind(AOwner: TComponent; AKind: TCalcBtnKind);
  269.     property Kind: TCalcBtnKind read FKind;
  270.   end;
  271. constructor TCalcButton.CreateKind(AOwner: TComponent; AKind: TCalcBtnKind);
  272. begin
  273.   inherited Create(AOwner);
  274.   ControlStyle := ControlStyle + [csReplicatable];
  275.   FKind := AKind;
  276.   if FKind in [cbNum0..cbClr] then Tag := Ord(Kind) - 1
  277.   else Tag := -1;
  278. end;
  279. const
  280.   BtnPos: array[TCalcBtnKind] of TPoint =
  281.   ((X: -1; Y: -1), (X: 38; Y: 120), (X: 38; Y: 92), (X: 71; Y: 92),
  282.     (X: 104; Y: 92), (X: 38; Y: 64), (X: 71; Y: 64), (X: 104; Y: 64),
  283.     (X: 38; Y: 36), (X: 71; Y: 36), (X: 104; Y: 36), (X: 71; Y: 120),
  284.     (X: 104; Y: 120), (X: 137; Y: 36), (X: 137; Y: 64), (X: 137; Y: 92),
  285.     (X: 137; Y: 120), (X: 170; Y: 36), (X: 170; Y: 64), (X: 170; Y: 92),
  286.     (X: 170; Y: 120), (X: 104; Y: 6), (X: 154; Y: 6), (X: 5; Y: 120),
  287.     (X: 5; Y: 92), (X: 5; Y: 64), (X: 5; Y: 36),
  288.     (X: 38; Y: 6), (X: 71; Y: 6));
  289.    ResultKeys = [#13, '=', '%'];
  290. function CreateCalcBtn(AParent: TWinControl; AKind: TCalcBtnKind;
  291.   AOnClick: TNotifyEvent): TCalcButton;
  292. const
  293.   BtnCaptions: array[cbSgn..cbMC] of PChar =
  294.    ('+/-', ',', '/', '*', '-', '+', 'sqrt', '%', '1/x', '=', '<', 'C',
  295.     'MP', 'MS', 'MR', 'MC');
  296. begin
  297.   Result := TCalcButton.CreateKind(AParent, AKind);
  298.   with Result do
  299.   try
  300.     if Kind in [cbNum0..cbNum9] then Caption := IntToStr(Tag)
  301.     else if Kind = cbDcm then Caption := DecimalSeparator
  302.     else if Kind in [cbSgn..cbMC] then Caption := StrPas(BtnCaptions[Kind]);
  303.     Left := BtnPos[Kind].X;
  304.     Top := BtnPos[Kind].Y;
  305.     Width := 30;
  306.     Height := 22;
  307.     OnClick := AOnClick;
  308.     Parent := AParent;
  309.   except
  310.     Free;
  311.     raise;
  312.   end;
  313. end;
  314. { TCalculatorPanel }
  315. type
  316.   TCalculatorPanel = class(TbsSkinPanel)
  317.   private
  318.     FText: string;
  319.     FStatus: TbsCalcState;
  320.     FOperator: Char;
  321.     FOperand: Double;
  322.     FMemory: Double;
  323.     FPrecision: Byte;
  324.     FBeepOnError: Boolean;
  325.     FMemoryLabel: TbsSkinStdLabel;
  326.     FOnError: TNotifyEvent;
  327.     FOnOk: TNotifyEvent;
  328.     FOnCancel: TNotifyEvent;
  329.     FOnResult: TNotifyEvent;
  330.     FOnTextChange: TNotifyEvent;
  331.     FOnCalcKey: TKeyPressEvent;
  332.     FOnDisplayChange: TNotifyEvent;
  333.     FControl: TControl;
  334.     procedure SetText(const Value: string);
  335.     procedure CheckFirst;
  336.     procedure CalcKey(Key: Char);
  337.     procedure Clear;
  338.     procedure Error;
  339.     procedure SetDisplay(R: Double);
  340.     function GetDisplay: Double;
  341.     procedure UpdateMemoryLabel;
  342.     function FindButton(Key: Char): TbsSkinSpeedButton;
  343.     procedure BtnClick(Sender: TObject);
  344.   protected
  345.     procedure TextChanged; virtual;
  346.   public
  347.     constructor CreateLayout(AOwner: TComponent);
  348.     procedure CalcKeyPress(Sender: TObject; var Key: Char);
  349.     procedure Copy;
  350.     procedure Paste;
  351.     property DisplayValue: Double read GetDisplay write SetDisplay;
  352.     property Text: string read FText;
  353.     property OnOkClick: TNotifyEvent read FOnOk write FOnOk;
  354.     property OnCancelClick: TNotifyEvent read FOnCancel write FOnCancel;
  355.     property OnResultClick: TNotifyEvent read FOnResult write FOnResult;
  356.     property OnError: TNotifyEvent read FOnError write FOnError;
  357.     property OnTextChange: TNotifyEvent read FOnTextChange write FOnTextChange;
  358.     property OnCalcKey: TKeyPressEvent read FOnCalcKey write FOnCalcKey;
  359.     property OnDisplayChange: TNotifyEvent read FOnDisplayChange write FOnDisplayChange;
  360.   end;
  361. constructor TCalculatorPanel.CreateLayout(AOwner: TComponent);
  362. var
  363.   I: TCalcBtnKind;
  364. const
  365.     BtnCaptions: array[cbSgn..cbCancel] of PChar =
  366.     ('+/-', ',', '/', '*', '-', '+', '', '%', '1/x', '=', '', '',
  367.     'MP', 'MS', 'MR', 'MC', '', '');
  368. begin
  369.   inherited Create(AOwner);
  370.   Height := 150;
  371.   Width := 210;
  372.   try
  373.     for I := cbNum0 to cbCancel do begin
  374.       if BtnPos[I].X > 0 then
  375.         with CreateCalcBtn(Self, I, BtnClick) do
  376.         begin
  377.           NumGlyphs := 1;
  378.           case I of
  379.             cbSqr: Glyph.LoadFromResourceName(HInstance, 'BS_CALC_SQRT');
  380.             cbClr: Glyph.LoadFromResourceName(HInstance, 'BS_CALC_CLEAR');
  381.             cbBck: Glyph.LoadFromResourceName(HInstance, 'BS_CALC_BACKSPACE');
  382.             cbOK: Glyph.LoadFromResourceName(HInstance, 'BS_CALC_OK');
  383.             cbCancel: Glyph.LoadFromResourceName(HInstance, 'BS_CALC_CANCEL');
  384.           end;
  385.           if (Kind in [cbBck, cbClr]) then Width := 46;
  386.           if (Kind in [cbSgn..cbCancel]) then Caption := BtnCaptions[Kind];
  387.         end;
  388.     end;
  389.     FMemoryLabel := TbsSkinStdLabel.Create(Self);
  390.     with FMemoryLabel do begin
  391.       SetBounds(6, 7, 34, 20);
  392.       Parent := Self;
  393.       Alignment := taCenter;
  394.     end;
  395.   finally
  396.   end;
  397.   FText := '0';
  398.   FMemory := 0.0;
  399.   FPrecision := DefCalcPrecision;
  400.   FBeepOnError := True;
  401. end;
  402. procedure TCalculatorPanel.SetText(const Value: string);
  403. begin
  404.   if FText <> Value then begin
  405.     FText := Value;
  406.     TextChanged;
  407.   end;
  408. end;
  409. procedure TCalculatorPanel.TextChanged;
  410. begin
  411.   if Assigned(FControl) then TLabel(FControl).Caption := FText;
  412.   if Assigned(FOnTextChange) then FOnTextChange(Self);
  413. end;
  414. procedure TCalculatorPanel.Error;
  415. begin
  416.   FStatus := csError;
  417.   SetText(SError);
  418.   if FBeepOnError then MessageBeep(0);
  419.   if Assigned(FOnError) then FOnError(Self);
  420. end;
  421. procedure TCalculatorPanel.SetDisplay(R: Double);
  422. var
  423.   S: string;
  424. begin
  425.   S := FloatToStrF(R, ffGeneral, Max(2, FPrecision), 0);
  426.   if FText <> S then begin
  427.     SetText(S);
  428.     if Assigned(FOnDisplayChange) then FOnDisplayChange(Self);
  429.   end;
  430. end;
  431. function TCalculatorPanel.GetDisplay: Double;
  432. begin
  433.   if FStatus = csError then Result := 0.0
  434.   else Result := StrToFloat(Trim(FText));
  435. end;
  436. procedure TCalculatorPanel.CheckFirst;
  437. begin
  438.   if FStatus = csFirst then begin
  439.     FStatus := csValid;
  440.     SetText('0');
  441.   end;
  442. end;
  443. procedure TCalculatorPanel.UpdateMemoryLabel;
  444. begin
  445.   if FMemoryLabel <> nil then
  446.     if FMemory <> 0.0 then FMemoryLabel.Caption := 'M'
  447.     else FMemoryLabel.Caption := '';
  448. end;
  449. procedure TCalculatorPanel.CalcKey(Key: Char);
  450. var
  451.   R: Double;
  452. begin
  453.   Key := UpCase(Key);
  454.   if (FStatus = csError) and (Key <> 'C') then Key := #0;
  455.   if Assigned(FOnCalcKey) then FOnCalcKey(Self, Key);
  456.   if Key in [DecimalSeparator, '.', ','] then begin
  457.     CheckFirst;
  458.     if Pos(DecimalSeparator, FText) = 0 then
  459.       SetText(FText + DecimalSeparator);
  460.     Exit;
  461.   end;
  462.   case Key of
  463.     'R':
  464.       if FStatus in [csValid, csFirst] then begin
  465.         FStatus := csFirst;
  466.         if GetDisplay = 0 then Error else SetDisplay(1.0 / GetDisplay);
  467.       end;
  468.     'Q':
  469.       if FStatus in [csValid, csFirst] then begin
  470.         FStatus := csFirst;
  471.         if GetDisplay < 0 then Error else SetDisplay(Sqrt(GetDisplay));
  472.       end;
  473.     '0'..'9':
  474.       begin
  475.         CheckFirst;
  476.         if FText = '0' then SetText('');
  477.         if Pos('E', FText) = 0 then begin
  478.           if Length(FText) < Max(2, FPrecision) + Ord(Boolean(Pos('-', FText))) then
  479.             SetText(FText + Key)
  480.           else if FBeepOnError then MessageBeep(0);
  481.         end;
  482.       end;
  483.     #8:
  484.       begin
  485.         CheckFirst;
  486.         if (Length(FText) = 1) or ((Length(FText) = 2) and (FText[1] = '-')) then
  487.           SetText('0')
  488.         else
  489.           SetText(System.Copy(FText, 1, Length(FText) - 1));
  490.       end;
  491.     '_': SetDisplay(-GetDisplay);
  492.     '+', '-', '*', '/', '=', '%', #13:
  493.       begin
  494.         if FStatus = csValid then begin
  495.           FStatus := csFirst;
  496.           R := GetDisplay;
  497.           if Key = '%' then
  498.             case FOperator of
  499.               '+', '-': R := FOperand * R / 100.0;
  500.               '*', '/': R := R / 100.0;
  501.             end;
  502.           case FOperator of
  503.             '+': SetDisplay(FOperand + R);
  504.             '-': SetDisplay(FOperand - R);
  505.             '*': SetDisplay(FOperand * R);
  506.             '/': if R = 0 then Error else SetDisplay(FOperand / R);
  507.           end;
  508.         end;
  509.         FOperator := Key;
  510.         FOperand := GetDisplay;
  511.         if Key in ResultKeys then
  512.           if Assigned(FOnResult) then FOnResult(Self);
  513.       end;
  514.     #27, 'C': Clear;
  515.     ^C: Copy;
  516.     ^V: Paste;
  517.   end;
  518. end;
  519. procedure TCalculatorPanel.Clear;
  520. begin
  521.   FStatus := csFirst;
  522.   SetDisplay(0.0);
  523.   FOperator := '=';
  524. end;
  525. procedure TCalculatorPanel.CalcKeyPress(Sender: TObject; var Key: Char);
  526. var
  527.   Btn: TbsSkinSpeedButton;
  528. begin
  529.   Btn := FindButton(Key);
  530.   if Btn <> nil then Btn.ButtonClick
  531.   else CalcKey(Key);
  532. end;
  533. function TCalculatorPanel.FindButton(Key: Char): TbsSkinSpeedButton;
  534. const
  535.   ButtonChars = '0123456789_./*-+Q%R='#8'C';
  536. var
  537.   I: Integer;
  538.   BtnTag: Longint;
  539. begin
  540.   if Key in [DecimalSeparator, '.', ','] then Key := '.'
  541.   else if Key = #13 then Key := '='
  542.   else if Key = #27 then Key := 'C';
  543.   BtnTag := Pos(UpCase(Key), ButtonChars) - 1;
  544.   if BtnTag >= 0 then
  545.     for I := 0 to ControlCount - 1 do begin
  546.       if Controls[I] is TbsSkinSpeedButton then begin
  547.         Result := TbsSkinSpeedButton(Controls[I]);
  548.         if Result.Tag = BtnTag then Exit;
  549.       end;
  550.     end;
  551.   Result := nil;
  552. end;
  553. procedure TCalculatorPanel.BtnClick(Sender: TObject);
  554. begin
  555.   case TCalcButton(Sender).Kind of
  556.     cbNum0..cbNum9: CalcKey(Char(TComponent(Sender).Tag + Ord('0')));
  557.     cbSgn: CalcKey('_');
  558.     cbDcm: CalcKey(DecimalSeparator);
  559.     cbDiv: CalcKey('/');
  560.     cbMul: CalcKey('*');
  561.     cbSub: CalcKey('-');
  562.     cbAdd: CalcKey('+');
  563.     cbSqr: CalcKey('Q');
  564.     cbPcnt: CalcKey('%');
  565.     cbRev: CalcKey('R');
  566.     cbEql: CalcKey('=');
  567.     cbBck: CalcKey(#8);
  568.     cbClr: CalcKey('C');
  569.     cbMP:
  570.       if FStatus in [csValid, csFirst] then begin
  571.         FStatus := csFirst;
  572.         FMemory := FMemory + GetDisplay;
  573.         UpdateMemoryLabel;
  574.       end;
  575.     cbMS:
  576.       if FStatus in [csValid, csFirst] then begin
  577.         FStatus := csFirst;
  578.         FMemory := GetDisplay;
  579.         UpdateMemoryLabel;
  580.       end;
  581.     cbMR:
  582.       if FStatus in [csValid, csFirst] then begin
  583.         FStatus := csFirst;
  584.         CheckFirst;
  585.         SetDisplay(FMemory);
  586.       end;
  587.     cbMC:
  588.       begin
  589.         FMemory := 0.0;
  590.         UpdateMemoryLabel;
  591.       end;
  592.     cbOk:
  593.       begin
  594.         if FStatus <> csError then begin
  595.           CalcKey('=');
  596.           DisplayValue := DisplayValue; { to raise exception on error }
  597.           if Assigned(FOnOk) then FOnOk(Self);
  598.         end
  599.         else if FBeepOnError then MessageBeep(0);
  600.       end;
  601.     cbCancel: if Assigned(FOnCancel) then FOnCancel(Self);
  602.   end;
  603. end;
  604. procedure TCalculatorPanel.Copy;
  605. begin
  606.   Clipboard.AsText := FText;
  607. end;
  608. procedure TCalculatorPanel.Paste;
  609. begin
  610.   if Clipboard.HasFormat(CF_TEXT) then
  611.     try
  612.       SetDisplay(StrToFloat(Trim(ReplaceStr(Clipboard.AsText,
  613.         CurrencyString, ''))));
  614.     except
  615.       SetText('0');
  616.     end;
  617. end;
  618. { TbsCalculator }
  619. constructor TbsSkinCalculator.Create(AOwner: TComponent);
  620. begin
  621.   inherited Create(AOwner);
  622.   FTitle := SCalculator;
  623.   FPrecision := DefCalcPrecision;
  624.   FBeepOnError := True;
  625.   FButtonSkinDataName := 'toolbutton';
  626.   FDisplayLabelSkinDataName := 'label';
  627.   FDefaultFont := TFont.Create;
  628.   with FDefaultFont do
  629.   begin
  630.     Name := 'Arial';
  631.     Style := [];
  632.     Height := 14;
  633.   end;
  634. end;
  635. destructor TbsSkinCalculator.Destroy;
  636. begin
  637.   FOnChange := nil;
  638.   FOnDisplayChange := nil;
  639.   FDefaultFont.Free;
  640.   inherited Destroy;
  641. end;
  642. procedure TbsSkinCalculator.SetDefaultFont;
  643. begin
  644.   FDefaultFont.Assign(Value);
  645. end;
  646. procedure TbsSkinCalculator.Notification;
  647. begin
  648.   inherited Notification(AComponent, Operation);
  649.   if (Operation = opRemove) and (AComponent = FSD) then FSD := nil;
  650.   if (Operation = opRemove) and (AComponent = FCtrlFSD) then FCtrlFSD := nil;
  651. end;
  652. function TbsSkinCalculator.GetTitle: string;
  653. begin
  654.   Result := FTitle;
  655. end;
  656. procedure TbsSkinCalculator.SetTitle(const Value: string);
  657. begin
  658.   FTitle := Value;
  659. end;
  660. function TbsSkinCalculator.TitleStored: Boolean;
  661. begin
  662.   Result := Title <> SCalculator;
  663. end;
  664. function TbsSkinCalculator.GetDisplay: Double;
  665. begin
  666.   if Assigned(FCalc) then
  667.     Result := TCalculatorPanel(FCalc.FCalcPanel).GetDisplay
  668.   else Result := FValue;
  669. end;
  670. procedure TbsSkinCalculator.CalcKey(var Key: Char);
  671. begin
  672.   if Assigned(FOnCalcKey) then FOnCalcKey(Self, Key);
  673. end;
  674. procedure TbsSkinCalculator.DisplayChange;
  675. begin
  676.   if Assigned(FOnDisplayChange) then FOnDisplayChange(Self);
  677. end;
  678. procedure TbsSkinCalculator.Change;
  679. begin
  680.   if Assigned(FOnChange) then FOnChange(Self);
  681. end;
  682. function TbsSkinCalculator.Execute: Boolean;
  683. var
  684.   i: Integer;
  685.   FW, FH: Integer;
  686. begin
  687.   FCalc := CreateCalculatorForm(Self, HelpContext);
  688.   with FCalc do
  689.   try
  690.     FCalcPanel.SkinData := Self.CtrlSkinData;
  691.     FDisplayLabel.DefaultFont := FDefaultFont;
  692.     FDisplayLabel.SkinDataName := FDisplayLabelSkinDataName;
  693.     FDisplayLabel.SkinData := Self.CtrlSkinData;
  694.     for i := 0 to FCalcPanel.ControlCount - 1 do
  695.     if FCalcPanel.Controls[i] is TbsSkinSpeedButton then
  696.     with TbsSkinSpeedButton(FCalcPanel.Controls[i]) do
  697.     begin
  698.       DefaultFont := Self.DefaultFont;
  699.       DefaultHeight := 25;
  700.       SkinDataName := FButtonSkinDataName;
  701.       SkinData := CtrlSkinData;
  702.     end
  703.     else
  704.     if FCalcPanel.Controls[i] is TbsSkinStdLabel then
  705.     with TbsSkinStdLabel(FCalcPanel.Controls[i]) do
  706.     begin
  707.       DefaultFont := Self.DefaultFont;
  708.       SkinData := CtrlSkinData;
  709.     end;
  710.     Caption := Self.Title;
  711.     TCalculatorPanel(FCalcPanel).FMemory := Self.FMemory;
  712.     TCalculatorPanel(FCalcPanel).UpdateMemoryLabel;
  713.     TCalculatorPanel(FCalcPanel).FPrecision := Max(2, Self.Precision);
  714.     TCalculatorPanel(FCalcPanel).FBeepOnError := Self.BeepOnError;
  715.     if Self.FValue <> 0 then begin
  716.       TCalculatorPanel(FCalcPanel).DisplayValue := Self.FValue;
  717.       TCalculatorPanel(FCalcPanel).FStatus := csFirst;
  718.       TCalculatorPanel(FCalcPanel).FOperator := '=';
  719.     end;
  720.     BSF.BorderIcons := [];
  721.     BSF.SkinData := Self.SkinData;
  722.     BSF.MenusSkinData := Self.CtrlSkinData;
  723.     BSF.AlphaBlend := AlphaBlend;
  724.     BSF.AlphaBlendAnimation := AlphaBlendAnimation;
  725.     BSF.AlphaBlendValue := AlphaBlendValue;
  726.     FW := 205;
  727.     FH := FCalcPanel.Height + FDisplayLabel.Height;
  728.     if (SkinData <> nil) and not SkinData.Empty
  729.     then
  730.       begin
  731.         if FW < BSF.GetMinWidth then FW := BSF.GetMinWidth;
  732.         if FH < BSF.GetMinHeight then FH := BSF.GetMinHeight;  
  733.       end;
  734.     ClientWidth := FW;
  735.     ClientHeight := FH;
  736.     Result := (ShowModal = mrOk);
  737.     if Result then begin
  738.       Self.FMemory := TCalculatorPanel(FCalcPanel).FMemory;
  739.       if (TCalculatorPanel(FCalcPanel).DisplayValue <> Self.FValue) then begin
  740.         Self.FValue := TCalculatorPanel(FCalcPanel).DisplayValue;
  741.         Change;
  742.       end;
  743.     end;
  744.   finally
  745.     Free;
  746.     FCalc := nil;
  747.   end;
  748. end;
  749. { TbsCalculatorForm }
  750. constructor TbsCalculatorForm.Create(AOwner: TComponent);
  751. var
  752.   Popup: TPopupMenu;
  753.   Items: array[0..1] of TMenuItem;
  754. begin
  755.   inherited CreateNew(AOwner);
  756.   BorderStyle := bsDialog;
  757.   Caption := SCalculator;
  758.   KeyPreview := True;
  759.   PixelsPerInch := 96;
  760.   Position := poScreenCenter;
  761.   OnKeyPress := FormKeyPress;
  762.   Items[0] := NewItem('&Copy', scCtrl + vk_Insert, False, True, CopyItemClick, 0, '');
  763.   Items[1] := NewItem('&Paste', scShift + vk_Insert, False, True, PasteItemClick, 0, '');
  764.   FPasteItem := Items[1];
  765.   Popup := NewPopupMenu(Self, 'PopupMenu', paLeft, True, Items);
  766.   Popup.OnPopup := PopupMenuPopup;
  767.   { DisplayPanel }
  768.   FDisplayLabel := TbsSkinLabel.Create(Self);
  769.   with FDisplayLabel do begin
  770.     Align := alTop;
  771.     Parent := Self;
  772.     AutoSize := False;
  773.     Alignment := taRightJustify;
  774.     Caption := '0';
  775.     BorderStyle := bvFrame;
  776.     DefaultHeight := 20;
  777.   end;
  778.   { CalcPanel }
  779.   FCalcPanel := TCalculatorPanel.CreateLayout(Self);
  780.   with TCalculatorPanel(FCalcPanel) do begin
  781.     Align := alTop;
  782.     Parent := Self;
  783.     OnOkClick := Self.OkClick;
  784.     OnCancelClick := Self.CancelClick;
  785.     OnCalcKey := Self.CalcKey;
  786.     OnDisplayChange := Self.DisplayChange;
  787.     FControl := FDisplayLabel;
  788.     BorderStyle := bvNone;
  789.   end;
  790.   BSF := TbsBusinessSkinForm.Create(Self);
  791. end;
  792. procedure TbsCalculatorForm.FormKeyPress(Sender: TObject; var Key: Char);
  793. begin
  794.   TCalculatorPanel(FCalcPanel).CalcKeyPress(Sender, Key);
  795. end;
  796. procedure TbsCalculatorForm.CopyItemClick(Sender: TObject);
  797. begin
  798.   TCalculatorPanel(FCalcPanel).Copy;
  799. end;
  800. procedure TbsCalculatorForm.PasteItemClick(Sender: TObject);
  801. begin
  802.   TCalculatorPanel(FCalcPanel).Paste;
  803. end;
  804. procedure TbsCalculatorForm.OkClick(Sender: TObject);
  805. begin
  806.   ModalResult := mrOk;
  807. end;
  808. procedure TbsCalculatorForm.CancelClick(Sender: TObject);
  809. begin
  810.   ModalResult := mrCancel;
  811. end;
  812. procedure TbsCalculatorForm.CalcKey(Sender: TObject; var Key: Char);
  813. begin
  814.   if (Owner <> nil) and (Owner is TbsSkinCalculator) then
  815.     TbsSkinCalculator(Owner).CalcKey(Key);
  816. end;
  817. procedure TbsCalculatorForm.DisplayChange(Sender: TObject);
  818. begin
  819.   if (Owner <> nil) and (Owner is TbsSkinCalculator) then
  820.     TbsSkinCalculator(Owner).DisplayChange;
  821. end;
  822. procedure TbsCalculatorForm.PopupMenuPopup(Sender: TObject);
  823. begin
  824.   FPasteItem.Enabled := Clipboard.HasFormat(CF_TEXT);
  825. end;
  826. constructor TbsSkinCalcEdit.Create(AOwner: TComponent);
  827. begin
  828.   inherited;
  829.   ButtonMode := True;
  830.   FValue := 0;
  831.   FIncrement := 1;
  832.   FDecimal := 2;
  833.   StopCheck := True;
  834.   Text := '0';
  835.   StopCheck := False;
  836.   Width := 120;
  837.   Height := 20;
  838.   FSkinDataName := 'buttonedit';
  839.   OnButtonClick := ButtonClick;
  840.   FCalc := TbsPopupCalculatorForm.Create(Self);
  841.   FCalc.Visible := False;
  842.   FCalc.CalcEdit := Self;
  843.   FCalc.Parent := Self;
  844.   FMemory := 0.0;
  845.   FPrecision := DefCalcPrecision;
  846.   FCalcButtonSkinDataName := 'toolbutton';
  847.   FCalcDisplayLabelSkinDataName := 'label';
  848.   FAlphaBlend := False;
  849.   FAlphaBlendValue := 0;
  850. end;
  851. destructor TbsSkinCalcEdit.Destroy;
  852. begin
  853.   FCalc.Free;
  854.   inherited;
  855. end;
  856. procedure TbsSkinCalcEdit.CMCancelMode(var Message: TCMCancelMode);
  857. begin
  858.   if (Message.Sender <> FCalc) and
  859.      not FCalc.ContainsControl(Message.Sender)
  860.   then
  861.     CloseUp;
  862. end;
  863. procedure TbsSkinCalcEdit.CloseUp;
  864. begin
  865.   if FCalc.Visible then FCalc.Hide;
  866.   if CheckW2KWXP and FAlphaBlend
  867.   then
  868.     SetWindowLong(FCalc.Handle, GWL_EXSTYLE,
  869.                   GetWindowLong(Handle, GWL_EXSTYLE) and not WS_EX_LAYERED);
  870. end;
  871. procedure TbsSkinCalcEdit.DropDown;
  872. var
  873.   i, Y: Integer;
  874.   P: TPoint;
  875. begin
  876.  with FCalc do
  877.   begin
  878.     SkinData := Self.SkinData;
  879.     FCalcPanel.SkinData := Self.SkinData;
  880.     FDisplayLabel.DefaultFont := FDefaultFont;
  881.     FDisplayLabel.SkinDataName := FCalcDisplayLabelSkinDataName;
  882.     FDisplayLabel.SkinData := Self.SkinData;
  883.     for i := 0 to FCalcPanel.ControlCount - 1 do
  884.     if FCalcPanel.Controls[i] is TbsSkinSpeedButton then
  885.     with TbsSkinSpeedButton(FCalcPanel.Controls[i]) do
  886.     begin
  887.       DefaultFont := Self.DefaultFont;
  888.       DefaultHeight := 25;
  889.       SkinDataName := FCalcButtonSkinDataName;
  890.       SkinData := Self.SkinData;
  891.     end
  892.     else
  893.     if FCalcPanel.Controls[i] is TbsSkinStdLabel then
  894.     with TbsSkinStdLabel(FCalcPanel.Controls[i]) do
  895.     begin
  896.       DefaultFont := Self.DefaultFont;
  897.       SkinData := Self.SkinData;
  898.     end;
  899.     TCalculatorPanel(FCalcPanel).FMemory := Self.FMemory;
  900.     TCalculatorPanel(FCalcPanel).UpdateMemoryLabel;
  901.     TCalculatorPanel(FCalcPanel).FPrecision := Max(2, Self.Precision);
  902.     TCalculatorPanel(FCalcPanel).FBeepOnError := False;
  903.     if Self.FValue <> 0 then begin
  904.       TCalculatorPanel(FCalcPanel).DisplayValue := Self.FValue;
  905.       TCalculatorPanel(FCalcPanel).FStatus := csFirst;
  906.       TCalculatorPanel(FCalcPanel).FOperator := '=';
  907.     end;
  908.     Width := 209;
  909.     //
  910.     if FIndex = -1
  911.     then
  912.       Height := FCalcPanel.Height + FDisplayLabel.Height + 2
  913.     else
  914.       Height := FCalcPanel.Height + FDisplayLabel.Height +
  915.       (RectHeight(SkinRect) - RectHeight(ClRect));
  916.     //
  917.     P := Self.Parent.ClientToScreen(Point(Self.Left, Self.Top));
  918.     Y := P.Y + Self.Height;
  919.     if Y + FCalc.Height > Screen.Height then Y := P.Y - FCalc.Height;
  920.     if P.X + FCalc.Width > Screen.Width
  921.     then P.X := Screen.Width - FCalc.Width;
  922.     if P.X < 0 then P.X := 0;
  923.     FCalc.Left := P.X;
  924.     FCalc.Top := Y;
  925.     //
  926.     if CheckW2KWXP and FAlphaBlend
  927.     then
  928.       begin
  929.         SetWindowLong(FCalc.Handle, GWL_EXSTYLE,
  930.                       GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
  931.         SetAlphaBlendTransparent(FCalc.Handle, 0)
  932.       end;
  933.     FCalc.Show(P.X, Y);
  934.     //
  935.     if FAlphaBlend and not FAlphaBlendAnimation and CheckW2KWXP
  936.     then
  937.       begin
  938.         Application.ProcessMessages;
  939.         SetAlphaBlendTransparent(FCalc.Handle, FAlphaBlendValue)
  940.       end
  941.     else
  942.     if CheckW2KWXP and FAlphaBlend and FAlphaBlendAnimation
  943.     then
  944.       begin
  945.         Application.ProcessMessages;
  946.         I := 0;
  947.         repeat
  948.           Inc(i, 2);
  949.           if i > FAlphaBlendValue then i := FAlphaBlendValue;
  950.           SetAlphaBlendTransparent(FCalc.Handle, i);
  951.         until i >= FAlphaBlendValue;
  952.       end;
  953.   end;
  954. end;
  955. procedure TbsSkinCalcEdit.ButtonClick(Sender: TObject);
  956. begin
  957.   if FCalc.Visible then CloseUp else DropDown;
  958. end;
  959. procedure TbsSkinCalcEdit.SetValueType(NewType: TbsValueType);
  960. begin
  961.   if FValueType <> NewType
  962.   then
  963.     begin
  964.       FValueType := NewType;
  965.       if FValueType = vtInteger
  966.       then
  967.         begin
  968.           FIncrement := Round(FIncrement);
  969.           if FIncrement = 0 then FIncrement := 1;
  970.         end;
  971.   end;
  972. end;
  973. procedure TbsSkinCalcEdit.SetDecimal(NewValue: Byte);
  974. begin
  975.   if FDecimal <> NewValue then begin
  976.     FDecimal := NewValue;
  977.   end;
  978. end;
  979. function TbsSkinCalcEdit.CheckValue;
  980. begin
  981.   Result := NewValue;
  982.   if (FMaxValue <> FMinValue)
  983.   then
  984.     begin
  985.       if NewValue < FMinValue then
  986.       Result := FMinValue
  987.       else if NewValue > FMaxValue then
  988.       Result := FMaxValue;
  989.     end;
  990. end;
  991. procedure TbsSkinCalcEdit.SetMinValue;
  992. begin
  993.   FMinValue := AValue;
  994. end;
  995. procedure TbsSkinCalcEdit.SetMaxValue;
  996. begin
  997.   FMaxValue := AValue;
  998. end;
  999. function TbsSkinCalcEdit.IsNumText;
  1000. function GetMinus: Boolean;
  1001. var
  1002.   i: Integer;
  1003.   S: String;
  1004. begin
  1005.   S := AText;
  1006.   i := Pos('-', S);
  1007.   if i > 1
  1008.   then
  1009.     Result := False
  1010.   else
  1011.     begin
  1012.       Delete(S, i, 1);
  1013.       Result := Pos('-', S) = 0;
  1014.     end;
  1015. end;
  1016. function GetP: Boolean;
  1017. var
  1018.   i: Integer;
  1019.   S: String;
  1020. begin
  1021.   S := AText;
  1022.   i := Pos(DecimalSeparator, S);
  1023.   if i = 1
  1024.   then
  1025.     Result := False
  1026.   else
  1027.     begin
  1028.       Delete(S, i, 1);
  1029.       Result := Pos(DecimalSeparator, S) = 0;
  1030.     end;
  1031. end;
  1032. const
  1033.   EditChars = '01234567890-';
  1034. var
  1035.   i: Integer;
  1036.   S: String;
  1037. begin
  1038.   S := EditChars;
  1039.   Result := True;
  1040.   if ValueType = vtFloat
  1041.   then
  1042.     S := S + DecimalSeparator;
  1043.   if (Text = '') or (Text = '-')
  1044.   then
  1045.     begin
  1046.       Result := False;
  1047.       Exit;
  1048.     end;
  1049.   for i := 1 to Length(Text) do
  1050.   begin
  1051.     if Pos(Text[i], S) = 0
  1052.     then
  1053.       begin
  1054.         Result := False;
  1055.         Break;
  1056.       end;
  1057.   end;
  1058.   Result := Result and GetMinus;
  1059.   if ValueType = vtFloat
  1060.   then
  1061.     Result := Result and GetP;
  1062. end;
  1063. procedure TbsSkinCalcEdit.Change;
  1064. var
  1065.   NewValue: Double;
  1066. begin
  1067.   inherited;
  1068.   if not StopCheck and IsNumText(Text)
  1069.   then
  1070.     begin
  1071.       if ValueType = vtFloat
  1072.       then NewValue := CheckValue(StrToFloat(Text))
  1073.       else NewValue := CheckValue(StrToInt(Text));
  1074.       if NewValue <> FValue
  1075.       then
  1076.         begin
  1077.           FValue := NewValue;
  1078.           Change;
  1079.         end;
  1080.       if (ValueType = vtFloat) and (NewValue <> StrToFloat(Text))
  1081.       then
  1082.         Text := FloatToStrF(Value, ffFixed, 15, FDecimal)
  1083.       else
  1084.       if (ValueType = vtInteger) and (NewValue <> StrToInt(Text))
  1085.       then
  1086.         Text := IntToStr(Round(Value));
  1087.     end;
  1088. end;
  1089. procedure TbsSkinCalcEdit.CMTextChanged;
  1090. var
  1091.   NewValue: Double;
  1092. begin
  1093.   inherited;
  1094.   if not StopCheck and IsNumText(Text)
  1095.   then
  1096.     begin
  1097.       if ValueType = vtFloat
  1098.       then NewValue := CheckValue(StrToFloat(Text))
  1099.       else NewValue := CheckValue(StrToInt(Text));
  1100.       if NewValue <> FValue
  1101.       then
  1102.         begin
  1103.           FValue := NewValue;
  1104.           StopCheck := True;
  1105.           Change;
  1106.           StopCheck := False;
  1107.         end;
  1108.       if (ValueType = vtFloat) and (NewValue <> StrToFloat(Text))
  1109.       then
  1110.         Text := FloatToStrF(Value, ffFixed, 15, FDecimal)
  1111.       else
  1112.       if (ValueType = vtInteger) and (NewValue <> StrToInt(Text))
  1113.       then
  1114.         Text := IntToStr(Round(Value));
  1115.     end;
  1116. end;
  1117. procedure TbsSkinCalcEdit.SetValue;
  1118. begin
  1119.   FValue := CheckValue(AValue);
  1120.   StopCheck := True;
  1121.   if ValueType = vtFloat
  1122.   then
  1123.     Text := FloatToStrF(CheckValue(AValue), ffFixed, 15, FDecimal)
  1124.   else
  1125.     Text := IntToStr(Round(CheckValue(AValue)));
  1126.   StopCheck := False;
  1127.   Change;
  1128. end;
  1129. procedure TbsSkinCalcEdit.KeyPress(var Key: Char);
  1130. begin
  1131.   if not IsValidChar(Key) then
  1132.   begin
  1133.     Key := #0;
  1134.     MessageBeep(0)
  1135.   end;
  1136.   if Key <> #0 then
  1137.   if FCalc.Visible
  1138.   then
  1139.     CloseUp
  1140.   else
  1141.     inherited KeyPress(Key);
  1142. end;
  1143. function TbsSkinCalcEdit.IsValidChar(Key: Char): Boolean;
  1144. begin
  1145.   if ValueType = vtInteger
  1146.   then
  1147.     Result := (Key in ['-', '0'..'9']) or
  1148.      ((Key < #32) and (Key <> Chr(VK_RETURN)))
  1149.   else
  1150.   Result := (Key in [DecimalSeparator, '-', '0'..'9']) or
  1151.     ((Key < #32) and (Key <> Chr(VK_RETURN)));
  1152.   if ReadOnly and Result and ((Key >= #32) or
  1153.      (Key = Char(VK_BACK)) or (Key = Char(VK_DELETE)))
  1154.   then
  1155.     Result := False;
  1156. end;
  1157. procedure TbsSkinCalcEdit.WMKillFocus(var Message: TWMKillFocus);
  1158. begin
  1159.   inherited;
  1160.   CloseUp;
  1161. end;
  1162. constructor TbsPopupCalculatorForm.Create(AOwner: TComponent);
  1163. begin
  1164.   inherited Create(AOwner);
  1165.   BorderStyle := bvFrame;
  1166.   ControlStyle := ControlStyle + [csNoDesignVisible, csReplicatable];
  1167.   CalcEdit := nil;
  1168.   { DisplayPanel }
  1169.   FDisplayLabel := TbsSkinLabel.Create(Self);
  1170.   with FDisplayLabel do begin
  1171.     Align := alTop;
  1172.     Parent := Self;
  1173.     AutoSize := False;
  1174.     Alignment := taRightJustify;
  1175.     Caption := '0';
  1176.     BorderStyle := bvNone;
  1177.     DefaultHeight := 20;
  1178.     Visible := True;
  1179.   end;
  1180.   { CalcPanel }
  1181.   FCalcPanel := TCalculatorPanel.CreateLayout(Self);
  1182.   with TCalculatorPanel(FCalcPanel) do begin
  1183.     Align := alTop;
  1184.     Parent := Self;
  1185.     FControl := FDisplayLabel;
  1186.     BorderStyle := bvNone;
  1187.     OnOkClick := OkClick;
  1188.     OnCancelClick := CancelClick;
  1189.     Visible := True;
  1190.   end;
  1191. end;
  1192. destructor TbsPopupCalculatorForm.Destroy;
  1193. begin
  1194.   FDisplayLabel.Free;
  1195.   FCalcPanel.Free;
  1196.   inherited;
  1197. end;
  1198. procedure TbsPopupCalculatorForm.Show(X, Y: Integer);
  1199. begin
  1200.   SetWindowPos(Handle, HWND_TOP, X, Y, 0, 0,
  1201.       SWP_NOSIZE or SWP_NOACTIVATE or SWP_SHOWWINDOW);
  1202.   Visible := True;
  1203. end;
  1204. procedure TbsPopupCalculatorForm.Hide;
  1205. begin
  1206.   SetWindowPos(Handle, 0, 0, 0, 0, 0, SWP_NOZORDER or
  1207.       SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SWP_HIDEWINDOW);
  1208.   Visible := False;
  1209. end;
  1210. procedure TbsPopupCalculatorForm.CreateParams(var Params: TCreateParams);
  1211. begin
  1212.   inherited CreateParams(Params);
  1213.   with Params do
  1214.   begin
  1215.     Style := WS_POPUP;
  1216.     ExStyle := WS_EX_TOOLWINDOW;
  1217.     AddBiDiModeExStyle(ExStyle);
  1218.     WindowClass.Style := CS_SAVEBITS;
  1219.   end;
  1220. end;
  1221. procedure TbsPopupCalculatorForm.WMMouseActivate(var Message: TMessage);
  1222. begin
  1223.   Message.Result := MA_NOACTIVATE;
  1224. end;
  1225. procedure TbsPopupCalculatorForm.OkClick(Sender: TObject);
  1226. begin
  1227.   if CalcEdit <> nil
  1228.   then
  1229.     begin
  1230.       CalcEdit.Value := TCalculatorPanel(FCalcPanel).DisplayValue;
  1231.       CalcEdit.CloseUp;
  1232.     end;
  1233. end;
  1234. procedure TbsPopupCalculatorForm.CancelClick(Sender: TObject);
  1235. begin
  1236.   if CalcEdit <> nil then CalcEdit.CloseUp;
  1237. end;
  1238. end.