{

  Copyright (c) 1997-2003 by CoolDev.Com. Part of CoolControls package.

}

{$I versions.inc}
unit CoolScrollbar;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  CoolCtrls, StdCtrls, Db, ExtCtrls, CoolUtils;

type
  // Possible options for the control drawing.
  TDrawOption = (doGlyphUpTransparent, doGlyphDownTransparent, doGlyphThumbTransparent);
  // Set of the TDrawOption type flags.
  TDrawOptions = set of TDrawOption;

  TSBDataLink = class;

  // Enhanced scroll bar control. Enables to paint advanced scrolling control. Wallpapers,
  // transparency, custom glyphs and other options for control customization.
  TCoolScrollbar = class(TCustomControl)
  private
    FAboutBox: TCCAboutBox;
    FRulesRect: TRect;
    FUpBtnRect: TRect;
    FDnBtnRect: TRect;
    FThumbRect: TRect;
    FWallpaper: TBitmap;
    FButtonUpVisible: Boolean;
    FButtonDownVisible: Boolean;
    FButtonDownGlyph: TBitmap;
    FButtonUpGlyph: TBitmap;
    FThumbGlyph: TBitmap;
    FMin: Integer;
    FMax: Integer;
    FPosition: Integer;
    FLargeChange: TScrollBarInc;
    FSmallChange: TScrollBarInc;
    FKind: TScrollBarKind;
    FOnChange: TNotifyEvent;
    FOnScroll: TScrollEvent;
    FPageSize: Integer;
    FStretchThumb: Boolean;
    FProportionalBtn: Boolean;
    FDrawOptions: TDrawOptions;
    FOptions: TCoolOptions;

    FCoolImagesChangeLink: TCoolChangeLink;
    FCoolImages: TCoolImages;
    FidWallpaper: Integer;

    procedure SetCoolImages(Value: TCoolImages);
    procedure SetidWallpaper(Value: Integer);
    procedure CoolImagesChange(Sender: TObject);

    procedure SetTransparent(const Value: Boolean);
    procedure SetFramed(const Value: Boolean);
    procedure SetButtonDownVisible(const Value: Boolean);
    procedure SetButtonUpVisible(const Value: Boolean);
    procedure SetWallpaper(Value: TBitmap);
    function GetWallpaper: TBitmap;
    procedure SetButtonDownGlyph(const Value: TBitmap);
    procedure SetButtonUpGlyph(const Value: TBitmap);
    procedure SetThumbGlyph(const Value: TBitmap);
    function GetTransparent: Boolean;
    function GetFramed: Boolean;
    procedure SetMax(const Value: Integer);
    procedure SetMin(const Value: Integer);
    procedure SetKind(const Value: TScrollBarKind);
    procedure SetPageSize(const Value: Integer);
    procedure SetStretchThumb(const Value: Boolean);
    procedure SetProportionalBtn(const Value: Boolean);
    procedure SetPosition(const Value: Integer);
    procedure SetDrawOptions(const Value: TDrawOptions);
    procedure SetOptions(Value: TCoolOptions);

    function IsWallpaperAssigned: Boolean;
    function CTLDrawWallpaper(DC: HDC; R: TRect; IsStretch: Boolean; Mode: Integer): Boolean;
  protected
    // Sizes of the visible buttons and thumb
    BtnLen: Integer;
    ScrollLen: Integer;
    FMousePos: Integer;
    FThumbLen: Double;
    FPosX, FPosY: Integer;
    FReadOnly: Boolean;
    FRightOfThumbDn: Boolean;
    FLeftOfThumbDn: Boolean;
    FThumbBtnDn: Boolean;
    FLeftBtnDn: Boolean;
    FRightBtnDn: Boolean;
    FMouseDn: Boolean;   { is the left button down? }
    FMouseIn: Boolean;   { is the curosr inside the control? }
    FFocused: Boolean;
    FButtonUp: TBitmap;
    FButtonDown: TBitmap;
    procedure WallpaperChanged(Sender: TObject);
    procedure DrawButtonUp(Down: Boolean);
    procedure DrawButtonDown(Down: Boolean);
    procedure DrawThumb;
    procedure DrawFrame;
    procedure Paint; override;
    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure MouseUp(Btn: TMouseButton; Shift: TShiftState;
      X, Y: Integer); override;
    procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
    procedure WMKillFocus(var Message: TWMSetFocus); message WM_KILLFOCUS;
    procedure CNKeyDown(var Message: TWMKeyDown); message CN_KEYDOWN;
    procedure CNKeyUp(var Message: TWMKeyUp); message CN_KEYUP;
    procedure WMSize(var Message: TMessage); message WM_SIZE;
    function PointInsideRect(const Rc: TRect; X, Y: Integer): Boolean;
    procedure RecalcRect;
    procedure Change; dynamic;
    procedure Scroll(ScrollCode: TScrollCode; var ScrollPos: Integer); dynamic;
    procedure SetEnabled(Value: Boolean); {$IFDEF DELPHI4_OR_ABOVE}override;{$ENDIF}
    procedure TimerEvent(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    // Displays information about the control and package version.
    property About: TCCAboutBox read FAboutBox write FAboutBox;
    // Use CoolImages property to specify  TCoolImages component will be used 
    // to load images for wallpapers from. TcoolImages acts much like 
    // TImageList that is behaves as placeholder for images. It can contain
    // images only but images of different sizes and color modes can be stored 
    // together in the same object.
    property CoolImages: TCoolImages read FCoolImages write SetCoolImages;
    // Determines the extended drawing options and rules.
    // <TABLE>
    // Value                      Meaning
    // --------------             -----------------
    // doGlyphUpTransparent       Whether the up glyph should be painted transparently.
    // doGlyphDownTransparent     Whether the down glyph should be painted transparently.
    // doGlyphThumbTransparent    Whether the thumb glyph should be painted transparently.
    // </TABLE>
    property DrawOptions: TDrawOptions read FDrawOptions write SetDrawOptions;
    // There's an alternative for direct assigning of 
    // the Wallpaper property for cases when you want 
    // to paint the image background for the 
    // control - use CoolImages and idWallpaper properties 
    // for that. This technique allows to save system resources 
    // by sharing the same image between many controls. IdWallpaper 
    // indicates the index of the image from CoolImages to be used. 
    // For controls that have Options property it's necessary to 
    // include ocPaintWallpaper flag (Options property) to enable 
    // the wallpaper painting.
    // 
    // See Also:
    //   Options
    //   CoolImages
    //   Wallpaper
    property idWallpaper: Integer read FidWallpaper write SetidWallpaper default -1;
    // Options property controls variety of various controls parameters, the combination of included and excluded flags
    // determines appearance and behavior of the control. The following items that being used separately or in combination define
    // control's look, note that some flags can not be used together and the others can or even must, note also that not all flags can be supported by the particular control or component.
    // These flags can be used with the following meaning:
    // <P>
    // * <I>ocPaintWallpaper.</I> Whether you want to paint the wallpaper for control. Wallpaper or combination of  CoolImages and idWallpaper properties must be assigned properly.
    // * <I>ocStretchWallpaper.</I> Whether you like to stretch the image to fit all the control surface. If false image will be repeatedly painted to fill the control (tiled).
    // * <I>ocPaintSelWallpaper.</I> Whether you want to paint the wallpaper for selected items. SelWallpaper or combination of  CoolImages and idSelWallpaper properties must be assigned properly.
    // * <I>ocPaintCaptionWallpaper.</I> Whether you want to paint the wallpaper for control's caption (if the latest is visible). CaptionWallpaper or combination of  CoolImages and idCaptionWallpaper properties must be assigned properly.
    // * <I>ocPaintGradiently.</I> Whether you  want to paint the gradient background. Respective color properties define the background range colors.
    // * <I>ocInvertWallpaperAsSelect.</I> Whether you want to use the same wallpaper you use for control to highlight selected items. When presents selected items will be drawn using inverted Wallpaper image, Wallpaper or combination of  CoolImages and idWallpaper properties must be assigned properly.
    // * <I>ocBevelOnlyIfSel.</I> Whether you like to paint bevel around all the control items or only around those selected.
    // * <I>ocNoHighlightImage.</I> If the items have attached images determines whether those for selected items should or should not be highlighted among with the item.
    // * <I>ocNoImageAttached.</I> Whether control presumes that its items some with attached images If not there will not be extra space between border and items
    // * <I>ocUseImageList.</I> Whether images should be taken from the linked Image List component or directly from the Glyph property.
    // * <I>oc3dMDIForm.</I> Whether MDI parent form has more 3D look.
    // * <I>ocWallpaperForMDIChildren.</I> Whether attached wallpaper should be painted for all MDI child windows. Wallpaper or combination of  CoolImages and idWallpaper properties must be assigned properly.
    // * <I>ocNoCaption.</I> Whether control has caption area. Some controls will not have caption even if this property set to True.
    // * <I>ocSmallCaption.</I> What kind of caption should be used for window (if possible) standard or small caption (like for tool windows).
    // * <I>ocNoMDIChildrensCaptions.</I> Whether MDI child windows should  be drawn with the captions.
    // * <I>ocDragUsingClientArea.</I> Is it possible to drag the form using its client area.
    // * <I>ocNoDragUsingCaption.</I> Is it possible to drag the form using its caption area.
    // * <I>ocRoundedForm.</I> Whether the form should have oval shape.
    // * <I>ocFlatBorder.</I> Whether control should be painted with the modern flat look.
    // * <I>ocPaintTransparently.</I> Whether the control should have its own background or use that of the parent container.
    property Options: TCoolOptions read FOptions write SetOptions default [ocNoCaption, ocBevelOnlyIfSel];
    // Use Wallpaper to specify the bitmap image
    // that will be painted as background wallpaper
    // for a control. In most cases CoolControls package
    // requires ocPaintWallpaper flag included into
    // Options property set in order to actually enable
    // wallpaper painting. Mind you that there's an
    // alternative way to attach the image to be painted
    // on control's background - use CoolImages and idWallpaper
    // properties for that. This technique allows to save system 
    // resources by sharing the same image between many controls.
    // 
    // See Also:
    //   Options
    //   idWallpaper
    //   CoolImages
    property Wallpaper: TBitmap read GetWallpaper write SetWallpaper;
    // Glyph for the thumb. Should contain three images. For up, down and mouse in state.
    property ThumbGlyph: TBitmap read FThumbGlyph write SetThumbGlyph;
    // Glyph for the up button. Should contain three images. For up, down and mouse in state.
    property ButtonUpGlyph: TBitmap read FButtonUpGlyph write SetButtonUpGlyph;
    // Glyph for the down button. Should contain three images. For up, down and mouse in state.
    property ButtonDownGlyph: TBitmap read FButtonDownGlyph write SetButtonDownGlyph;
    // Whether we need to paint frame around the control.
    property Framed: Boolean read GetFramed write SetFramed default True;
    // If the control must be painted as transparent or not.
    property Transparent: Boolean read GetTransparent write SetTransparent default False;
    // If the Up button must be painted.
    property ButtonUpVisible: Boolean read FButtonUpVisible write SetButtonUpVisible default True;
    // If the Down button must be painted.
    property ButtonDownVisible: Boolean read FButtonDownVisible write SetButtonDownVisible default True;
    // Whether the thumb image should be stretched accordingly to the control's sizes.
    property StretchThumb: Boolean read FStretchThumb write SetStretchThumb default True;
    // Should the buttons be painted as proportional or not.
    property ProportionalBtn: Boolean read FProportionalBtn write SetProportionalBtn;

    property Align;
{$IFDEF DELPHI5_OR_ABOVE}
    property Anchors;
    property BiDiMode;
    property Constraints;
{$ENDIF}
    property Ctl3D;
    property DragCursor;
{$IFDEF DELPHI5_OR_ABOVE}
    property DragKind;
{$ENDIF}
    property DragMode;
    property Enabled;
    // Set LargeChange to specify how much to change the value of Position when the user clicks on the side of the thumb tab (that is, on the thumb tab track, but not on the thumb tab itself). The Max and Min properties define the total range over which Position can vary.
    // 
    // For example, if Max is 30000 and Min is 0, the scroll box can assume 30,000 positions. If the LargeChange property setting is 10000 and the Position property is 0, the user can click the scroll bar track three times after the thumb tab before it moves all the way to the end of the scroll bar (30000 / 10000 = 3).
    //
    // LargeChange should correspond to the portion of this range that the user sees in one page or screen, expressed in the logical units used by the Max, Min, and Position properties.
    property LargeChange: TScrollBarInc read FLargeChange write FLargeChange default 1;
    // Set Kind to indicate the orientation of the scrollbar. These are the possible values:
    //
    // <TABLE>
    // Value            Meaning
    // ---------        ------------------
    // sbHorizontal	Scroll bar is horizontal
    // sbVertical       Scroll bar is vertical
    // </TABLE>
    property Kind: TScrollBarKind read FKind write SetKind default sbHorizontal;
    // Set Max to the maximum value the Position property can take. The Max and Min properties define the total range over which Position can vary. 
    property Max: Integer read FMax write SetMax default 100;
    // Set Min to the minimum value the Position property can take. The Min and Max properties define the total range over which Position can vary.
    property Min: Integer read FMin write SetMin default 0;
    // et PageSize to the distance along the track bar that corresponds to a single view. The current Position is marked by thumb tab. The PageUp key decrements the value of Position by PageSize, and PageDown key increments the value of Position by PageSize.
    property PageSize: Integer read FPageSize write SetPageSize;
{$IFDEF DELPHI5_OR_ABOVE}
    property ParentBiDiMode;
{$ENDIF}    
    property ParentCtl3D;
    property ParentShowHint;
    property PopupMenu;
    // Read Position to determine the current position of the thumb tab. This value can be used to determine how to scroll any components controlled by the scroll bar. When the user scrolls the scroll bar, the value of Position changes. Set Position to programmatically move the thumb tab of the scroll bar.
    // 
    // The number of possible positions on the scroll bar is determined by the difference between the Max property and the Min property. If Position has the same value as Min, the thumb tab appears at the far left of a horizontal scroll bar or the top of a vertical scroll bar. If Position has the same value as Max, the thumb tab appears at the far right of a horizontal scroll bar or the bottom of a vertical scroll bar.
    property Position: Integer read FPosition write SetPosition default 0;
    property ShowHint;
    // Set SmallChange to specify how much to change the value of Position when the user clicks on the arrow buttons. The Max and Min properties define the total range over which Position can vary.
    // 
    // For example, if Max is 100 and Min is 0, the scroll box can assume 100 positions. If the SmallChange property setting is 5 and the Position property is 0, the user can click the down or right arrow button 20 times before the thumb tab is moved all the way to the end of the scroll bar.
    // 
    // SmallChange should correspond to the portion of this range that the user sees as one line or one item, expressed in the logical units used by the Max, Min, and Position properties.
    property SmallChange: TScrollBarInc read FSmallChange write FSmallChange default 1;
    property TabOrder;
    property TabStop default True;
    property Visible;

    // Occurs when value of the Position property has changed.
    property OnChange: TNotifyEvent read FOnChange write FOnChange;
    {$IFDEF DELPHI5_OR_ABOVE}
    property OnContextPopUp;
    {$ENDIF}
    property OnDragDrop;
    property OnDragOver;
{$IFDEF DELPHI5_OR_ABOVE}
    property OnEndDock;
{$ENDIF}    
    property OnEndDrag;
    property OnEnter;
    property OnExit;
    property OnKeyDown;
    property OnKeyPress;
    property OnKeyUp;
    // Occurs when scroll bar is being scrolled.
    property OnScroll: TScrollEvent read FOnScroll write FOnScroll;
{$IFDEF DELPHI5_OR_ABOVE}
    property OnStartDock;
{$ENDIF}    
    property OnStartDrag;
  end;

  // Data aware version of the TCoolScrollBar.
  TDBCoolScrollbar = class(TCoolScrollbar)
  private
    FDataLink: TSBDataLink;
    function GetDataSource: TDataSource;
    procedure SetDataSource(const Value: TDataSource);
  protected
    procedure Loaded; override;
    procedure Notification(AComponent: TComponent;
      Operation: TOperation); override;
    procedure DataChanged;
    procedure ActiveChanged;
    procedure Scroll(ScrollCode: TScrollCode; var ScrollPos: Integer); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    // Datasource the control is attached to.
    property DataSource: TDataSource read GetDataSource write SetDataSource;
  end;

  TSBDataLink = class(TDataLink)
  private
    FNavigator: TDBCoolScrollbar;
  protected
    procedure DataSetChanged; override;
    procedure ActiveChanged; override;
  public
    constructor Create(ANav: TDBCoolScrollbar);
    destructor Destroy; override;
  end;

implementation

type
  TWinCtl = class(TWinControl);

{ TCoolScrollbar }
constructor TCoolScrollbar.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  ControlStyle := ControlStyle + [csOpaque, csReplicatable, csFramed] +
  [csCaptureMouse, csClickEvents];

  Width := 121;
  Height := GetSystemMetrics(SM_CYHSCROLL);
  FButtonUpVisible := True;
  FButtonDownVisible := True;
  FButtonDownGlyph := TBitmap.Create;
  FButtonUpGlyph := TBitmap.Create;
  FThumbGlyph := TBitmap.Create;

  FButtonUp := TBitmap.Create;
  FButtonDown := TBitmap.Create;
  TabStop := True;
  FKind := sbHorizontal;
  FPosition := 0;
  FMin := 0;
  FMax := 100;
  FSmallChange := 1;
  FLargeChange := 1;
  FStretchThumb := True;
  FReadOnly := False;

  FCoolImagesChangeLink := TCoolChangeLink.Create;
  FCoolImagesChangeLink.OnChange := CoolImagesChange;
  FidWallpaper := -1;
end;

destructor TCoolScrollbar.Destroy;
begin
  FButtonUp.Free;
  FButtonDown.Free;

  FButtonDownGlyph.Free;
  FButtonUpGlyph.Free;
  FThumbGlyph.Free;

  if Assigned(FWallpaper) then FWallPaper.Free;
  FCoolImagesChangeLink.Free;
  inherited Destroy;
end;

function TCoolScrollbar.IsWallpaperAssigned: Boolean;
begin
  Result := (Assigned(FCoolImages) and (FidWallpaper >= 0) and (FidWallpaper <= Pred(FCoolImages.Images.Count)) and Assigned(FCoolImages.Images.Items[FidWallpaper].Bitmap) and not FCoolImages.Images.Items[FidWallpaper].Bitmap.Empty) or
            (Assigned(FWallpaper) and not FWallpaper.Empty);
end;

function TCoolScrollbar.CTLDrawWallpaper(DC: HDC; R: TRect; IsStretch: Boolean; Mode: Integer): Boolean;
begin
  Result := False;
  if Assigned(FCoolImages) and (FidWallpaper >= 0) and (FidWallpaper <= Pred(FCoolImages.Images.Count)) and Assigned(FCoolImages.Images.Items[FidWallpaper].Bitmap) and not FCoolImages.Images.Items[FidWallpaper].Bitmap.Empty then
  begin
    DrawWallpaper(DC, FCoolImages.Images.Items[FidWallpaper].Bitmap, R, IsStretch, Mode);
    Result := True;
  end else
  if Assigned(FWallpaper) and not FWallpaper.Empty then
  begin
    DrawWallpaper(DC, FWallpaper, R, IsStretch, Mode);
    Result := True;
  end;
end;

procedure TCoolScrollbar.SetidWallpaper(Value: Integer);
begin
  if FidWallpaper <> Value then
  begin
    FidWallpaper := Value;
    Invalidate;
  end;
end;

procedure TCoolScrollbar.SetCoolImages(Value: TCoolImages);
begin
  if Assigned(CoolImages) then
    CoolImages.UnRegisterChanges(FCoolImagesChangeLink);

  FCoolImages := Value;

  if Assigned(CoolImages) then
    CoolImages.RegisterChanges(FCoolImagesChangeLink);

  Invalidate;
end;

procedure TCoolScrollbar.CoolImagesChange(Sender: TObject);
begin
  Invalidate;
end;

procedure TCoolScrollbar.DrawButtonDown(Down: Boolean);
var
  MyRect: TRect;

  procedure DrawDnBitmapBtn;
  var
    MyBitmap: TBitmap;
  begin
    if doGlyphDownTransparent in DrawOptions then
    begin
      MyBitmap := TBitmap.Create;
      try
        MyBitmap.Width := MyRect.Right - MyRect.Left;
        MyBitmap.Height := MyRect.Bottom - MyRect.Top;
        MyBitmap.Canvas.CopyRect(Rect(0, 0, MyBitmap.Width, MyBitmap.Height), FButtonDownGlyph.Canvas, MyRect);

        MyBitmap.Transparent := True;
        Canvas.Draw(FDnBtnRect.Left, FDnBtnRect.Top, MyBitmap);
      finally
        MyBitmap.Free;
      end;
    end
    else
      Canvas.CopyRect(FDnBtnRect, FButtonDownGlyph.Canvas, MyRect);
  end;

begin
  if not Enabled then
  begin
    if FButtonDownGlyph.Empty then
    begin
       if Kind = sbHorizontal then
         DrawFrameControl(Canvas.Handle, FDnBtnRect, DFC_SCROLL, DFCS_SCROLLRIGHT
          or DFCS_INACTIVE)
       else
         DrawFrameControl(Canvas.Handle, FDnBtnRect, DFC_SCROLL, DFCS_SCROLLDOWN
          or DFCS_INACTIVE);
    end
    else
    begin
      MyRect := FButtonDownGlyph.Canvas.ClipRect;
      MyRect.Right := MyRect.Right div 3;
      OffsetRect(MyRect, MyRect.Right * 2, 0);
      DrawDnBitmapBtn;
    end;
  end
  else
  if Down then
  begin
    if FButtonDownGlyph.Empty then
    begin
       if Kind = sbHorizontal then
         DrawFrameControl(Canvas.Handle, FDnBtnRect, DFC_SCROLL, DFCS_SCROLLRIGHT
          or DFCS_FLAT)
       else
         DrawFrameControl(Canvas.Handle, FDnBtnRect, DFC_SCROLL, DFCS_SCROLLDOWN
          or DFCS_FLAT);
    end
    else
    begin
      MyRect := FButtonDownGlyph.Canvas.ClipRect;
      MyRect.Right := MyRect.Right div 3;
      OffsetRect(MyRect, MyRect.Right, 0);
      DrawDnBitmapBtn;
    end;
  end
  else
  begin
    if FButtonDownGlyph.Empty then
    begin
       if Kind = sbHorizontal then
         DrawFrameControl(Canvas.Handle, FDnBtnRect, DFC_SCROLL, DFCS_SCROLLRIGHT)
       else
         DrawFrameControl(Canvas.Handle, FDnBtnRect, DFC_SCROLL, DFCS_SCROLLDOWN);
    end
    else
    begin
      MyRect := FButtonDownGlyph.Canvas.ClipRect;
      MyRect.Right := MyRect.Right div 3;
      DrawDnBitmapBtn;
    end;
  end;
end;

procedure TCoolScrollbar.DrawButtonUp(Down: Boolean);
var
  MyRect: TRect;

  procedure DrawUpBitmapBtn;
  var
    MyBitmap: TBitmap;
  begin
    if doGlyphUpTransparent in DrawOptions then
    begin
      MyBitmap := TBitmap.Create;
      try
        MyBitmap.Width := MyRect.Right - MyRect.Left;
        MyBitmap.Height := MyRect.Bottom - MyRect.Top;
        MyBitmap.Canvas.CopyRect(Rect(0, 0, MyBitmap.Width, MyBitmap.Height), FButtonUpGlyph.Canvas, MyRect);

        MyBitmap.Transparent := True;
        Canvas.Draw(FUpBtnRect.Left, FUpBtnRect.Top, MyBitmap);
	      finally
        MyBitmap.Free;
      end;
    end
    else
      Canvas.CopyRect(FUpBtnRect, FButtonUpGlyph.Canvas, MyRect);
  end;

begin
  if not Enabled then
  begin
    if FButtonUpGlyph.Empty then
    begin
       if Kind = sbHorizontal then
         DrawFrameControl(Canvas.Handle, FUpBtnRect, DFC_SCROLL, DFCS_SCROLLLEFT
          or DFCS_INACTIVE)
       else
         DrawFrameControl(Canvas.Handle, FUpBtnRect, DFC_SCROLL, DFCS_SCROLLUP
          or DFCS_INACTIVE);
    end
    else
    begin
      MyRect := FButtonUpGlyph.Canvas.ClipRect;
      MyRect.Right := MyRect.Right div 3;
      OffsetRect(MyRect, MyRect.Right * 2, 0);
      DrawUpBitmapBtn;
    end;
  end
  else
  if Down then
  begin
    if FButtonUpGlyph.Empty then
    begin
       if Kind = sbHorizontal then
         DrawFrameControl(Canvas.Handle, FUpBtnRect, DFC_SCROLL, DFCS_SCROLLLEFT
          or DFCS_FLAT)
       else
         DrawFrameControl(Canvas.Handle, FUpBtnRect, DFC_SCROLL, DFCS_SCROLLUP
          or DFCS_FLAT);
    end
    else
    begin
      MyRect := FButtonUpGlyph.Canvas.ClipRect;
      MyRect.Right := MyRect.Right div 3;
      OffsetRect(MyRect, MyRect.Right, 0);
      DrawUpBitmapBtn;
    end;
  end
  else
  begin
    if FButtonUpGlyph.Empty then
    begin
       if Kind = sbHorizontal then
         DrawFrameControl(Canvas.Handle, FUpBtnRect, DFC_SCROLL, DFCS_SCROLLLEFT)
       else
         DrawFrameControl(Canvas.Handle, FUpBtnRect, DFC_SCROLL, DFCS_SCROLLUP);
    end
    else
    begin
      MyRect := FButtonUpGlyph.Canvas.ClipRect;
      MyRect.Right := MyRect.Right div 3;
      DrawUpBitmapBtn;
    end;
  end;
end;

procedure TCoolScrollbar.DrawFrame;
var
  qrc: TRect;
begin
  qrc := FRulesRect;

  if Transparent then
    PaintBackground(Self, Canvas.Handle, False)
  else
    if IsWallpaperAssigned then
      CTLDrawWallpaper(Canvas.Handle, qrc, False, SRCCOPY)
    else
      begin
{$IFDEF DELPHI5_OR_ABOVE}
        Canvas.Brush.Bitmap := AllocPatternBitmap(clBtnFace, clBtnHighlight);
        Canvas.FillRect(qrc);
{$ELSE}
        PaintPatternBackground(Canvas, qrc);
{$ENDIF}
      end;
end;

procedure TCoolScrollbar.MouseDown(Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);

procedure Delay(msecs : DWORD);
var
  EndTime: DWORD;
begin
  EndTime := GetTickCount + msecs;
  while EndTime > GetTickCount do
    if Application.Terminated then
      Break else Application.ProcessMessages;
end;

begin
  if not FReadOnly then
  begin
    if Button = mbLeft then
    begin
      if ButtonUpVisible and PointInsideRect(FUpBtnRect, X, Y) then
      begin
        FThumbBtnDn := False;
        FRightBtnDn := False;
        FLeftBtnDn := True;
        Invalidate;
        while FLeftBtnDn do
        begin// if mouse inside button we fire event otherwise break
          TimerEvent(Self);
          delay(30);
        end;
      end
      else
        if ButtonDownVisible and PointInsideRect(FDnBtnRect, X, Y) then
        begin
          FThumbBtnDn := False;
          FLeftBtnDn := False;
          FRightBtnDn := True;
          Invalidate;
          while FRightBtnDn do
          begin // if mouse inside button we fire event otherwise break
            TimerEvent(Self);
            delay(30);
          end;
        end
        else
          if PointInsideRect(FThumbRect, X, Y) then
          begin
            // mouse on thumb
            FLeftBtnDn := False;
            FRightBtnDn := False;
            FThumbBtnDn := True;
            if Kind = sbHorizontal then
              FMousePos := X
            else
              FMousePos := Y;
          end
          else
          begin
            FThumbBtnDn := False;
            if Kind = sbHorizontal then
            begin
              FLeftOfThumbDn := X < FThumbRect.Left;
              FRightOfThumbDn := X > FThumbRect.Right;
            end
            else
            begin
              FLeftOfThumbDn := Y < FThumbRect.Top;
              FRightOfThumbDn := Y > FThumbRect.Bottom;
            end;
            while FLeftOfThumbDn do
            begin
              TimerEvent(Self);
              delay(30);
            end;
            while FRightOfThumbDn do
            begin
              TimerEvent(Self);
              delay(30);
            end;
          end;
    end;
    if not Focused then SetFocus;
  end;
  inherited MouseDown(Button, Shift, X, Y);
end;

procedure TCoolScrollbar.Paint;
begin
  DrawFrame;
  if FButtonDownVisible then DrawButtonDown(FRightBtnDn);
  if FButtonUpVisible then DrawButtonUp(FLeftBtnDn);
  DrawThumb();
  if PointInsideRect(FThumbRect, FPosX, FPosY) then
  begin
    //mouse on the thumb
    FLeftBtnDn := False;
    FRightBtnDn := False;
    FLeftOfThumbDn := False;
    FRightOfThumbDn := False;
  end
end;

procedure TCoolScrollbar.SetButtonDownVisible(const Value: Boolean);
begin
  if FButtonDownVisible <> Value then
  begin
    FButtonDownVisible := Value;
    RecalcRect;
    Invalidate;
  end;
end;

procedure TCoolScrollbar.SetButtonUpVisible(const Value: Boolean);
begin
  if FButtonUpVisible <> Value then
  begin
    FButtonUpVisible := Value;
    RecalcRect;
    Invalidate;
  end;
end;

procedure TCoolScrollbar.SetWallpaper(Value: TBitmap);
begin
  if FWallpaper = nil then FWallpaper := TBitmap.Create;
  FWallPaper.Assign(Value);
  Invalidate;
end;

function TCoolScrollbar.GetWallpaper: TBitmap;
begin
  if FWallpaper = nil then FWallpaper := TBitmap.Create;
  Result := FWallpaper;
  Result.OnChange := WallpaperChanged;
end;

procedure TCoolScrollbar.SetFramed(const Value: Boolean);
begin
  if Framed <> Value then
  begin
    if Value then
      ControlStyle := ControlStyle + [csFramed] else
      ControlStyle := ControlStyle - [csFramed];

    Invalidate;
  end;
end;

procedure TCoolScrollbar.SetTransparent(const Value: Boolean);
begin
  if Transparent <> Value then
  begin
    if Value then
      ControlStyle := ControlStyle - [csOpaque] else
      ControlStyle := ControlStyle + [csOpaque];
    Invalidate;
  end;
end;

procedure TCoolScrollbar.WallpaperChanged(Sender: TObject);
begin
  Invalidate;
  Perform(CM_COLORCHANGED, 0, 0);
end;

procedure TCoolScrollbar.SetButtonDownGlyph(const Value: TBitmap);
begin
  FButtonDownGlyph.Assign(Value);
  Invalidate;
end;

procedure TCoolScrollbar.SetButtonUpGlyph(const Value: TBitmap);
begin
  FButtonUpGlyph.Assign(Value);
  Invalidate;
end;

procedure TCoolScrollbar.SetThumbGlyph(const Value: TBitmap);
begin
  FThumbGlyph.Assign(Value);
  Invalidate;
end;

function TCoolScrollbar.GetFramed: Boolean;
begin
  Result := (csFramed in ControlStyle);
end;

function TCoolScrollbar.GetTransparent: Boolean;
begin
  Result := not (csOpaque in ControlStyle);
end;

procedure TCoolScrollbar.SetMax(const Value: Integer);
begin
  if FMax <> Value then
  begin
    FMax := Value;
    if FMax < FMin then FMax := FMin;
    if FPosition > FMax then FPosition := FMax;
    if FPageSize > FMax - FMin + 1 then FPageSize := FMax - FMin + 1;
    if (FPageSize <> 0) then SetPageSize(FPageSize);
    RecalcRect;
    Invalidate;
  end;
end;

procedure TCoolScrollbar.SetMin(const Value: Integer);
begin
  if FMin <> Value then
  begin
    FMin := Value;
    if FMin > FMax then FMin := FMax;
    if FPosition < FMin then FPosition := FMin;
    if FPageSize > FMax - FMin + 1 then FPageSize := FMax - FMin + 1;
    if (FPageSize <> 0) then SetPageSize(FPageSize);
    RecalcRect;
    Invalidate;
  end;
end;

procedure TCoolScrollbar.DrawThumb();
begin
  if FThumbGlyph.Empty then
    DrawFrameControl(Canvas.Handle, FThumbRect, DFC_BUTTON, DFCS_BUTTONPUSH)
  else
  begin
    if doGlyphThumbTransparent in DrawOptions then
    begin
      FThumbGlyph.Transparent := True;
      Canvas.StretchDraw(FThumbRect, FThumbGlyph);
    end
    else
      Canvas.StretchDraw(FThumbRect, FThumbGlyph);
  end;
end;

procedure TCoolScrollbar.WMKillFocus(var Message: TWMSetFocus);
begin
  inherited;
  FFocused := False;
  Invalidate;
end;

procedure TCoolScrollbar.WMSetFocus(var Message: TWMSetFocus);
begin
  inherited;
  FFocused := True;
  Invalidate;
end;

procedure TCoolScrollbar.SetKind(const Value: TScrollBarKind);
begin
  if FKind <> Value then
  begin
    FKind := Value;
    if not (csLoading in ComponentState) then SetBounds(Left, Top, Height, Width);
    RecalcRect;
    Invalidate;
  end;
end;

procedure TCoolScrollbar.SetPosition(const Value: Integer);
var
  OldPosition: Integer;
  OldRect: TRect;
begin
  if Enabled and not FReadOnly then
  begin
    OldRect := FThumbRect;
    OldPosition := FPosition;

    FPosition := Value;
    if FPosition > FMax then FPosition := FMax;
    if FPosition < FMin then FPosition := FMin;
    if OldPosition <> FPosition then
    begin
      RecalcRect;
      InvalidateRect(Handle, @OldRect, True);
      InvalidateRect(Handle, @FThumbRect, True);
      Change;
    end;
  end;
end;

function TCoolScrollbar.PointInsideRect(const Rc: TRect; X, Y: Integer): Boolean;
begin
  if ((X >= Rc.left) and (X <= Rc.right) and
   (Y >= Rc.top) and (Y <= Rc.bottom)) then
    Result := True
  else
    Result := False;
end;

procedure TCoolScrollbar.RecalcRect;
var
  MaxMin: Integer;
  UpBtnLen: Integer;
begin
  BtnLen := 0;
  UpBtnLen := 0;
  MaxMin := (Max - Min);
  if MaxMin < 1 then MaxMin := 1;
  if FKind = sbHorizontal then
  begin
    FUpBtnRect.Left := 0;
    FUpBtnRect.Top := 0;
    FUpBtnRect.Bottom := ClientHeight;
    if FProportionalBtn then
      FUpBtnRect.Right := ClientHeight
    else
      FUpBtnRect.Right := GetSystemMetrics(SM_CYHSCROLL);
    FDnBtnRect := FUpBtnRect;
    OffsetRect(FDnBtnRect, ClientWidth - FDnBtnRect.Right, 0);
    if FButtonUpVisible then
    begin
      UpBtnLen := (FUpBtnRect.Right - FUpBtnRect.Left);
      BtnLen := BtnLen + UpBtnLen;
    end;
    if FButtonDownVisible then
    begin
      BtnLen := BtnLen + (FDnBtnRect.Right - FDnBtnRect.Left);
    end;
    //thumb size
    FThumbRect := FUpBtnRect;
    if (FPageSize <> 0) and FStretchThumb then
    begin
      FThumbRect.Right := Round((ClientWidth - BtnLen) * FThumbLen);
      if FThumbRect.Right < 8 then FThumbRect.Right := 8;
    end;

    BtnLen := BtnLen + (FThumbRect.Right - FThumbRect.Left);
    ScrollLen := ClientWidth - BtnLen;
    OffsetRect(FThumbRect, UpBtnLen + ScrollLen * (Position - Min) div MaxMin, 0);
    FRulesRect.Left := 0;
    FRulesRect.Top := 0;
    FRulesRect.Bottom := ClientHeight;
    FRulesRect.Right := ClientWidth;
    if FButtonUpVisible then
      FRulesRect.Right := FRulesRect.Right - FUpBtnRect.Right;
    if FButtonDownVisible then
      FRulesRect.Right := FRulesRect.Right - FUpBtnRect.Right;
    if FButtonUpVisible then
      OffsetRect(FRulesRect, FUpBtnRect.Right, 0);
  end
  else
  begin
    FUpBtnRect.Left := 0;
    FUpBtnRect.Top := 0;
    FUpBtnRect.Right := ClientWidth;
    if FProportionalBtn then
      FUpBtnRect.Bottom := ClientWidth
    else
      FUpBtnRect.Bottom := GetSystemMetrics(SM_CYHSCROLL);
    FDnBtnRect := FUpBtnRect;
    OffsetRect(FDnBtnRect, 0, ClientHeight - FDnBtnRect.Bottom);
    if FButtonUpVisible then
    begin
      UpBtnLen := (FUpBtnRect.Bottom - FUpBtnRect.Top);
      BtnLen := BtnLen + UpBtnLen;
    end;
    if FButtonDownVisible then
    begin
      BtnLen := BtnLen + (FDnBtnRect.Bottom - FDnBtnRect.Top);
    end;
    //thumb size
    FThumbRect := FUpBtnRect;
    if (FPageSize <> 0) and FStretchThumb then
    begin
      FThumbRect.Bottom := Round((ClientHeight - BtnLen) * FThumbLen);
      if FThumbRect.Bottom < 8 then FThumbRect.Bottom := 8;
    end;

    BtnLen := BtnLen + (FThumbRect.Bottom - FThumbRect.Top);
    ScrollLen := ClientHeight - BtnLen;
    OffsetRect(FThumbRect, 0, UpBtnLen + ScrollLen * (Position - Min) div MaxMin);
    FRulesRect.Left := 0;
    FRulesRect.Top := 0;
    FRulesRect.Right := ClientWidth;

    FRulesRect.Bottom := ClientHeight;
    if FButtonUpVisible then
      FRulesRect.Bottom := FRulesRect.Bottom - FUpBtnRect.Bottom;
    if FButtonDownVisible then
      FRulesRect.Bottom := FRulesRect.Bottom - FUpBtnRect.Bottom;
    if FButtonUpVisible then
      OffsetRect(FRulesRect, 0, FUpBtnRect.Bottom);
  end;
end;

procedure TCoolScrollbar.WMSize(var Message: TMessage);
var
  MinSize: Word;
begin
  inherited;
  if FProportionalBtn then
    MinSize := FUpBtnRect.Right * 3
  else
    MinSize := GetSystemMetrics(SM_CYHSCROLL) * 3;
  if Kind = sbHorizontal then
  begin
    if Message.LParamLo < MinSize then Width := MinSize;
  end
  else
  begin
    if Message.LParamHi < MinSize then Height := MinSize;
  end;
  RecalcRect;
end;

procedure TCoolScrollbar.Change;
begin
  if Assigned(FOnChange) then FOnChange(Self);
end;

procedure TCoolScrollbar.Scroll(ScrollCode: TScrollCode; var ScrollPos: Integer);
begin
  if Assigned(FOnScroll) then FOnScroll(Self, ScrollCode, ScrollPos);
end;

procedure TCoolScrollbar.SetPageSize(const Value: Integer);
var
  Track: Integer;
begin
  FPageSize := Value;
  Track := (Max - Min + 1);
  if Value > Track then FPageSize := Track;
  begin
    FThumbLen := FPageSize / Track;
  end;
  RecalcRect;
  Invalidate;
end;

procedure TCoolScrollbar.SetOptions(Value: TCoolOptions);
begin
  if FOptions <> Value then
  begin
    if (ocPaintTransparently in Value) and (ocPaintWallpaper in FOptions) then
      Exclude(Value, ocPaintWallpaper) else
        if (ocPaintWallpaper in Value) and (ocPaintTransparently in FOptions) then
          Exclude(Value, ocPaintTransparently);

    FOptions := Value;
    Perform(CM_COLORCHANGED, 0, 0);
  end;
end;

procedure TCoolScrollbar.MouseMove(Shift: TShiftState; X, Y: Integer);

  function MouseInCtl(Control: TControl): Boolean;
  var
    P: TPoint;
    R: TRect;
  begin
    Result := Assigned(Control) and Assigned(Control.Parent);
    if Result then
      with Control do
      begin
        GetCursorPos(P);
        P := Parent.ScreenToClient(P);
        R := Rect(Left, Top, Left + Width, Top + Height);
        Result := PtInRect(R, P);
      end;
  end;

var
  FRightBtnDnTmp: Boolean;
  FLeftBtnDnTmp: Boolean;
  NewMousePos: Integer;
  Offset: Real;
  NewPos: Integer;
begin
  if not FReadOnly then
  begin
    FPosX := X;
    FPosY := Y;
    FRightBtnDnTmp := FRightBtnDn;
    FLeftBtnDnTmp := FLeftBtnDn;
    FRightBtnDn := FRightBtnDn and ButtonDownVisible and PointInsideRect(FDnBtnRect, X, Y)
     and (ssLeft in Shift);
    FLeftBtnDn := FLeftBtnDn and ButtonUpVisible and PointInsideRect(FUpBtnRect, X, Y)
     and (ssLeft in Shift);

    if (FRightBtnDnTmp <> FRightBtnDn) or (FLeftBtnDnTmp <> FLeftBtnDn) then
    begin
      Invalidate;
    end;
    if FThumbBtnDn then
    begin
      if Kind = sbHorizontal then
        NewMousePos := X
      else
        NewMousePos := Y;
      if FMousePos <> NewMousePos then
      begin
        if Kind = sbHorizontal then
        begin
          Offset := (FMax - FMin) / ClientWidth;
          NewPos := Round((X - FThumbRect.Left - ((FThumbRect.Right - FThumbRect.Left) div 2)) * Offset);
          Position := Position + NewPos;
        end
        else
        begin
          Offset := (FMax - FMin) / ClientHeight;
          NewPos := Round((Y - FThumbRect.Top - ((FThumbRect.Bottom - FThumbRect.Top) div 2)) * Offset);
          Position := Position + NewPos;
        end;
        Scroll(scTrack, FPosition);
        if Kind = sbHorizontal then
          FMousePos := X
        else
          FMousePos := Y;
      end;
    end;
  end;
  inherited MouseMove(Shift, X, Y);
end;

procedure TCoolScrollbar.MouseUp(Btn: TMouseButton; Shift: TShiftState; X,
  Y: Integer);
var
  RightBtnDnTmp: Boolean;
  LeftBtnDnTmp: Boolean;
begin
  inherited MouseUp(Btn, Shift, X, Y);
  if not FReadOnly then
  begin
    if FThumbBtnDn then
    begin
      Scroll(scPosition, FPosition);
    end;
    RightBtnDnTmp := FRightBtnDn;
    LeftBtnDnTmp := FLeftBtnDn;
    FThumbBtnDn := False;
    FRightBtnDn := False;
    FLeftBtnDn := False;
    FRightOfThumbDn := False;
    FLeftOfThumbDn := False;
    Scroll(scEndScroll, FPosition);
    if RightBtnDnTmp then DrawButtonDown(False);
    if LeftBtnDnTmp then DrawButtonUp(False);

    if (doGlyphUpTransparent in FDrawOptions) or (doGlyphDownTransparent in FDrawOptions) or (doGlyphThumbTransparent in FDrawOptions) then
      Invalidate;
  end;
end;

procedure TCoolScrollbar.SetEnabled(Value: Boolean);
begin
{$IFDEF DELPHI5_OR_ABOVE}
  inherited SetEnabled(Value);
{$ENDIF}  
  Invalidate;
end;

procedure TCoolScrollbar.TimerEvent(Sender: TObject);
begin
  if FLeftBtnDn then
  begin
    Position := FPosition - FSmallChange;
    Scroll(scLineUp, FPosition);
  end
  else
    if FRightBtnDn then
    begin
      Position := FPosition + FSmallChange;
      Scroll(scLineDown, FPosition);
    end
    else
      if FLeftOfThumbDn then
      begin
        Position := FPosition - FLargeChange;
        Scroll(scPageUp, FPosition);
      end
      else
        if FRightOfThumbDn then
        begin
          Position := FPosition + FLargeChange;
          Scroll(scPageDown, FPosition);
        end;
end;

procedure TCoolScrollbar.CNKeyDown(var Message: TWMKeyDown);
begin
  if FReadOnly then
    inherited
  else
  begin
    case Message.CharCode of
     VK_DOWN, VK_RIGHT : begin
                           Position := Position + SmallChange;// SB_LINEDOWN or SB_LINERIGHT
                           Scroll(scLineDown, FPosition);
                         end;
     VK_LEFT, VK_UP : begin
                        Position := Position - SmallChange;// SB_LINEUP or SB_LINELEFT
                        Scroll(scLineUp, FPosition);
                      end;
     VK_NEXT : begin
                 Position := Position + LargeChange;// SB_PAGEDOWN or SB_PAGERIGHT
                 Scroll(scPageDown, FPosition);
               end;
     VK_PRIOR : begin
                  Position := Position - LargeChange;// SB_PAGEUP or SB_PAGELEFT
                  Scroll(scPageUp, FPosition);
                end;
     VK_END : begin
                Position := Max;// SB_BOTTOM
                Scroll(scBottom, FPosition);
              end;
     VK_HOME : begin
                 Position := Min;// SB_TOP
                 Scroll(scTop, FPosition);
               end;
     else inherited;
    end;
  end;
end;

procedure TCoolScrollbar.SetStretchThumb(const Value: Boolean);
begin
  if FStretchThumb <> Value then
  begin
    FStretchThumb := Value;

    if not (csLoading in ComponentState) then
      RecalcRect;

    Invalidate;
  end;
end;

procedure TCoolScrollbar.SetProportionalBtn(const Value: Boolean);
var
  MinSize: Integer;
begin
  if FProportionalBtn <> Value then
  begin
    FProportionalBtn := Value;
    if not (csLoading in ComponentState) then
    begin
      RecalcRect;
      if FProportionalBtn then
        MinSize := FUpBtnRect.Right * 3
      else
        MinSize := GetSystemMetrics(SM_CYHSCROLL) * 3;
      if Kind = sbHorizontal then
      begin
        if Width < MinSize then Width := MinSize;
      end
      else
      begin
        if Height < MinSize then Height := MinSize;
      end;
      RecalcRect;
      Invalidate;
    end;
  end;
end;

procedure TCoolScrollbar.CNKeyUp(var Message: TWMKeyUp);
begin
  if not FReadOnly then
  begin
    case Message.CharCode of
     VK_DOWN, VK_RIGHT, VK_LEFT, VK_UP, VK_NEXT, VK_PRIOR,
     VK_END, VK_HOME:  Scroll(scEndScroll, FPosition);
    end;
  end;
  inherited;
end;

procedure TCoolScrollbar.SetDrawOptions(const Value: TDrawOptions);
begin
  FDrawOptions := Value;
  Invalidate;
end;

{ TSBDataLink }

procedure TSBDataLink.ActiveChanged;
begin
  if FNavigator <> nil then FNavigator.ActiveChanged;
end;

constructor TSBDataLink.Create(ANav: TDBCoolScrollbar);
begin
  inherited Create;
  FNavigator := ANav;
{$IFDEF DELPHI5_OR_ABOVE}
  VisualControl := True;
{$ENDIF}
end;

procedure TSBDataLink.DataSetChanged;
begin
  if FNavigator <> nil then FNavigator.DataChanged;
end;

destructor TSBDataLink.Destroy;
begin
  FNavigator := nil;
  inherited Destroy;
end;

{ TDBCoolScrollbar }

function TDBCoolScrollbar.GetDataSource: TDataSource;
begin
  Result := FDataLink.DataSource;
end;

procedure TDBCoolScrollbar.Notification(AComponent: TComponent;
  Operation: TOperation);
begin
  inherited Notification(AComponent, Operation);
  if (Operation = opRemove) and (FDataLink <> nil) and
    (AComponent = DataSource) then DataSource := nil;
end;

procedure TDBCoolScrollbar.Loaded;
begin
  inherited Loaded;
  RecalcRect;
  ActiveChanged;
end;

procedure TDBCoolScrollbar.SetDataSource(const Value: TDataSource);
begin
  FDataLink.DataSource := Value;
  if not (csLoading in ComponentState) then ActiveChanged;
  if Value <> nil then Value.FreeNotification(Self);
end;

procedure TDBCoolScrollbar.ActiveChanged;
begin
  if not (Enabled and FDataLink.Active) then
  begin
    FReadOnly := True;
  end
  else
  begin
    FReadOnly := False;
    Min := 1;
    Max := FDataLink.DataSet.RecordCount;
    DataChanged;
  end;
end;

procedure TDBCoolScrollbar.DataChanged;
begin
  if Max <> FDataLink.DataSet.RecordCount then
    Max := FDataLink.DataSet.RecordCount;
  if FDataLink.DataSource.DataSet.State = dsBrowse then
    Position := Datasource.DataSet.RecNo;
end;

constructor TDBCoolScrollbar.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FDataLink := TSBDataLink.Create(Self);
  FPageSize := 6;
end;

destructor TDBCoolScrollbar.Destroy;
begin
  FDataLink.Free;
  FDataLink := nil;
  inherited Destroy;
end;

procedure TDBCoolScrollbar.Scroll(ScrollCode: TScrollCode;
  var ScrollPos: Integer);
begin
  inherited Scroll(ScrollCode, ScrollPos);
  if (FPosition <= DataSource.DataSet.RecordCount) and (FPosition >= 0) then
  try
    case ScrollCode of
       scLineDown, scPageDown, scLineUp, scPageUp, scPosition,
         scBottom, scTop : DataSource.DataSet.RecNo := FPosition;
    end;
  except
  end;
end;

end.
