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

Delphi控件源码

开发平台:

Delphi

  1. {*******************************************************}
  2. {                                                       }
  3. {         Delphi VCL Extensions (RX)                    }
  4. {                                                       }
  5. {         Copyright (c) 1995 AO ROSNO                   }
  6. {         Copyright (c) 1997, 1998 Master-Bank          }
  7. {                                                       }
  8. {*******************************************************}
  9. unit RXSpin;
  10. interface
  11. {$I RX.INC}
  12. uses {$IFDEF WIN32} Windows, ComCtrls, {$ELSE} WinTypes, WinProcs, {$ENDIF}
  13.   Controls, ExtCtrls, Classes, Graphics, Messages, Forms, StdCtrls, Menus,
  14.   SysUtils;
  15. type
  16. { TRxSpinButton }
  17.   TSpinButtonState = (sbNotDown, sbTopDown, sbBottomDown);
  18.   TRxSpinButton = class(TGraphicControl)
  19.   private
  20.     FDown: TSpinButtonState;
  21.     FUpBitmap: TBitmap;
  22.     FDownBitmap: TBitmap;
  23.     FDragging: Boolean;
  24.     FInvalidate: Boolean;
  25.     FTopDownBtn: TBitmap;
  26.     FBottomDownBtn: TBitmap;
  27.     FRepeatTimer: TTimer;
  28.     FNotDownBtn: TBitmap;
  29.     FLastDown: TSpinButtonState;
  30.     FFocusControl: TWinControl;
  31.     FOnTopClick: TNotifyEvent;
  32.     FOnBottomClick: TNotifyEvent;
  33.     procedure TopClick;
  34.     procedure BottomClick;
  35.     procedure GlyphChanged(Sender: TObject);
  36.     function GetUpGlyph: TBitmap;
  37.     function GetDownGlyph: TBitmap;
  38.     procedure SetUpGlyph(Value: TBitmap);
  39.     procedure SetDownGlyph(Value: TBitmap);
  40.     procedure SetDown(Value: TSpinButtonState);
  41.     procedure SetFocusControl(Value: TWinControl);
  42.     procedure DrawAllBitmap;
  43.     procedure DrawBitmap(ABitmap: TBitmap; ADownState: TSpinButtonState);
  44.     procedure TimerExpired(Sender: TObject);
  45.     procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
  46.   protected
  47.     procedure Paint; override;
  48.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  49.       X, Y: Integer); override;
  50.     procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
  51.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
  52.       X, Y: Integer); override;
  53.     procedure Notification(AComponent: TComponent;
  54.       Operation: TOperation); override;
  55.   public
  56.     constructor Create(AOwner: TComponent); override;
  57.     destructor Destroy; override;
  58.     property Down: TSpinButtonState read FDown write SetDown default sbNotDown;
  59.   published
  60.     property DragCursor;
  61.     property DragMode;
  62.     property Enabled;
  63.     property Visible;
  64.     property DownGlyph: TBitmap read GetDownGlyph write SetDownGlyph;
  65.     property UpGlyph: TBitmap read GetUpGlyph write SetUpGlyph;
  66.     property FocusControl: TWinControl read FFocusControl write SetFocusControl;
  67.     property ShowHint;
  68.     property ParentShowHint;
  69. {$IFDEF RX_D4}
  70.     property Anchors;
  71.     property Constraints;
  72.     property DragKind;
  73. {$ENDIF}
  74.     property OnBottomClick: TNotifyEvent read FOnBottomClick write FOnBottomClick;
  75.     property OnTopClick: TNotifyEvent read FOnTopClick write FOnTopClick;
  76.     property OnDragDrop;
  77.     property OnDragOver;
  78.     property OnEndDrag;
  79. {$IFDEF WIN32}
  80.     property OnStartDrag;
  81. {$ENDIF}
  82. {$IFDEF RX_D4}
  83.     property OnEndDock;
  84.     property OnStartDock;
  85. {$ENDIF}
  86.   end;
  87. { TRxSpinEdit }
  88. {$IFDEF CBUILDER}
  89.   TValueType = (vtInt, vtFloat, vtHex);
  90. {$ELSE}
  91.   TValueType = (vtInteger, vtFloat, vtHex);
  92. {$ENDIF}
  93. {$IFDEF WIN32}
  94.   TSpinButtonKind = (bkStandard, bkDiagonal);
  95. {$ENDIF}
  96.   TRxSpinEdit = class(TCustomEdit)
  97.   private
  98.     FAlignment: TAlignment;
  99.     FMinValue: Extended;
  100.     FMaxValue: Extended;
  101.     FIncrement: Extended;
  102.     FDecimal: Byte;
  103.     FChanging: Boolean;
  104.     FEditorEnabled: Boolean;
  105.     FValueType: TValueType;
  106.     FButton: TRxSpinButton;
  107.     FBtnWindow: TWinControl;
  108.     FArrowKeys: Boolean;
  109.     FOnTopClick: TNotifyEvent;
  110.     FOnBottomClick: TNotifyEvent;
  111. {$IFDEF WIN32}
  112.     FButtonKind: TSpinButtonKind;
  113.     FUpDown: TCustomUpDown;
  114.     function GetButtonKind: TSpinButtonKind;
  115.     procedure SetButtonKind(Value: TSpinButtonKind);
  116.     procedure UpDownClick(Sender: TObject; Button: TUDBtnType);
  117. {$ENDIF}
  118.     function GetMinHeight: Integer;
  119.     procedure GetTextHeight(var SysHeight, Height: Integer);
  120.     function GetValue: Extended;
  121.     function CheckValue(NewValue: Extended): Extended;
  122.     function GetAsInteger: Longint;
  123.     function IsIncrementStored: Boolean;
  124.     function IsMaxStored: Boolean;
  125.     function IsMinStored: Boolean;
  126.     function IsValueStored: Boolean;
  127.     procedure SetArrowKeys(Value: Boolean);
  128.     procedure SetAsInteger(NewValue: Longint);
  129.     procedure SetValue(NewValue: Extended);
  130.     procedure SetValueType(NewType: TValueType);
  131.     procedure SetDecimal(NewValue: Byte);
  132.     function GetButtonWidth: Integer;
  133.     procedure RecreateButton;
  134.     procedure ResizeButton;
  135.     procedure SetEditRect;
  136.     procedure SetAlignment(Value: TAlignment);
  137.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  138.     procedure CMEnter(var Message: TMessage); message CM_ENTER;
  139.     procedure CMExit(var Message: TCMExit); message CM_EXIT;
  140.     procedure WMPaste(var Message: TWMPaste); message WM_PASTE;
  141.     procedure WMCut(var Message: TWMCut); message WM_CUT;
  142.     procedure CMCtl3DChanged(var Message: TMessage); message CM_CTL3DCHANGED;
  143.     procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
  144.     procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
  145. {$IFDEF RX_D4}
  146.     procedure CMBiDiModeChanged(var Message: TMessage); message CM_BIDIMODECHANGED;
  147. {$ENDIF}
  148.   protected
  149.     procedure Change; override;
  150.     function IsValidChar(Key: Char): Boolean; virtual;
  151.     procedure UpClick(Sender: TObject); virtual;
  152.     procedure DownClick(Sender: TObject); virtual;
  153.     procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  154.     procedure KeyPress(var Key: Char); override;
  155.     procedure CreateParams(var Params: TCreateParams); override;
  156.     procedure CreateWnd; override;
  157.   public
  158.     constructor Create(AOwner: TComponent); override;
  159.     destructor Destroy; override;
  160.     property AsInteger: Longint read GetAsInteger write SetAsInteger default 0;
  161.     property Text;
  162.   published
  163.     property Alignment: TAlignment read FAlignment write SetAlignment
  164.       default taLeftJustify;
  165.     property ArrowKeys: Boolean read FArrowKeys write SetArrowKeys default True;
  166. {$IFDEF WIN32}
  167.     property ButtonKind: TSpinButtonKind read FButtonKind write SetButtonKind
  168.       default bkDiagonal;
  169. {$ENDIF}
  170.     property Decimal: Byte read FDecimal write SetDecimal default 2;
  171.     property EditorEnabled: Boolean read FEditorEnabled write FEditorEnabled default True;
  172.     property Increment: Extended read FIncrement write FIncrement stored IsIncrementStored;
  173.     property MaxValue: Extended read FMaxValue write FMaxValue stored IsMaxStored;
  174.     property MinValue: Extended read FMinValue write FMinValue stored IsMinStored;
  175.     property ValueType: TValueType read FValueType write SetValueType
  176.       default {$IFDEF CBUILDER} vtInt {$ELSE} vtInteger {$ENDIF};
  177.     property Value: Extended read GetValue write SetValue stored IsValueStored;
  178.     property AutoSelect;
  179.     property AutoSize;
  180.     property BorderStyle;
  181.     property Color;
  182.     property Ctl3D;
  183.     property DragCursor;
  184.     property DragMode;
  185.     property Enabled;
  186.     property Font;
  187. {$IFDEF RX_D4}
  188.     property Anchors;
  189.     property BiDiMode;
  190.     property Constraints;
  191.     property DragKind;
  192.     property ParentBiDiMode;
  193. {$ENDIF}
  194. {$IFDEF WIN32}
  195.   {$IFNDEF VER90}
  196.     property ImeMode;
  197.     property ImeName;
  198.   {$ENDIF}
  199. {$ENDIF}
  200.     property MaxLength;
  201.     property ParentColor;
  202.     property ParentCtl3D;
  203.     property ParentFont;
  204.     property ParentShowHint;
  205.     property PopupMenu;
  206.     property ReadOnly;
  207.     property ShowHint;
  208.     property TabOrder;
  209.     property TabStop;
  210.     property Visible;
  211.     property OnBottomClick: TNotifyEvent read FOnBottomClick write FOnBottomClick;
  212.     property OnTopClick: TNotifyEvent read FOnTopClick write FOnTopClick;
  213.     property OnChange;
  214.     property OnClick;
  215.     property OnDblClick;
  216.     property OnDragDrop;
  217.     property OnDragOver;
  218.     property OnEndDrag;
  219.     property OnEnter;
  220.     property OnExit;
  221.     property OnKeyDown;
  222.     property OnKeyPress;
  223.     property OnKeyUp;
  224.     property OnMouseDown;
  225.     property OnMouseMove;
  226.     property OnMouseUp;
  227. {$IFDEF WIN32}
  228.     property OnStartDrag;
  229. {$ENDIF}
  230. {$IFDEF RX_D5}
  231.     property OnContextPopup;
  232. {$ENDIF}
  233. {$IFDEF RX_D4}
  234.     property OnMouseWheelDown;
  235.     property OnMouseWheelUp;
  236.     property OnEndDock;
  237.     property OnStartDock;
  238. {$ENDIF}
  239.   end;
  240. implementation
  241. uses {$IFDEF WIN32} CommCtrl, {$ENDIF} VCLUtils;
  242. {$IFDEF WIN32}
  243.  {$R *.R32}
  244. {$ELSE}
  245.  {$R *.R16}
  246. {$ENDIF}
  247. const
  248.   sSpinUpBtn = 'RXSPINUP';
  249.   sSpinDownBtn = 'RXSPINDOWN';
  250. const
  251.   InitRepeatPause = 400; { pause before repeat timer (ms) }
  252.   RepeatPause     = 100;
  253. { TRxSpinButton }
  254. constructor TRxSpinButton.Create(AOwner: TComponent);
  255. begin
  256.   inherited Create(AOwner);
  257.   FUpBitmap := TBitmap.Create;
  258.   FDownBitmap := TBitmap.Create;
  259.   FUpBitmap.Handle := LoadBitmap(HInstance, sSpinUpBtn);
  260.   FDownBitmap.Handle := LoadBitmap(HInstance, sSpinDownBtn);
  261.   FUpBitmap.OnChange := GlyphChanged;
  262.   FDownBitmap.OnChange := GlyphChanged;
  263.   Height := 20;
  264.   Width := 20;
  265.   FTopDownBtn := TBitmap.Create;
  266.   FBottomDownBtn := TBitmap.Create;
  267.   FNotDownBtn := TBitmap.Create;
  268.   DrawAllBitmap;
  269.   FLastDown := sbNotDown;
  270. end;
  271. destructor TRxSpinButton.Destroy;
  272. begin
  273.   FTopDownBtn.Free;
  274.   FBottomDownBtn.Free;
  275.   FNotDownBtn.Free;
  276.   FUpBitmap.Free;
  277.   FDownBitmap.Free;
  278.   FRepeatTimer.Free;
  279.   inherited Destroy;
  280. end;
  281. procedure TRxSpinButton.GlyphChanged(Sender: TObject);
  282. begin
  283.   FInvalidate := True;
  284.   Invalidate;
  285. end;
  286. function TRxSpinButton.GetUpGlyph: TBitmap;
  287. begin
  288.   Result := FUpBitmap;
  289. end;
  290. procedure TRxSpinButton.SetUpGlyph(Value: TBitmap);
  291. begin
  292.   if Value <> nil then FUpBitmap.Assign(Value)
  293.   else FUpBitmap.Handle := LoadBitmap(HInstance, sSpinUpBtn);
  294. end;
  295. function TRxSpinButton.GetDownGlyph: TBitmap;
  296. begin
  297.   Result := FDownBitmap;
  298. end;
  299. procedure TRxSpinButton.SetDownGlyph(Value: TBitmap);
  300. begin
  301.   if Value <> nil then FDownBitmap.Assign(Value)
  302.   else FDownBitmap.Handle := LoadBitmap(HInstance, sSpinDownBtn);
  303. end;
  304. procedure TRxSpinButton.SetDown(Value: TSpinButtonState);
  305. var
  306.   OldState: TSpinButtonState;
  307. begin
  308.   OldState := FDown;
  309.   FDown := Value;
  310.   if OldState <> FDown then Repaint;
  311. end;
  312. procedure TRxSpinButton.SetFocusControl(Value: TWinControl);
  313. begin
  314.   FFocusControl := Value;
  315. {$IFDEF WIN32}
  316.   if Value <> nil then Value.FreeNotification(Self);
  317. {$ENDIF}
  318. end;
  319. procedure TRxSpinButton.Notification(AComponent: TComponent;
  320.   Operation: TOperation);
  321. begin
  322.   inherited Notification(AComponent, Operation);
  323.   if (Operation = opRemove) and (AComponent = FFocusControl) then
  324.     FFocusControl := nil;
  325. end;
  326. procedure TRxSpinButton.Paint;
  327. begin
  328.   if not Enabled and not (csDesigning in ComponentState) then
  329.     FDragging := False;
  330.   if (FNotDownBtn.Height <> Height) or (FNotDownBtn.Width <> Width) or
  331.     FInvalidate then DrawAllBitmap;
  332.   FInvalidate := False;
  333.   with Canvas do
  334.     case FDown of
  335.       sbNotDown: Draw(0, 0, FNotDownBtn);
  336.       sbTopDown: Draw(0, 0, FTopDownBtn);
  337.       sbBottomDown: Draw(0, 0, FBottomDownBtn);
  338.     end;
  339. end;
  340. procedure TRxSpinButton.DrawAllBitmap;
  341. begin
  342.   DrawBitmap(FTopDownBtn, sbTopDown);
  343.   DrawBitmap(FBottomDownBtn, sbBottomDown);
  344.   DrawBitmap(FNotDownBtn, sbNotDown);
  345. end;
  346. procedure TRxSpinButton.DrawBitmap(ABitmap: TBitmap; ADownState: TSpinButtonState);
  347. var
  348.   R, RSrc: TRect;
  349.   dRect: Integer;
  350.   {Temp: TBitmap;}
  351. begin
  352.   ABitmap.Height := Height;
  353.   ABitmap.Width := Width;
  354.   with ABitmap.Canvas do begin
  355.     R := Bounds(0, 0, Width, Height);
  356.     Pen.Width := 1;
  357.     Brush.Color := clBtnFace;
  358.     Brush.Style := bsSolid;
  359.     FillRect(R);
  360.     { buttons frame }
  361.     Pen.Color := clWindowFrame;
  362.     Rectangle(0, 0, Width, Height);
  363.     MoveTo(-1, Height);
  364.     LineTo(Width, -1);
  365.     { top button }
  366.     if ADownState = sbTopDown then Pen.Color := clBtnShadow
  367.     else Pen.Color := clBtnHighlight;
  368.     MoveTo(1, Height - 4);
  369.     LineTo(1, 1);
  370.     LineTo(Width - 3, 1);
  371.     if ADownState = sbTopDown then Pen.Color := clBtnHighlight
  372.       else Pen.Color := clBtnShadow;
  373.     if ADownState <> sbTopDown then begin
  374.       MoveTo(1, Height - 3);
  375.       LineTo(Width - 2, 0);
  376.     end;
  377.     { bottom button }
  378.     if ADownState = sbBottomDown then Pen.Color := clBtnHighlight
  379.       else Pen.Color := clBtnShadow;
  380.     MoveTo(2, Height - 2);
  381.     LineTo(Width - 2, Height - 2);
  382.     LineTo(Width - 2, 1);
  383.     if ADownState = sbBottomDown then Pen.Color := clBtnShadow
  384.       else Pen.Color := clBtnHighlight;
  385.     MoveTo(2, Height - 2);
  386.     LineTo(Width - 1, 1);
  387.     { top glyph }
  388.     dRect := 1;
  389.     if ADownState = sbTopDown then Inc(dRect);
  390.     R := Bounds(Round((Width / 4) - (FUpBitmap.Width / 2)) + dRect,
  391.       Round((Height / 4) - (FUpBitmap.Height / 2)) + dRect, FUpBitmap.Width,
  392.       FUpBitmap.Height);
  393.     RSrc := Bounds(0, 0, FUpBitmap.Width, FUpBitmap.Height);
  394.     {
  395.     if Self.Enabled or (csDesigning in ComponentState) then
  396.       BrushCopy(R, FUpBitmap, RSrc, FUpBitmap.TransparentColor)
  397.     else begin
  398.       Temp := CreateDisabledBitmap(FUpBitmap, clBlack);
  399.       try
  400.         BrushCopy(R, Temp, RSrc, Temp.TransparentColor);
  401.       finally
  402.         Temp.Free;
  403.       end;
  404.     end;
  405.     }
  406.     BrushCopy(R, FUpBitmap, RSrc, FUpBitmap.TransparentColor);
  407.     { bottom glyph }
  408.     R := Bounds(Round((3 * Width / 4) - (FDownBitmap.Width / 2)) - 1,
  409.       Round((3 * Height / 4) - (FDownBitmap.Height / 2)) - 1,
  410.       FDownBitmap.Width, FDownBitmap.Height);
  411.     RSrc := Bounds(0, 0, FDownBitmap.Width, FDownBitmap.Height);
  412.     {
  413.     if Self.Enabled or (csDesigning in ComponentState) then
  414.       BrushCopy(R, FDownBitmap, RSrc, FDownBitmap.TransparentColor)
  415.     else begin
  416.       Temp := CreateDisabledBitmap(FDownBitmap, clBlack);
  417.       try
  418.         BrushCopy(R, Temp, RSrc, Temp.TransparentColor);
  419.       finally
  420.         Temp.Free;
  421.       end;
  422.     end;
  423.     }
  424.     BrushCopy(R, FDownBitmap, RSrc, FDownBitmap.TransparentColor);
  425.     if ADownState = sbBottomDown then begin
  426.       Pen.Color := clBtnShadow;
  427.       MoveTo(3, Height - 2);
  428.       LineTo(Width - 1, 2);
  429.     end;
  430.   end;
  431. end;
  432. procedure TRxSpinButton.CMEnabledChanged(var Message: TMessage);
  433. begin
  434.   inherited;
  435.   FInvalidate := True;
  436.   Invalidate;
  437. end;
  438. procedure TRxSpinButton.TopClick;
  439. begin
  440.   if Assigned(FOnTopClick) then begin
  441.     FOnTopClick(Self);
  442.     if not (csLButtonDown in ControlState) then FDown := sbNotDown;
  443.   end;
  444. end;
  445. procedure TRxSpinButton.BottomClick;
  446. begin
  447.   if Assigned(FOnBottomClick) then begin
  448.     FOnBottomClick(Self);
  449.     if not (csLButtonDown in ControlState) then FDown := sbNotDown;
  450.   end;
  451. end;
  452. procedure TRxSpinButton.MouseDown(Button: TMouseButton; Shift: TShiftState;
  453.   X, Y: Integer);
  454. begin
  455.   inherited MouseDown(Button, Shift, X, Y);
  456.   if (Button = mbLeft) and Enabled then begin
  457.     if (FFocusControl <> nil) and FFocusControl.TabStop and
  458.       FFocusControl.CanFocus and (GetFocus <> FFocusControl.Handle) then
  459.         FFocusControl.SetFocus;
  460.     if FDown = sbNotDown then begin
  461.       FLastDown := FDown;
  462.       if Y > (-(Height/Width) * X + Height) then begin
  463.         FDown := sbBottomDown;
  464.         BottomClick;
  465.       end
  466.       else begin
  467.         FDown := sbTopDown;
  468.         TopClick;
  469.       end;
  470.       if FLastDown <> FDown then begin
  471.         FLastDown := FDown;
  472.         Repaint;
  473.       end;
  474.       if FRepeatTimer = nil then FRepeatTimer := TTimer.Create(Self);
  475.       FRepeatTimer.OnTimer := TimerExpired;
  476.       FRepeatTimer.Interval := InitRepeatPause;
  477.       FRepeatTimer.Enabled := True;
  478.     end;
  479.     FDragging := True;
  480.   end;
  481. end;
  482. procedure TRxSpinButton.MouseMove(Shift: TShiftState; X, Y: Integer);
  483. var
  484.   NewState: TSpinButtonState;
  485. begin
  486.   inherited MouseMove(Shift, X, Y);
  487.   if FDragging then begin
  488.     if (X >= 0) and (X <= Width) and (Y >= 0) and (Y <= Height) then begin
  489.       NewState := FDown;
  490.       if Y > (-(Width / Height) * X + Height) then begin
  491.         if (FDown <> sbBottomDown) then begin
  492.           if FLastDown = sbBottomDown then FDown := sbBottomDown
  493.           else FDown := sbNotDown;
  494.           if NewState <> FDown then Repaint;
  495.         end;
  496.       end
  497.       else begin
  498.         if (FDown <> sbTopDown) then begin
  499.           if (FLastDown = sbTopDown) then FDown := sbTopDown
  500.           else FDown := sbNotDown;
  501.           if NewState <> FDown then Repaint;
  502.         end;
  503.       end;
  504.     end else
  505.       if FDown <> sbNotDown then begin
  506.         FDown := sbNotDown;
  507.         Repaint;
  508.       end;
  509.   end;
  510. end;
  511. procedure TRxSpinButton.MouseUp(Button: TMouseButton; Shift: TShiftState;
  512.   X, Y: Integer);
  513. begin
  514.   inherited MouseUp(Button, Shift, X, Y);
  515.   if FDragging then begin
  516.     FDragging := False;
  517.     if (X >= 0) and (X <= Width) and (Y >= 0) and (Y <= Height) then begin
  518.       FDown := sbNotDown;
  519.       FLastDown := sbNotDown;
  520.       Repaint;
  521.     end;
  522.   end;
  523. end;
  524. procedure TRxSpinButton.TimerExpired(Sender: TObject);
  525. begin
  526.   FRepeatTimer.Interval := RepeatPause;
  527.   if (FDown <> sbNotDown) and MouseCapture then begin
  528.     try
  529.       if FDown = sbBottomDown then BottomClick else TopClick;
  530.     except
  531.       FRepeatTimer.Enabled := False;
  532.       raise;
  533.     end;
  534.   end;
  535. end;
  536. function DefBtnWidth: Integer;
  537. begin
  538.   Result := GetSystemMetrics(SM_CXVSCROLL);
  539.   if Result > 15 then Result := 15;
  540. end;
  541. {$IFDEF WIN32}
  542. type
  543.   TRxUpDown = class(TCustomUpDown)
  544.   private
  545.     FChanging: Boolean;
  546.     procedure ScrollMessage(var Message: TWMVScroll);
  547.     procedure WMHScroll(var Message: TWMHScroll); message CN_HSCROLL;
  548.     procedure WMVScroll(var Message: TWMVScroll); message CN_VSCROLL;
  549.     procedure WMSize(var Message: TWMSize); message WM_SIZE;
  550.   public
  551.     constructor Create(AOwner: TComponent); override;
  552.     destructor Destroy; override;
  553.   published
  554.     property OnClick;
  555.   end;
  556. constructor TRxUpDown.Create(AOwner: TComponent);
  557. begin
  558.   inherited Create(AOwner);
  559.   Orientation := udVertical;
  560.   Min := -1;
  561.   Max := 1;
  562.   Position := 0;
  563. end;
  564. destructor TRxUpDown.Destroy;
  565. begin
  566.   OnClick := nil;
  567.   inherited Destroy;
  568. end;
  569. procedure TRxUpDown.ScrollMessage(var Message: TWMVScroll);
  570. begin
  571.   if Message.ScrollCode = SB_THUMBPOSITION then begin
  572.     if not FChanging then begin
  573.       FChanging := True;
  574.       try
  575.         if Message.Pos > 0 then Click(btNext)
  576.         else if Message.Pos < 0 then Click(btPrev);
  577.         if HandleAllocated then
  578.           SendMessage(Handle, UDM_SETPOS, 0, 0);
  579.       finally
  580.         FChanging := False;
  581.       end;
  582.     end;
  583.   end;
  584. end;
  585. procedure TRxUpDown.WMHScroll(var Message: TWMHScroll);
  586. begin
  587.   ScrollMessage(TWMVScroll(Message));
  588. end;
  589. procedure TRxUpDown.WMVScroll(var Message: TWMVScroll);
  590. begin
  591.   ScrollMessage(Message);
  592. end;
  593. procedure TRxUpDown.WMSize(var Message: TWMSize);
  594. begin
  595.   inherited;
  596.   if Width <> DefBtnWidth then Width := DefBtnWidth;
  597. end;
  598. {$ENDIF WIN32}
  599. { TRxSpinEdit }
  600. constructor TRxSpinEdit.Create(AOwner: TComponent);
  601. begin
  602.   inherited Create(AOwner);
  603.   Text := '0';
  604.   ControlStyle := ControlStyle - [csSetCaption];
  605.   FIncrement := 1.0;
  606.   FDecimal := 2;
  607.   FEditorEnabled := True;
  608. {$IFDEF WIN32}
  609.   FButtonKind := bkDiagonal;
  610. {$ENDIF}
  611.   FArrowKeys := True;
  612.   RecreateButton;
  613. end;
  614. destructor TRxSpinEdit.Destroy;
  615. begin
  616.   Destroying;
  617.   FChanging := True;
  618.   if FButton <> nil then begin
  619.     FButton.Free;
  620.     FButton := nil;
  621.     FBtnWindow.Free;
  622.     FBtnWindow := nil;
  623.   end;
  624. {$IFDEF WIN32}
  625.   if FUpDown <> nil then begin
  626.     FUpDown.Free;
  627.     FUpDown := nil;
  628.   end;
  629. {$ENDIF}
  630.   inherited Destroy;
  631. end;
  632. procedure TRxSpinEdit.RecreateButton;
  633. begin
  634.   if (csDestroying in ComponentState) then Exit;
  635.   FButton.Free;
  636.   FButton := nil;
  637.   FBtnWindow.Free;
  638.   FBtnWindow := nil;
  639. {$IFDEF WIN32}
  640.   FUpDown.Free;
  641.   FUpDown := nil;
  642.   if GetButtonKind = bkStandard then begin
  643.     FUpDown := TRxUpDown.Create(Self);
  644.     with TRxUpDown(FUpDown) do begin
  645.       Visible := True;
  646.       SetBounds(0, 0, DefBtnWidth, Self.Height);
  647. {$IFDEF RX_D4}
  648.       if (BiDiMode = bdRightToLeft) then Align := alLeft else
  649. {$ENDIF}
  650.       Align := alRight;
  651.       Parent := Self;
  652.       OnClick := UpDownClick;
  653.     end;
  654.   end
  655.   else begin
  656. {$ENDIF}
  657.     FBtnWindow := TWinControl.Create(Self);
  658.     FBtnWindow.Visible := True;
  659.     FBtnWindow.Parent := Self;
  660.     FBtnWindow.SetBounds(0, 0, Height, Height);
  661.     FButton := TRxSpinButton.Create(Self);
  662.     FButton.Visible := True;
  663.     FButton.Parent := FBtnWindow;
  664.     FButton.FocusControl := Self;
  665.     FButton.OnTopClick := UpClick;
  666.     FButton.OnBottomClick := DownClick;
  667.     FButton.SetBounds(0, 0, FBtnWindow.Width, FBtnWindow.Height);
  668. {$IFDEF WIN32}
  669.   end;
  670. {$ENDIF}
  671. end;
  672. procedure TRxSpinEdit.SetArrowKeys(Value: Boolean);
  673. begin
  674.   FArrowKeys := Value;
  675. {$IFDEF WIN32}
  676.   ResizeButton;
  677. {$ENDIF}
  678. end;
  679. {$IFDEF WIN32}
  680. function TRxSpinEdit.GetButtonKind: TSpinButtonKind;
  681. begin
  682.   if NewStyleControls then Result := FButtonKind
  683.   else Result := bkDiagonal;
  684. end;
  685. procedure TRxSpinEdit.SetButtonKind(Value: TSpinButtonKind);
  686. var
  687.   OldKind: TSpinButtonKind;
  688. begin
  689.   OldKind := FButtonKind;
  690.   FButtonKind := Value;
  691.   if OldKind <> GetButtonKind then begin
  692.     RecreateButton;
  693.     ResizeButton;
  694.     SetEditRect;
  695.   end;
  696. end;
  697. procedure TRxSpinEdit.UpDownClick(Sender: TObject; Button: TUDBtnType);
  698. begin
  699.   if TabStop and CanFocus then SetFocus;
  700.   case Button of
  701.     btNext: UpClick(Sender);
  702.     btPrev: DownClick(Sender);
  703.   end;
  704. end;
  705. {$ENDIF WIN32}
  706. function TRxSpinEdit.GetButtonWidth: Integer;
  707. begin
  708. {$IFDEF WIN32}
  709.   if FUpDown <> nil then Result := FUpDown.Width else
  710. {$ENDIF}
  711.   if FButton <> nil then Result := FButton.Width
  712.   else Result := DefBtnWidth;
  713. end;
  714. procedure TRxSpinEdit.ResizeButton;
  715. {$IFDEF WIN32}
  716. var
  717.   R: TRect;
  718. {$ENDIF}
  719. begin
  720. {$IFDEF WIN32}
  721.   if FUpDown <> nil then begin
  722.     FUpDown.Width := DefBtnWidth;
  723.  {$IFDEF RX_D4}
  724.     if (BiDiMode = bdRightToLeft) then FUpDown.Align := alLeft else
  725.  {$ENDIF}
  726.     FUpDown.Align := alRight;
  727.   end
  728.   else if FButton <> nil then begin { bkDiagonal }
  729.     if NewStyleControls and Ctl3D and (BorderStyle = bsSingle) then
  730.       R := Bounds(Width - Height - 1, -1, Height - 3, Height - 3)
  731.     else
  732.       R := Bounds(Width - Height, 0, Height, Height);
  733.  {$IFDEF RX_D4}
  734.     if (BiDiMode = bdRightToLeft) then begin
  735.       if NewStyleControls and Ctl3D and (BorderStyle = bsSingle) then begin
  736.         R.Left := -1;
  737.         R.Right := Height - 4;
  738.       end
  739.       else begin
  740.         R.Left := 0;
  741.         R.Right := Height;
  742.       end;
  743.     end;
  744.  {$ENDIF}
  745.     with R do
  746.       FBtnWindow.SetBounds(Left, Top, Right - Left, Bottom - Top);
  747.     FButton.SetBounds(0, 0, FBtnWindow.Width, FBtnWindow.Height);
  748.   end;
  749. {$ELSE}
  750.   if FButton <> nil then begin
  751.     FBtnWindow.SetBounds(Width - Height, 0, Height, Height);
  752.     FButton.SetBounds(0, 0, FBtnWindow.Width, FBtnWindow.Height);
  753.   end;
  754. {$ENDIF}
  755. end;
  756. procedure TRxSpinEdit.KeyDown(var Key: Word; Shift: TShiftState);
  757. begin
  758.   inherited KeyDown(Key, Shift);
  759.   if ArrowKeys and (Key in [VK_UP, VK_DOWN]) then begin
  760.     if Key = VK_UP then UpClick(Self)
  761.     else if Key = VK_DOWN then DownClick(Self);
  762.     Key := 0;
  763.   end;
  764. end;
  765. procedure TRxSpinEdit.Change;
  766. begin
  767.   if not FChanging then inherited Change;
  768. end;
  769. procedure TRxSpinEdit.KeyPress(var Key: Char);
  770. begin
  771.   if not IsValidChar(Key) then begin
  772.     Key := #0;
  773.     MessageBeep(0)
  774.   end;
  775.   if Key <> #0 then begin
  776.     inherited KeyPress(Key);
  777.     if (Key = Char(VK_RETURN)) or (Key = Char(VK_ESCAPE)) then begin
  778.       { must catch and remove this, since is actually multi-line }
  779.       GetParentForm(Self).Perform(CM_DIALOGKEY, Byte(Key), 0);
  780.       if Key = Char(VK_RETURN) then Key := #0;
  781.     end;
  782.   end;
  783. end;
  784. function TRxSpinEdit.IsValidChar(Key: Char): Boolean;
  785. var
  786.   ValidChars: set of Char;
  787. begin
  788.   ValidChars := ['+', '-', '0'..'9'];
  789.   if ValueType = vtFloat then begin
  790.     if Pos(DecimalSeparator, Text) = 0 then
  791.       ValidChars := ValidChars + [DecimalSeparator];
  792.     if Pos('E', AnsiUpperCase(Text)) = 0 then
  793.       ValidChars := ValidChars + ['e', 'E'];
  794.   end
  795.   else if ValueType = vtHex then begin
  796.     ValidChars := ValidChars + ['A'..'F', 'a'..'f'];
  797.   end;
  798.   Result := (Key in ValidChars) or (Key < #32);
  799.   if not FEditorEnabled and Result and ((Key >= #32) or
  800.     (Key = Char(VK_BACK)) or (Key = Char(VK_DELETE))) then Result := False;
  801. end;
  802. procedure TRxSpinEdit.CreateParams(var Params: TCreateParams);
  803. const
  804. {$IFDEF RX_D4}
  805.   Alignments: array[Boolean, TAlignment] of DWORD =
  806.     ((ES_LEFT, ES_RIGHT, ES_CENTER), (ES_RIGHT, ES_LEFT, ES_CENTER));
  807. {$ELSE}
  808.   Alignments: array[TAlignment] of Longint = (ES_LEFT, ES_RIGHT, ES_CENTER);
  809. {$ENDIF}
  810. begin
  811.   inherited CreateParams(Params);
  812.   Params.Style := Params.Style or ES_MULTILINE or WS_CLIPCHILDREN or
  813. {$IFDEF RX_D4}
  814.     Alignments[UseRightToLeftAlignment, FAlignment];
  815. {$ELSE}
  816.     Alignments[FAlignment];
  817. {$ENDIF}
  818. end;
  819. procedure TRxSpinEdit.CreateWnd;
  820. begin
  821.   inherited CreateWnd;
  822.   SetEditRect;
  823. end;
  824. procedure TRxSpinEdit.SetEditRect;
  825. var
  826.   Loc: TRect;
  827. begin
  828. {$IFDEF RX_D4}
  829.   if (BiDiMode = bdRightToLeft) then
  830.     SetRect(Loc, GetButtonWidth + 1, 0, ClientWidth - 1,
  831.       ClientHeight + 1) else
  832. {$ENDIF RX_D4}
  833.   SetRect(Loc, 0, 0, ClientWidth - GetButtonWidth - 2, ClientHeight + 1);
  834.   SendMessage(Handle, EM_SETRECTNP, 0, Longint(@Loc));
  835. end;
  836. procedure TRxSpinEdit.SetAlignment(Value: TAlignment);
  837. begin
  838.   if FAlignment <> Value then begin
  839.     FAlignment := Value;
  840.     RecreateWnd;
  841.   end;
  842. end;
  843. procedure TRxSpinEdit.WMSize(var Message: TWMSize);
  844. var
  845.   MinHeight: Integer;
  846. begin
  847.   inherited;
  848.   MinHeight := GetMinHeight;
  849.   { text edit bug: if size to less than minheight, then edit ctrl does
  850.     not display the text }
  851.   if Height < MinHeight then
  852.     Height := MinHeight
  853.   else begin
  854.     ResizeButton;
  855.     SetEditRect;
  856.   end;
  857. end;
  858. procedure TRxSpinEdit.GetTextHeight(var SysHeight, Height: Integer);
  859. var
  860.   DC: HDC;
  861.   SaveFont: HFont;
  862.   SysMetrics, Metrics: TTextMetric;
  863. begin
  864.   DC := GetDC(0);
  865.   GetTextMetrics(DC, SysMetrics);
  866.   SaveFont := SelectObject(DC, Font.Handle);
  867.   GetTextMetrics(DC, Metrics);
  868.   SelectObject(DC, SaveFont);
  869.   ReleaseDC(0, DC);
  870.   SysHeight := SysMetrics.tmHeight;
  871.   Height := Metrics.tmHeight;
  872. end;
  873. function TRxSpinEdit.GetMinHeight: Integer;
  874. var
  875.   I, H: Integer;
  876. begin
  877.   GetTextHeight(I, H);
  878.   if I > H then I := H;
  879.   Result := H + {$IFNDEF WIN32} (I div 4) + {$ENDIF}
  880.     (GetSystemMetrics(SM_CYBORDER) * 4) + 1;
  881. end;
  882. procedure TRxSpinEdit.UpClick(Sender: TObject);
  883. var
  884.   OldText: string;
  885. begin
  886.   if ReadOnly then MessageBeep(0)
  887.   else begin
  888.     FChanging := True;
  889.     try
  890.       OldText := inherited Text;
  891.       Value := Value + FIncrement;
  892.     finally
  893.       FChanging := False;
  894.     end;
  895.     if CompareText(inherited Text, OldText) <> 0 then begin
  896.       Modified := True;
  897.       Change;
  898.     end;
  899.     if Assigned(FOnTopClick) then FOnTopClick(Self);
  900.   end;
  901. end;
  902. procedure TRxSpinEdit.DownClick(Sender: TObject);
  903. var
  904.   OldText: string;
  905. begin
  906.   if ReadOnly then MessageBeep(0)
  907.   else begin
  908.     FChanging := True;
  909.     try
  910.       OldText := inherited Text;
  911.       Value := Value - FIncrement;
  912.     finally
  913.       FChanging := False;
  914.     end;
  915.     if CompareText(inherited Text, OldText) <> 0 then begin
  916.       Modified := True;
  917.       Change;
  918.     end;
  919.     if Assigned(FOnBottomClick) then FOnBottomClick(Self);
  920.   end;
  921. end;
  922. {$IFDEF RX_D4}
  923. procedure TRxSpinEdit.CMBiDiModeChanged(var Message: TMessage);
  924. begin
  925.   inherited;
  926.   ResizeButton;
  927.   SetEditRect;
  928. end;
  929. {$ENDIF}
  930. procedure TRxSpinEdit.CMFontChanged(var Message: TMessage);
  931. begin
  932.   inherited;
  933.   ResizeButton;
  934.   SetEditRect;
  935. end;
  936. procedure TRxSpinEdit.CMCtl3DChanged(var Message: TMessage);
  937. begin
  938.   inherited;
  939.   ResizeButton;
  940.   SetEditRect;
  941. end;
  942. procedure TRxSpinEdit.CMEnabledChanged(var Message: TMessage);
  943. begin
  944.   inherited;
  945. {$IFDEF WIN32}
  946.   if FUpDown <> nil then begin
  947.     FUpDown.Enabled := Enabled;
  948.     ResizeButton;
  949.   end;
  950. {$ENDIF}
  951.   if FButton <> nil then FButton.Enabled := Enabled;
  952. end;
  953. procedure TRxSpinEdit.WMPaste(var Message: TWMPaste);
  954. begin
  955.   if not FEditorEnabled or ReadOnly then Exit;
  956.   inherited;
  957. end;
  958. procedure TRxSpinEdit.WMCut(var Message: TWMCut);
  959. begin
  960.   if not FEditorEnabled or ReadOnly then Exit;
  961.   inherited;
  962. end;
  963. procedure TRxSpinEdit.CMExit(var Message: TCMExit);
  964. begin
  965.   inherited;
  966.   if CheckValue(Value) <> Value then SetValue(Value);
  967. end;
  968. procedure TRxSpinEdit.CMEnter(var Message: TMessage);
  969. begin
  970.   if AutoSelect and not (csLButtonDown in ControlState) then SelectAll;
  971.   inherited;
  972. end;
  973. function TRxSpinEdit.GetValue: Extended;
  974. begin
  975.   try
  976.     if ValueType = vtFloat then Result := StrToFloat(Text)
  977.     else if ValueType = vtHex then Result := StrToInt('$' + Text)
  978.     else Result := StrToInt(Text);
  979.   except
  980.     if ValueType = vtFloat then Result := FMinValue
  981.     else Result := Trunc(FMinValue);
  982.   end;
  983. end;
  984. procedure TRxSpinEdit.SetValue(NewValue: Extended);
  985. begin
  986.   if ValueType = vtFloat then
  987.     Text := FloatToStrF(CheckValue(NewValue), ffFixed, 15, FDecimal)
  988.   else if ValueType = vtHex then
  989.     Text := IntToHex(Round(CheckValue(NewValue)), 1)
  990.   else
  991.     Text := IntToStr(Round(CheckValue(NewValue)));
  992. end;
  993. function TRxSpinEdit.GetAsInteger: Longint;
  994. begin
  995.   Result := Trunc(GetValue);
  996. end;
  997. procedure TRxSpinEdit.SetAsInteger(NewValue: Longint);
  998. begin
  999.   SetValue(NewValue);
  1000. end;
  1001. procedure TRxSpinEdit.SetValueType(NewType: TValueType);
  1002. begin
  1003.   if FValueType <> NewType then begin
  1004.     FValueType := NewType;
  1005.     Value := GetValue;
  1006.     if FValueType in [{$IFDEF CBUILDER} vtInt {$ELSE} vtInteger {$ENDIF}, vtHex] then
  1007.     begin
  1008.       FIncrement := Round(FIncrement);
  1009.       if FIncrement = 0 then FIncrement := 1;
  1010.     end;
  1011.   end;
  1012. end;
  1013. function TRxSpinEdit.IsIncrementStored: Boolean;
  1014. begin
  1015.   Result := FIncrement <> 1.0;
  1016. end;
  1017. function TRxSpinEdit.IsMaxStored: Boolean;
  1018. begin
  1019.   Result := (MaxValue <> 0.0);
  1020. end;
  1021. function TRxSpinEdit.IsMinStored: Boolean;
  1022. begin
  1023.   Result := (MinValue <> 0.0);
  1024. end;
  1025. function TRxSpinEdit.IsValueStored: Boolean;
  1026. begin
  1027.   Result := (GetValue <> 0.0);
  1028. end;
  1029. procedure TRxSpinEdit.SetDecimal(NewValue: Byte);
  1030. begin
  1031.   if FDecimal <> NewValue then begin
  1032.     FDecimal := NewValue;
  1033.     Value := GetValue;
  1034.   end;
  1035. end;
  1036. function TRxSpinEdit.CheckValue(NewValue: Extended): Extended;
  1037. begin
  1038.   Result := NewValue;
  1039.   if (FMaxValue <> FMinValue) then begin
  1040.     if NewValue < FMinValue then
  1041.       Result := FMinValue
  1042.     else if NewValue > FMaxValue then
  1043.       Result := FMaxValue;
  1044.   end;
  1045. end;
  1046. end.