home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 April / Chip_2002-04_cd1.bin / zkuste / delphi / kolekce / d3456 / PBEDIT.ZIP / PBSuperSpin.pas < prev    next >
Pascal/Delphi Source File  |  2002-01-19  |  12KB  |  387 lines

  1. {Author:    Poul Bak}
  2. {}
  3. {Copyright ⌐ 1999 - 2002 : BakSoft-Denmark (Poul Bak). All rights reserved.}
  4. {}
  5. {http://home11.inet.tele.dk/BakSoft/}
  6. {Mailto: baksoft-denmark@dk2net.dk}
  7. {}
  8. {Component Version: 6.00.00.00}
  9. {}
  10. {PBSuperSpin is a PBNumEdit component with spin-buttons.}
  11. {PBSuperSpin can display all that PBNumEdit can.}
  12. {You can use decimal values as Increment.}
  13. {It has a Wrap property that wraps to MinValue when you exceed MaxValue.}
  14. {Accelerated spin when holding down the mouse-button or up/down keys.}
  15. {Can replace standard components without any disadvantages.}
  16.  
  17. {Supports Windows 95, 98 and NT.}
  18. {Supports Default-Button click. (Standard SpinEdit does not).}
  19. {Supports Cancel-button click.}
  20.  
  21. unit PBSuperSpin;
  22.  
  23. interface
  24.  
  25. uses
  26.     Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  27.     StdCtrls, Spin, PBNumEdit;
  28.  
  29. type
  30. {Author:    Poul Bak}
  31. {}
  32. {Copyright ⌐ 1999 - 2002 : BakSoft-Denmark (Poul Bak). All rights reserved.}
  33. {}
  34. {http://home11.inet.tele.dk/BakSoft/}
  35. {Mailto: baksoft-denmark@dk2net.dk}
  36. {}
  37. {Component Version: 6.00.00.00}
  38. {}
  39. {PBSuperSpin is a PBNumEdit component with spin-buttons.}
  40. {PBSuperSpin can display all that PBNumEdit can.}
  41. {You can use decimal values as Increment.}
  42. {Accelerated spin when holding down the mouse-button or up/down keys.}
  43. {It has a Wrap property that wraps to MinValue when you exceed MaxValue.}
  44. {Can replace standard components without any disadvantages.}
  45.  
  46. {Supports Windows 95, 98 and NT.}
  47. {Supports Default-Button click. (Standard SpinEdit does not).}
  48.     TPBSuperSpin = class(TPBNumEdit)
  49.     private
  50.         { Private declarations }
  51.         FButton: TSpinButton;
  52.         FIncrement, TempIncrement : extended;
  53.         FEditorEnabled, FWrap, FRoundValues : Boolean;
  54.         FVersion : string;
  55.         ClickTime : DWord;
  56.         RepeatCount : integer;
  57.         function GetCursor : TCursor;
  58.         function GetMinHeight: Integer;
  59.         procedure SetEditRect;
  60.         procedure WMSize(var Message: TWMSize); message WM_SIZE;
  61.         procedure WMPaste(var Message: TWMPaste); message WM_PASTE;
  62.         procedure WMCut(var Message: TWMCut); message WM_CUT;
  63.         procedure Dummy(Value: string);
  64.         procedure SetCursor(Value : TCursor);
  65.         procedure SetIncrement(Value : extended);
  66.     protected
  67.         { Protected declarations }
  68.         procedure CreateWnd; override;
  69.         procedure DoExit; override;
  70.         procedure DownClick (Sender: TObject);
  71.         procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  72.         procedure KeyPress(var Key: Char); override;
  73.         procedure KeyUp(var Key: Word; Shift: TShiftState); override;
  74.         procedure UpClick (Sender: TObject);
  75.     public
  76.         { Public declarations }
  77.         constructor Create(AOwner: TComponent); override;
  78.         destructor Destroy; override;
  79. {Steps down the Value by Increment. Same as clicking the Up-button except that it
  80. does not accelerate the increment. See also Wrap.}
  81.         procedure DownStep;
  82. {Manually rounds the Value. See RoundValues.}
  83.         procedure RoundValue;
  84. {Steps up the Value by Increment. Same as clicking the Up-button except that it
  85. does not accelerate the increment. See also Wrap.}
  86.         procedure UpStep;
  87.     published
  88.         property Cursor : TCursor read GetCursor write SetCursor;
  89. {EditorEnabled decides whether it is possible to enter a value directly in the editor.}
  90.         property EditorEnabled: Boolean read FEditorEnabled write FEditorEnabled default True;
  91. {Increment is the decimal value that Value steps by when you click the buttons up or down.
  92. If you keep the mouse-button down (or the up/down keys) the value will increase to accelerate the spin.}
  93. //Note: You can set Increment to decimal values like 0.25.
  94.         property Increment: extended read FIncrement write SetIncrement;
  95. {When True: Values will always be MinValue + an integer times Increment.}
  96. {Example: MinValue = 10, Increment = 5. If a user enters say 23 it will be
  97. rounded to 25 upon exit or if a spin-button is pressed.}
  98. {If EditorEnabled is False, it has no purpose.}
  99.         property RoundValues : Boolean read FRoundValues write FRoundValues;
  100. {Read only}
  101.         property Version : string read FVersion write Dummy stored False;
  102. {Wrap decides whether or not the value should stop incrementing when it reaches MaxValue
  103.  or it should wrap around to MinValue (or vice versa when pressing down-button).}
  104.         property Wrap : Boolean read FWrap write FWrap;
  105.     end;
  106.  
  107. procedure Register;
  108.  
  109. implementation
  110.  
  111. constructor TPBSuperSpin.Create(AOwner: TComponent);
  112. begin
  113.     inherited Create(AOwner);
  114.     FButton := TSpinButton.Create(Self);
  115.     FButton.Parent := Self;
  116.     FButton.Width := 15;
  117.     FButton.Height := 17;
  118.     FButton.Visible := True;
  119.     FButton.FocusControl := Self;
  120.     FButton.OnUpClick := UpClick;
  121.     FButton.OnDownClick := DownClick;
  122.     ControlStyle := ControlStyle - [csSetCaption];
  123.     FIncrement := 1;
  124.     TempIncrement := 1;
  125.     FEditorEnabled := True;
  126.     FRoundValues := False;
  127.     FWrap := False;
  128.     FVersion := '6.00.00.00';
  129.     ClickTime := 0;
  130.     RepeatCount := 0;
  131. end;
  132.  
  133. destructor TPBSuperSpin.Destroy;
  134. begin
  135.     FButton.Free;
  136.     FButton := nil;
  137.     inherited Destroy;
  138. end;
  139.  
  140. procedure TPBSuperSpin.KeyDown(var Key: Word; Shift: TShiftState);
  141. begin
  142.     if (not ReadOnly) then
  143.     begin
  144. //        if FEditorEnabled then
  145.         if Key = VK_UP then UpClick (Self)
  146.         else if Key = VK_DOWN then DownClick (Self);
  147.         inherited KeyDown(Key, Shift);
  148.     end
  149.     else
  150.     begin
  151.         MessageBeep(0);
  152.         Key := 0;
  153.     end;
  154. end;
  155.  
  156. procedure TPBSuperSpin.KeyUp(var Key: Word; Shift: TShiftState);
  157. begin
  158.     TempIncrement := FIncrement;
  159.     RepeatCount := 0;
  160.     if (not ReadOnly) then inherited KeyUp(Key, Shift)
  161.     else Key := 0;
  162. end;
  163.  
  164. procedure TPBSuperSpin.KeyPress(var Key: Char);
  165. begin
  166.     if FEditorEnabled then inherited KeyPress(Key)
  167.     else
  168.     begin
  169.         MessageBeep(0);
  170.         Key := #0;
  171.     end;
  172. end;
  173.  
  174. procedure TPBSuperSpin.CreateWnd;
  175. begin
  176.     inherited CreateWnd;
  177.     SetEditRect;
  178. end;
  179.  
  180. procedure TPBSuperSpin.SetEditRect;
  181. var
  182.     Loc: TRect;
  183.     BorderWidth, DX : integer;
  184. begin
  185.     SendMessage(Handle, EM_GETRECT, 0, LongInt(@Loc));
  186.     Loc.Bottom := ClientHeight + 1;  {+1 is workaround for windows paint bug}
  187.     if (BorderStyle = bsSingle) and Ctl3D then BorderWidth := 2
  188.     else if (BorderStyle = bsSingle) then BorderWidth := 1
  189.     else BorderWidth := 0;
  190.     if (BorderStyle = bsNone) then DX := -2
  191.     else DX := 1;
  192.     Loc.Right := ClientWidth - FButton.Width - BorderWidth + DX;
  193.     Loc.Top := 2 - BorderWidth;
  194.     Loc.Left := 2;
  195.     SendMessage(Handle, EM_SETRECT, 0, LongInt(@Loc));
  196. end;
  197.  
  198. procedure TPBSuperSpin.WMSize(var Message: TWMSize);
  199. var
  200.     MinHeight, BorderWidth, Delta : Integer;
  201. begin
  202.     inherited;
  203.     MinHeight := GetMinHeight;
  204.         { text edit bug: if size is less than minheight, then edit ctrl does
  205.             not display the text }
  206.     if Height < MinHeight then Height := MinHeight
  207.     else if FButton <> nil then
  208.     begin
  209.         Delta := 0;
  210.         if (BorderStyle = bsSingle) then
  211.         begin
  212.             if Ctl3D then BorderWidth := 2
  213.             else
  214.             begin
  215.                 BorderWidth := 1;
  216.                 Delta := 1;
  217.             end;
  218.         end
  219.         else BorderWidth := 0;
  220.         FButton.SetBounds(ClientWidth - FButton.Width - Delta, Delta, FButton.Width, Height - BorderWidth * 2 - 1);
  221.         SetEditRect;
  222.     end;
  223. end;
  224.  
  225. function TPBSuperSpin.GetMinHeight: Integer;
  226. var
  227.     DC: HDC;
  228.     SaveFont: HFont;
  229.     I: Integer;
  230.     SysMetrics, Metrics: TTextMetric;
  231. begin
  232.     DC := GetDC(0);
  233.     GetTextMetrics(DC, SysMetrics);
  234.     SaveFont := SelectObject(DC, Font.Handle);
  235.     GetTextMetrics(DC, Metrics);
  236.     SelectObject(DC, SaveFont);
  237.     ReleaseDC(0, DC);
  238.     I := SysMetrics.tmHeight;
  239.     if I > Metrics.tmHeight then I := Metrics.tmHeight;
  240.     Result := Metrics.tmHeight + I div 4 + GetSystemMetrics(SM_CYBORDER) * 4 + 2;
  241. end;
  242.  
  243. procedure TPBSuperSpin.UpClick (Sender: TObject);
  244. begin
  245.     if ReadOnly and (Sender = FButton) then MessageBeep(0)
  246.     else
  247.     begin
  248.         if GetTickCount - ClickTime > 200 then
  249.         begin
  250.             TempIncrement := FIncrement;
  251.             RepeatCount := 0;
  252.         end
  253.         else if TempIncrement < (MaxValue - MinValue) / 5 then
  254.         begin
  255.             Inc(RepeatCount);
  256.             if (RepeatCount > 4) and (RepeatCount mod 2 = 0) then    TempIncrement := TempIncrement + FIncrement;
  257.         end;
  258.         ClickTime := GetTickCount;
  259.         if (Value < MinValue) and ((MinValue <> 0) or (MaxValue <> 0)) then InvalidEntry
  260.         else if (Value + TempIncrement <= MaxValue) or ((MinValue = 0) and (MaxValue = 0)) then Value := Value + TempIncrement
  261.         else if FWrap then Value := MinValue
  262.         else if (Value + FIncrement <= MaxValue) or ((MinValue = 0) and (MaxValue = 0)) then
  263.         begin
  264.             TempIncrement := FIncrement;
  265.             Value := Value + TempIncrement;
  266.         end
  267.         else InvalidEntry;
  268.         if FRoundValues then RoundValue;
  269.     end;
  270. end;
  271.  
  272. procedure TPBSuperSpin.DownClick (Sender: TObject);
  273. begin
  274.     if ReadOnly and (Sender = FButton) then MessageBeep(0)
  275.     else
  276.     begin
  277.         if GetTickCount - ClickTime > 200 then
  278.         begin
  279.             TempIncrement := FIncrement;
  280.             RepeatCount := 0;
  281.         end
  282.         else if TempIncrement < (MaxValue - MinValue) / 5 then
  283.         begin
  284.             Inc(RepeatCount);
  285.             if (RepeatCount > 4) and (RepeatCount mod 2 = 0) then    TempIncrement := TempIncrement + FIncrement;
  286.         end;
  287.         ClickTime := GetTickCount;
  288.         if (Value > MaxValue) and ((MinValue <> 0) or (MaxValue <> 0)) then InvalidEntry
  289.         else if (Value - TempIncrement >= MinValue) or ((MinValue = 0) and (MaxValue = 0)) then Value := Value - TempIncrement
  290.         else if FWrap then Value := MaxValue
  291.         else if (Value - FIncrement >= MinValue) or ((MinValue = 0) and (MaxValue = 0)) then
  292.         begin
  293.             TempIncrement := FIncrement;
  294.             Value := Value - TempIncrement;
  295.         end
  296.         else InvalidEntry;
  297.         if FRoundValues then RoundValue;
  298.     end;
  299. end;
  300.  
  301. procedure TPBSuperSpin.WMPaste(var Message: TWMPaste);
  302. begin
  303.     if not FEditorEnabled or ReadOnly then Exit;
  304.     inherited;
  305. end;
  306.  
  307. procedure TPBSuperSpin.WMCut(var Message: TWMPaste);
  308. begin
  309.     if not FEditorEnabled or ReadOnly then Exit;
  310.     inherited;
  311. end;
  312.  
  313. procedure TPBSuperSpin.Dummy(Value: string);
  314. begin
  315.     // Read-only
  316. end;
  317.  
  318. procedure TPBSuperSpin.DoExit;
  319. begin
  320.     if FRoundValues and (Value >= MinValue) and (Value <= MaxValue)
  321.         or ((MinValue = 0) and (MaxValue = 0)) then RoundValue;
  322.     inherited DoExit;
  323. end;
  324.  
  325. procedure TPBSuperSpin.RoundValue;
  326. var
  327.     X : extended;
  328. begin
  329.     X := Round((Value - MinValue) / FIncrement);
  330.     Value := MinValue + X * FIncrement;
  331.     if (Value > MaxValue) and ((MinValue <> 0) or (MaxValue <> 0)) then Value := Value - FIncrement;
  332. end;
  333.  
  334. function TPBSuperSpin.GetCursor : TCursor;
  335. begin
  336.     Result := inherited Cursor;
  337. end;
  338.  
  339. procedure TPBSuperSpin.SetCursor(Value : TCursor);
  340. begin
  341.     if inherited Cursor <> Value then
  342.     begin
  343.         inherited Cursor := Value;
  344.         FButton.Cursor := Value;
  345.     end;
  346. end;
  347.  
  348. procedure TPBSuperSpin.SetIncrement(Value : extended);
  349. begin
  350.     if (FIncrement <> Value) then
  351.     begin
  352.         if (Value <= MaxValue - MinValue) or ((MinValue = 0) and (MaxValue = 0)) then
  353.         begin
  354.             FIncrement := Value;
  355.             TempIncrement := Value;
  356.             if FRoundValues then RoundValue;
  357.         end;
  358.     end;
  359. end;
  360.  
  361. procedure TPBSuperSpin.DownStep;
  362. begin
  363.     if (Value > MaxValue) and ((MinValue <> 0) or (MaxValue <> 0)) then InvalidEntry
  364.     else if (Value - FIncrement >= MinValue) or ((MinValue = 0) and (MaxValue = 0)) then Value := Value - FIncrement
  365.     else if FWrap then Value := MaxValue
  366.     else InvalidEntry;
  367.     if FRoundValues then RoundValue;
  368. end;
  369.  
  370. procedure TPBSuperSpin.UpStep;
  371. begin
  372.     if (Value < MinValue) and ((MinValue <> 0) or (MaxValue <> 0)) then InvalidEntry
  373.     else if (Value + FIncrement <= MaxValue) or ((MinValue = 0) and (MaxValue = 0))
  374.         then Value := Value + FIncrement
  375.     else if FWrap then Value := MinValue
  376.     else InvalidEntry;
  377.     if FRoundValues then RoundValue;
  378. end;
  379.  
  380. procedure Register;
  381. begin
  382.     RegisterComponents('PB', [TPBSuperSpin]);
  383. end;
  384.  
  385. end.
  386.  
  387.