home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 June / Chip_2002-06_cd1.bin / zkuste / delphi / kolekce / d6 / rxlibsetup.exe / {app} / units / CURREDIT.PAS < prev    next >
Encoding:
Pascal/Delphi Source File  |  2002-02-19  |  21.5 KB  |  836 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 2001,2002 SGB Software          }
  6. {         Copyright (c) 1997, 1998 Fedor Koshevnikov,   }
  7. {                        Igor Pavluk and Serge Korolev  }
  8. {                                                       }
  9. {*******************************************************}
  10.  
  11.  
  12.  
  13. unit CurrEdit;
  14.  
  15. {$I RX.INC}
  16. {$W-}
  17.  
  18. interface
  19.  
  20. uses SysUtils, Windows, Messages, Classes, Graphics, Controls, Menus, Forms, StdCtrls, Mask,
  21.   Buttons, ToolEdit;
  22.  
  23. type
  24.  
  25. { TCustomNumEdit }
  26.  
  27.   TCustomNumEdit = class(TCustomComboEdit)
  28.   private
  29.     FCanvas: TControlCanvas;
  30.     FAlignment: TAlignment;
  31.     FFocused: Boolean;
  32.     FValue: Extended;
  33.     FMinValue, FMaxValue: Extended;
  34.     FDecimalPlaces: Cardinal;
  35.     FBeepOnError: Boolean;
  36.     FCheckOnExit: Boolean;
  37.     FZeroEmpty: Boolean;
  38.     FFormatOnEditing: Boolean;
  39.     FFormatting: Boolean;
  40.     FDisplayFormat: String;
  41.     procedure SetFocused(Value: Boolean);
  42.     procedure SetAlignment(Value: TAlignment);
  43.     procedure SetBeepOnError(Value: Boolean);
  44.     procedure SetDisplayFormat(const Value: string);
  45.     function GetDisplayFormat: string;
  46.     procedure SetDecimalPlaces(Value: Cardinal);
  47.     function GetValue: Extended;
  48.     procedure SetValue(AValue: Extended);
  49.     function GetAsInteger: Longint;
  50.     procedure SetAsInteger(AValue: Longint);
  51.     procedure SetMaxValue(AValue: Extended);
  52.     procedure SetMinValue(AValue: Extended);
  53.     procedure SetZeroEmpty(Value: Boolean);
  54.     procedure SetFormatOnEditing(Value: Boolean);
  55.     function GetText: string;
  56.     procedure SetText(const AValue: string);
  57.     function TextToValText(const AValue: string): string;
  58.     function CheckValue(NewValue: Extended; RaiseOnError: Boolean): Extended;
  59.     function IsFormatStored: Boolean;
  60.     procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
  61.     procedure CMEnter(var Message: TCMEnter); message CM_ENTER;
  62.     procedure CMExit(var Message: TCMExit); message CM_EXIT;
  63.     procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  64.     procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  65.     procedure WMPaste(var Message: TMessage); message WM_PASTE;
  66.   protected
  67. {$IFDEF WIN32}
  68.     procedure AcceptValue(const Value: Variant); override;
  69. {$ELSE}
  70.     procedure AcceptValue(const Value: string); override;
  71. {$ENDIF}
  72.     procedure Change; override;
  73.     procedure ReformatEditText; dynamic;
  74.     function GetDefaultBitmap(var DestroyNeeded: Boolean): TBitmap; override;
  75.     procedure DataChanged; virtual;
  76.     function DefaultDisplayFormat: string; virtual;
  77.     procedure KeyPress(var Key: Char); override;
  78.     function IsValidChar(Key: Char): Boolean; virtual;
  79.     function FormatDisplayText(Value: Extended): string;
  80.     function GetDisplayText: string; virtual;
  81.     procedure Reset; override;
  82.     procedure CheckRange;
  83.     procedure UpdateData;
  84.     procedure UpdatePopup; virtual;
  85.     property Formatting: Boolean read FFormatting;
  86.     property Alignment: TAlignment read FAlignment write SetAlignment
  87.       default taRightJustify;
  88.     property BeepOnError: Boolean read FBeepOnError write SetBeepOnError
  89.       default True;
  90.     property CheckOnExit: Boolean read FCheckOnExit write FCheckOnExit default False;
  91.     property GlyphKind default gkDefault;
  92.     property ButtonWidth default 20;
  93.     property DecimalPlaces: Cardinal read FDecimalPlaces write SetDecimalPlaces
  94.       default 2;
  95.     property DisplayFormat: string read GetDisplayFormat write SetDisplayFormat
  96.       stored IsFormatStored;
  97.     property MaxValue: Extended read FMaxValue write SetMaxValue;
  98.     property MinValue: Extended read FMinValue write SetMinValue;
  99.     property FormatOnEditing: Boolean read FFormatOnEditing
  100.       write SetFormatOnEditing default False;
  101.     property Text: string read GetText write SetText stored False;
  102.     property MaxLength default 0;
  103.     property ZeroEmpty: Boolean read FZeroEmpty write SetZeroEmpty default True;
  104.   public
  105.     constructor Create(AOwner: TComponent); override;
  106.     destructor Destroy; override;
  107.     procedure Clear; {$IFDEF RX_D5} override; {$ENDIF}
  108.     property AsInteger: Longint read GetAsInteger write SetAsInteger;
  109.     property DisplayText: string read GetDisplayText;
  110.     property PopupVisible;
  111.     property Value: Extended read GetValue write SetValue;
  112.   end;
  113.  
  114. { TCurrencyEdit }
  115.  
  116.   TCurrencyEdit = class(TCustomNumEdit)
  117.   protected
  118.     function DefaultDisplayFormat: string; override;
  119.   public
  120.     constructor Create(AOwner: TComponent); override;
  121.   published
  122.     property Alignment;
  123.     property AutoSelect;
  124.     property AutoSize;
  125.     property BeepOnError;
  126.     property BorderStyle;
  127.     property CheckOnExit;
  128.     property Color;
  129.     property Ctl3D;
  130.     property DecimalPlaces;
  131.     property DisplayFormat;
  132.     property DragCursor;
  133.     property DragMode;
  134.     property Enabled;
  135.     property Font;
  136.     property FormatOnEditing;
  137.     property HideSelection;
  138. {$IFDEF RX_D4}
  139.     property Anchors;
  140.     property BiDiMode;
  141.     property Constraints;
  142.     property DragKind;
  143.     property ParentBiDiMode;
  144. {$ENDIF}
  145. {$IFDEF WIN32}
  146.   {$IFNDEF VER90}
  147.     property ImeMode;
  148.     property ImeName;
  149.   {$ENDIF}
  150. {$ENDIF}
  151.     property MaxLength;
  152.     property MaxValue;
  153.     property MinValue;
  154.     property ParentColor;
  155.     property ParentCtl3D;
  156.     property ParentFont;
  157.     property ParentShowHint;
  158.     property PopupMenu;
  159.     property ReadOnly;
  160.     property ShowHint;
  161.     property TabOrder;
  162.     property TabStop;
  163.     property Text;
  164.     property Value;
  165.     property Visible;
  166.     property ZeroEmpty;
  167.     property OnChange;
  168.     property OnClick;
  169.     property OnDblClick;
  170.     property OnDragDrop;
  171.     property OnDragOver;
  172.     property OnEndDrag;
  173.     property OnEnter;
  174.     property OnExit;
  175.     property OnKeyDown;
  176.     property OnKeyPress;
  177.     property OnKeyUp;
  178.     property OnMouseDown;
  179.     property OnMouseMove;
  180.     property OnMouseUp;
  181. {$IFDEF RX_D5}
  182.     property OnContextPopup;
  183. {$ENDIF}
  184. {$IFDEF WIN32}
  185.     property OnStartDrag;
  186. {$ENDIF}
  187. {$IFDEF RX_D4}
  188.     property OnEndDock;
  189.     property OnStartDock;
  190. {$ENDIF}
  191.   end;
  192.  
  193. { TRxCustomCalcEdit }
  194.  
  195.   TRxCustomCalcEdit = class(TCustomNumEdit)
  196.   public
  197.     constructor Create(AOwner: TComponent); override;
  198.   end;
  199.  
  200. { TRxCalcEdit }
  201.  
  202.   TRxCalcEdit = class(TRxCustomCalcEdit)
  203.   published
  204.     property Alignment;
  205.     property AutoSelect;
  206.     property AutoSize;
  207.     property BeepOnError;
  208.     property BorderStyle;
  209.     property ButtonHint;
  210.     property CheckOnExit;
  211.     property ClickKey;
  212.     property Color;
  213.     property Ctl3D;
  214.     property DecimalPlaces;
  215.     property DirectInput;
  216.     property DisplayFormat;
  217.     property DragCursor;
  218.     property DragMode;
  219.     property Enabled;
  220.     property Font;
  221.     property FormatOnEditing;
  222.     property GlyphKind;
  223.     { Ensure GlyphKind is published before Glyph and ButtonWidth }
  224.     property Glyph;
  225.     property ButtonWidth;
  226.     property HideSelection;
  227. {$IFDEF RX_D4}
  228.     property Anchors;
  229.     property BiDiMode;
  230.     property Constraints;
  231.     property DragKind;
  232.     property ParentBiDiMode;
  233. {$ENDIF}
  234. {$IFDEF WIN32}
  235.   {$IFNDEF VER90}
  236.     property ImeMode;
  237.     property ImeName;
  238.   {$ENDIF}
  239. {$ENDIF}
  240.     property MaxLength;
  241.     property MaxValue;
  242.     property MinValue;
  243.     property NumGlyphs;
  244.     property ParentColor;
  245.     property ParentCtl3D;
  246.     property ParentFont;
  247.     property ParentShowHint;
  248.     property PopupAlign;
  249.     property PopupMenu;
  250.     property ReadOnly;
  251.     property ShowHint;
  252.     property TabOrder;
  253.     property TabStop;
  254.     property Text;
  255.     property Value;
  256.     property Visible;
  257.     property ZeroEmpty;
  258.     property OnButtonClick;
  259.     property OnChange;
  260.     property OnClick;
  261.     property OnDblClick;
  262.     property OnDragDrop;
  263.     property OnDragOver;
  264.     property OnEndDrag;
  265.     property OnEnter;
  266.     property OnExit;
  267.     property OnKeyDown;
  268.     property OnKeyPress;
  269.     property OnKeyUp;
  270.     property OnMouseDown;
  271.     property OnMouseMove;
  272.     property OnMouseUp;
  273. {$IFDEF RX_D5}
  274.     property OnContextPopup;
  275. {$ENDIF}
  276. {$IFDEF WIN32}
  277.     property OnStartDrag;
  278. {$ENDIF}
  279. {$IFDEF RX_D4}
  280.     property OnEndDock;
  281.     property OnStartDock;
  282. {$ENDIF}
  283.   end;
  284.  
  285. implementation
  286.  
  287. uses Consts, rxStrUtils, VclUtils, MaxMin, RxCalc;
  288.  
  289.  {$R *.R32}
  290.  
  291. const
  292.   sCalcBmp = 'CEDITBMP'; { Numeric editor button glyph }
  293.   CalcBitmap: TBitmap = nil;
  294.  
  295. type
  296.   THack = class(TPopupWindow);
  297.  
  298. function IsValidFloat(const Value: string; var RetValue: Extended): Boolean;
  299. var
  300.   I: Integer;
  301.   Buffer: array[0..63] of Char;
  302. begin
  303.   Result := False;
  304.   for I := 1 to Length(Value) do
  305.     if not (Value[I] in [DecimalSeparator, '-', '+', '0'..'9', 'e', 'E']) then
  306.       Exit;
  307.   Result := TextToFloat(StrPLCopy(Buffer, Value,
  308.     SizeOf(Buffer) - 1), RetValue {$IFDEF WIN32}, fvExtended {$ENDIF});
  309. end;
  310.  
  311. function FormatFloatStr(const S: string; Thousands: Boolean): string;
  312. var
  313.   I, MaxSym, MinSym, Group: Integer;
  314.   IsSign: Boolean;
  315. begin
  316.   Result := '';
  317.   MaxSym := Length(S);
  318.   IsSign := (MaxSym > 0) and (S[1] in ['-', '+']);
  319.   if IsSign then MinSym := 2
  320.   else MinSym := 1;
  321.   I := Pos(DecimalSeparator, S);
  322.   if I > 0 then MaxSym := I - 1;
  323.   I := Pos('E', AnsiUpperCase(S));
  324.   if I > 0 then MaxSym := Min(I - 1, MaxSym);
  325.   Result := Copy(S, MaxSym + 1, MaxInt);
  326.   Group := 0;
  327.   for I := MaxSym downto MinSym do begin
  328.     Result := S[I] + Result;
  329.     Inc(Group);
  330.     if (Group = 3) and Thousands and (I > MinSym) then begin
  331.       Group := 0;
  332.       Result := ThousandSeparator + Result;
  333.     end;
  334.   end;
  335.   if IsSign then Result := S[1] + Result;
  336. end;
  337.  
  338. { TCustomNumEdit }
  339.  
  340. constructor TCustomNumEdit.Create(AOwner: TComponent);
  341. begin
  342.   inherited Create(AOwner);
  343.   ControlStyle := ControlStyle - [csSetCaption];
  344.   MaxLength := 0;
  345.   FBeepOnError := True;
  346.   FAlignment := taRightJustify;
  347.   FDisplayFormat := DefaultDisplayFormat;
  348.   FDecimalPlaces := 2;
  349.   FZeroEmpty := True;
  350.   inherited Text := '';
  351.   inherited Alignment := taLeftJustify;
  352.   FDefNumGlyphs := 2;
  353.   { forces update }
  354.   DataChanged;
  355.   ControlState := ControlState + [csCreating];
  356.   try
  357.     GlyphKind := gkDefault;
  358.     ButtonWidth := 20;
  359.   finally
  360.     ControlState := ControlState - [csCreating];
  361.   end;
  362. end;
  363.  
  364. destructor TCustomNumEdit.Destroy;
  365. begin
  366.   FCanvas.Free;
  367.   //DisposeStr(FDisplayFormat);
  368.   if FPopup <> nil then begin
  369.     TPopupWindow(FPopup).OnCloseUp := nil;
  370.     FPopup.Free;
  371.     FPopup := nil;
  372.   end;
  373.   inherited Destroy;
  374. end;
  375.  
  376. function TCustomNumEdit.GetDefaultBitmap(var DestroyNeeded: Boolean): TBitmap;
  377. begin
  378.   DestroyNeeded := False;
  379.   if CalcBitmap = nil then begin
  380.     CalcBitmap := TBitmap.Create;
  381.     CalcBitmap.Handle := LoadBitmap(hInstance, sCalcBmp);
  382.   end;
  383.   Result := CalcBitmap;
  384. end;
  385.  
  386. function TCustomNumEdit.DefaultDisplayFormat: string;
  387. begin
  388.   Result := ',0.##';
  389. end;
  390.  
  391. function TCustomNumEdit.IsFormatStored: Boolean;
  392. begin
  393.   Result := (DisplayFormat <> DefaultDisplayFormat);
  394. end;
  395.  
  396. function TCustomNumEdit.IsValidChar(Key: Char): Boolean;
  397. var
  398.   S: string;
  399.   SelStart, SelStop, DecPos: Integer;
  400.   RetValue: Extended;
  401. begin
  402.   Result := False;
  403.   S := EditText;
  404.   GetSel(SelStart, SelStop);
  405.   System.Delete(S, SelStart + 1, SelStop - SelStart);
  406.   System.Insert(Key, S, SelStart + 1);
  407.   S := TextToValText(S);
  408.   DecPos := Pos(DecimalSeparator, S);
  409.   if (DecPos > 0) then begin
  410.     SelStart := Pos('E', UpperCase(S));
  411.     if (SelStart > DecPos) then DecPos := SelStart - DecPos
  412.     else DecPos := Length(S) - DecPos;
  413.     if DecPos > Integer(FDecimalPlaces) then Exit;
  414.   end;
  415.   Result := IsValidFloat(S, RetValue);
  416.   if Result and (FMinValue >= 0) and (FMaxValue > 0) and (RetValue < 0) then
  417.     Result := False;
  418. end;
  419.  
  420. procedure TCustomNumEdit.KeyPress(var Key: Char);
  421. begin
  422.   if PopupVisible and (UpCase(Key) in ['0'..'9', DecimalSeparator, '.', ',',
  423.     '+', '-', '*', '/', '_', '=', 'C', 'R', 'Q', '%', #8, #13] -
  424.     [ThousandSeparator]) then
  425.   begin
  426.     THack(FPopup).KeyPress(Key);
  427.     Key := #0;
  428.   end;
  429.   if Key in ['.', ','] - [ThousandSeparator] then
  430.     Key := DecimalSeparator;
  431.   inherited KeyPress(Key);
  432.   if (Key in [#32..#255]) and not IsValidChar(Key) then begin
  433.     if BeepOnError then MessageBeep(0);
  434.     Key := #0;
  435.   end
  436.   else if Key = #27 then begin
  437.     Reset;
  438.     Key := #0;
  439.   end;
  440. end;
  441.  
  442. procedure TCustomNumEdit.Reset;
  443. begin
  444.   DataChanged;
  445.   SelectAll;
  446. end;
  447.  
  448. procedure TCustomNumEdit.SetZeroEmpty(Value: Boolean);
  449. begin
  450.   if FZeroEmpty <> Value then begin
  451.     FZeroEmpty := Value;
  452.     DataChanged;
  453.   end;
  454. end;
  455.  
  456. procedure TCustomNumEdit.SetBeepOnError(Value: Boolean);
  457. begin
  458.   if FBeepOnError <> Value then begin
  459.     FBeepOnError := Value;
  460.     UpdatePopup;
  461.   end;
  462. end;
  463.  
  464. procedure TCustomNumEdit.SetAlignment(Value: TAlignment);
  465. begin
  466.   if FAlignment <> Value then begin
  467.     FAlignment := Value;
  468.     Invalidate;
  469.   end;
  470. end;
  471.  
  472. procedure TCustomNumEdit.SetDisplayFormat(const Value: string);
  473. begin
  474.   if DisplayFormat <> Value then begin
  475.     FDisplayFormat := Value;
  476.     Invalidate;
  477.     DataChanged;
  478.   end;
  479. end;
  480.  
  481. function TCustomNumEdit.GetDisplayFormat: string;
  482. begin
  483.   Result := FDisplayFormat;
  484. end;
  485.  
  486. procedure TCustomNumEdit.SetFocused(Value: Boolean);
  487. begin
  488.   if FFocused <> Value then begin
  489.     FFocused := Value;
  490.     Invalidate;
  491.     FFormatting := True;
  492.     try
  493.       DataChanged;
  494.     finally
  495.       FFormatting := False;
  496.     end;
  497.   end;
  498. end;
  499.  
  500. procedure TCustomNumEdit.SetFormatOnEditing(Value: Boolean);
  501. begin
  502.   if FFormatOnEditing <> Value then begin
  503.     FFormatOnEditing := Value;
  504.     if FFormatOnEditing then inherited Alignment := Alignment
  505.     else inherited Alignment := taLeftJustify;
  506.     if FFormatOnEditing and FFocused then ReformatEditText
  507.     else if FFocused then begin
  508.       UpdateData;
  509.       DataChanged;
  510.     end;
  511.   end;
  512. end;
  513.  
  514. procedure TCustomNumEdit.SetDecimalPlaces(Value: Cardinal);
  515. begin
  516.   if FDecimalPlaces <> Value then begin
  517.     FDecimalPlaces := Value;
  518.     DataChanged;
  519.     Invalidate;
  520.   end;
  521. end;
  522.  
  523. function TCustomNumEdit.FormatDisplayText(Value: Extended): string;
  524. begin
  525.   if DisplayFormat <> '' then
  526.     Result := FormatFloat(DisplayFormat, Value)
  527.   else
  528.     Result := FloatToStr(Value);
  529. end;
  530.  
  531. function TCustomNumEdit.GetDisplayText: string;
  532. begin
  533.   Result := FormatDisplayText(FValue);
  534. end;
  535.  
  536. procedure TCustomNumEdit.Clear;
  537. begin
  538.   Text := '';
  539. end;
  540.  
  541. procedure TCustomNumEdit.DataChanged;
  542. var
  543.   EditFormat: string;
  544. begin
  545.   EditFormat := '0';
  546.   if FDecimalPlaces > 0 then
  547.     EditFormat := EditFormat + '.' + MakeStr('#', FDecimalPlaces);
  548.   if (FValue = 0.0) and FZeroEmpty then
  549.     EditText := ''
  550.   else
  551.     EditText := FormatFloat(EditFormat, FValue);
  552. end;
  553.  
  554. function TCustomNumEdit.CheckValue(NewValue: Extended;
  555.   RaiseOnError: Boolean): Extended;
  556. begin
  557.   Result := NewValue;
  558.   if (FMaxValue <> FMinValue) then begin
  559.     if (FMaxValue > FMinValue) then begin
  560.       if NewValue < FMinValue then Result := FMinValue
  561.       else if NewValue > FMaxValue then Result := FMaxValue;
  562.     end
  563.     else begin
  564.       if FMaxValue = 0 then begin
  565.         if NewValue < FMinValue then Result := FMinValue;
  566.       end
  567.       else if FMinValue = 0 then begin
  568.         if NewValue > FMaxValue then Result := FMaxValue;
  569.       end;
  570.     end;
  571.     if RaiseOnError and (Result <> NewValue) then
  572.       raise ERangeError.CreateFmt(ReplaceStr(ResStr(SOutOfRange), '%d', '%.*f'),
  573.         [DecimalPlaces, FMinValue, DecimalPlaces, FMaxValue]);
  574.   end;
  575. end;
  576.  
  577. procedure TCustomNumEdit.CheckRange;
  578. begin
  579.   if not (csDesigning in ComponentState) and CheckOnExit then
  580.     CheckValue(StrToFloat(TextToValText(EditText)), True);
  581. end;
  582.  
  583. procedure TCustomNumEdit.UpdateData;
  584. begin
  585.   ValidateEdit;
  586.   FValue := CheckValue(StrToFloat(TextToValText(EditText)), False);
  587. end;
  588.  
  589. procedure TCustomNumEdit.UpdatePopup;
  590. begin
  591.   if FPopup <> nil then
  592.     SetupPopupCalculator(FPopup, DefCalcPrecision, BeepOnError);
  593. end;
  594.  
  595. function TCustomNumEdit.GetValue: Extended;
  596. begin
  597.   if not (csDesigning in ComponentState) then
  598.     try
  599.       UpdateData;
  600.     except
  601.       FValue := FMinValue;
  602.     end;
  603.   Result := FValue;
  604. end;
  605.  
  606. procedure TCustomNumEdit.SetValue(AValue: Extended);
  607. begin
  608.   FValue := CheckValue(AValue, False);
  609.   DataChanged;
  610.   Invalidate;
  611. end;
  612.  
  613. function TCustomNumEdit.GetAsInteger: Longint;
  614. begin
  615.   Result := Trunc(Value);
  616. end;
  617.  
  618. procedure TCustomNumEdit.SetAsInteger(AValue: Longint);
  619. begin
  620.   SetValue(AValue);
  621. end;
  622.  
  623. procedure TCustomNumEdit.SetMinValue(AValue: Extended);
  624. begin
  625.   if FMinValue <> AValue then begin
  626.     FMinValue := AValue;
  627.     Value := FValue;
  628.   end;
  629. end;
  630.  
  631. procedure TCustomNumEdit.SetMaxValue(AValue: Extended);
  632. begin
  633.   if FMaxValue <> AValue then begin
  634.     FMaxValue := AValue;
  635.     Value := FValue;
  636.   end;
  637. end;
  638.  
  639. function TCustomNumEdit.GetText: string;
  640. begin
  641.   Result := inherited Text;
  642. end;
  643.  
  644. function TCustomNumEdit.TextToValText(const AValue: string): string;
  645. begin
  646.   Result := DelRSpace(AValue);
  647.   if DecimalSeparator <> ThousandSeparator then begin
  648.     Result := DelChars(Result, ThousandSeparator);
  649.   end;
  650.   if (DecimalSeparator <> '.') and (ThousandSeparator <> '.') then
  651.     Result := ReplaceStr(Result, '.', DecimalSeparator);
  652.   if (DecimalSeparator <> ',') and (ThousandSeparator <> ',') then
  653.     Result := ReplaceStr(Result, ',', DecimalSeparator);
  654.   if Result = '' then Result := '0'
  655.   else if Result = '-' then Result := '-0';
  656. end;
  657.  
  658. procedure TCustomNumEdit.SetText(const AValue: string);
  659. begin
  660.   if not (csReading in ComponentState) then begin
  661.     FValue := CheckValue(StrToFloat(TextToValText(AValue)), False);
  662.     DataChanged;
  663.     Invalidate;
  664.   end;
  665. end;
  666.  
  667. procedure TCustomNumEdit.ReformatEditText;
  668. var
  669.   S: string;
  670.   IsEmpty: Boolean;
  671.   OldLen, SelStart, SelStop: Integer;
  672. begin
  673.   FFormatting := True;
  674.   try
  675.     S := inherited Text;
  676.     OldLen := Length(S);
  677.     IsEmpty := (OldLen = 0) or (S = '-');
  678.     if HandleAllocated then GetSel(SelStart, SelStop);
  679.     if not IsEmpty then S := TextToValText(S);
  680.     S := FormatFloatStr(S, Pos(',', DisplayFormat) > 0);
  681.     inherited Text := S;
  682.     if HandleAllocated and (GetFocus = Handle) and not
  683.       (csDesigning in ComponentState) then
  684.     begin
  685.       Inc(SelStart, Length(S) - OldLen);
  686.       SetCursor(SelStart);
  687.     end;
  688.   finally
  689.     FFormatting := False;
  690.   end;
  691. end;
  692.  
  693. procedure TCustomNumEdit.Change;
  694. begin
  695.   if not FFormatting then begin
  696.     if FFormatOnEditing and FFocused then ReformatEditText;
  697.     inherited Change;
  698.   end;
  699. end;
  700.  
  701. {$IFDEF WIN32}
  702. procedure TCustomNumEdit.AcceptValue(const Value: Variant);
  703. {$ELSE}
  704. procedure TCustomNumEdit.AcceptValue(const Value: string);
  705. {$ENDIF}
  706. begin
  707.   inherited AcceptValue(Value);
  708. end;
  709.  
  710. procedure TCustomNumEdit.WMPaste(var Message: TMessage);
  711. var
  712.   S: string;
  713. begin
  714.   S := EditText;
  715.   try
  716.     inherited;
  717.     UpdateData;
  718.   except
  719.     EditText := S;
  720.     SelectAll;
  721.     if CanFocus then SetFocus;
  722.     if BeepOnError then MessageBeep(0);
  723.   end;
  724. end;
  725.  
  726. procedure TCustomNumEdit.CMEnter(var Message: TCMEnter);
  727. begin
  728.   SetFocused(True);
  729.   if FFormatOnEditing then ReformatEditText;
  730.   inherited;
  731. end;
  732.  
  733. procedure TCustomNumEdit.CMExit(var Message: TCMExit);
  734. begin
  735.   try
  736.     CheckRange;
  737.     UpdateData;
  738.   except
  739.     SelectAll;
  740.     if CanFocus then SetFocus;
  741.     raise;
  742.   end;
  743.   SetFocused(False);
  744.   SetCursor(0);
  745.   DoExit;
  746. end;
  747.  
  748. procedure TCustomNumEdit.CMEnabledChanged(var Message: TMessage);
  749. begin
  750.   inherited;
  751.   if NewStyleControls and not FFocused then Invalidate;
  752. end;
  753.  
  754. procedure TCustomNumEdit.WMPaint(var Message: TWMPaint);
  755. var
  756.   S: string;
  757. begin
  758.   if PopupVisible then S := TPopupWindow(FPopup).GetPopupText
  759.   else S := GetDisplayText;
  760.   if not PaintComboEdit(Self, S, FAlignment, FFocused and not PopupVisible,
  761.     FCanvas, Message) then inherited;
  762. end;
  763.  
  764. procedure TCustomNumEdit.CMFontChanged(var Message: TMessage);
  765. begin
  766.   inherited;
  767.   Invalidate;
  768. end;
  769.  
  770. { TCurrencyEdit }
  771.  
  772. constructor TCurrencyEdit.Create(AOwner: TComponent);
  773. begin
  774.   inherited Create(AOwner);
  775.   ControlState := ControlState + [csCreating];
  776.   try
  777.     ButtonWidth := 0;
  778.   finally
  779.     ControlState := ControlState - [csCreating];
  780.   end;
  781. end;
  782.  
  783. function TCurrencyEdit.DefaultDisplayFormat: string;
  784. var
  785.   CurrStr: string;
  786.   I: Integer;
  787.   C: Char;
  788. begin
  789.   Result := ',0.' + MakeStr('0', CurrencyDecimals);
  790.   CurrStr := '';
  791.   for I := 1 to Length(CurrencyString) do begin
  792.     C := CurrencyString[I];
  793.     if C in [',', '.'] then CurrStr := CurrStr + '''' + C + ''''
  794.     else CurrStr := CurrStr + C;
  795.   end;
  796.   if Length(CurrStr) > 0 then
  797.     case CurrencyFormat of
  798.       0: Result := CurrStr + Result; { '$1' }
  799.       1: Result := Result + CurrStr; { '1$' }
  800.       2: Result := CurrStr + ' ' + Result; { '$ 1' }
  801.       3: Result := Result + ' ' + CurrStr; { '1 $' }
  802.     end;
  803.   Result := Format('%s;-%s', [Result, Result]);
  804. end;
  805.  
  806. { TRxCustomCalcEdit }
  807.  
  808. constructor TRxCustomCalcEdit.Create(AOwner: TComponent);
  809. begin
  810.   inherited Create(AOwner);
  811.   ControlState := ControlState + [csCreating];
  812.   try
  813.     FPopup := TPopupWindow(CreatePopupCalculator(Self
  814.       {$IFDEF RX_D4}, BiDiMode {$ENDIF}));
  815.     TPopupWindow(FPopup).OnCloseUp := PopupCloseUp;
  816.     UpdatePopup;
  817.   finally
  818.     ControlState := ControlState - [csCreating];
  819.   end;
  820. end;
  821.  
  822. procedure DestroyLocals; far;
  823. begin
  824.   CalcBitmap.Free;
  825.   CalcBitmap := nil;
  826. end;
  827.  
  828. {$IFDEF WIN32}
  829. initialization
  830. finalization
  831.   DestroyLocals;
  832. {$ELSE}
  833. initialization
  834.   AddExitProc(DestroyLocals);
  835. {$ENDIF}
  836. end.