Browse Source

added bcfluentslider

Leandro Diaz 1 year ago
parent
commit
ee0aa8a245

+ 602 - 0
bcfluentslider.pas

@@ -0,0 +1,602 @@
+{
+ 2024 by hedgehog
+}
+
+unit BCFluentSlider;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Controls, Graphics, ExtCtrls,
+  ComCtrls,
+  BGRAGraphicControl, BGRABitmapTypes, BCTypes;
+
+type
+
+  TTickPlacement = (tpBottomRight, tpTopLeft);
+  TSliderOrientation = (pbHorizontal, pbVertical, pbRightToLeft, pbTopDown);
+
+  { TBCFluentSlider }
+
+  TBCFluentSlider = class(TCustomBGRAGraphicControl)
+  private
+    FOnChangeValue: TNotifyEvent;
+    FShowTicks: boolean;
+    FThumbState: TBCMouseState;
+    FDeltaThumbPos: TPointF;
+    FFullRect, FDrawRect: TRectF;
+    FThumbRadius: single;
+    FBorderWidth: single;
+    FThumbRect: TRectF;
+    FCenterDrawRect: TPointF;
+    FRealLineWidth: single;
+    FRealLineColor: TBGRAPixel;
+    FOrientation: TSliderOrientation;
+    FStartTickCount: QWord;
+    FAnimationPercent: integer;
+    FStartPercent: integer;
+    FTickFrequency: integer;
+    FTickPlacement: TTickPlacement;
+    FTimer: TTimer;
+    FMaxValue: integer;
+    FMinValue: integer;
+    FValue: integer;
+    FLineColor: TColor;
+    FLineBkgColor: TColor;
+    FLineWidth: integer;
+    procedure CalculateThumbRect;
+    function GetValueFromMouse(X, Y: single): integer;
+    function GetXYFromValue(v: integer): TPointF;
+    procedure SetLineBkgColor(AValue: TColor);
+    procedure SetLineColor(AValue: TColor);
+    procedure SetMaxValue(AValue: integer);
+    procedure SetMinValue(AValue: integer);
+    procedure SetOrientation(AValue: TSliderOrientation);
+    procedure SetShowTicks(AValue: boolean);
+    procedure SetTickFrequency(AValue: integer);
+    procedure SetTickPlacement(AValue: TTickPlacement);
+    procedure SetValue(AValue: integer);
+    procedure SetLineWidth(AValue: integer);
+    procedure DrawBackLine;
+    procedure DrawTicks;
+    procedure DrawThumb;
+    procedure SetStateAnimation(NewState: TBCMouseState);
+  protected
+    procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
+    procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
+      X, Y: Integer); override;
+    procedure MouseUp(Button: TMouseButton; Shift: TShiftState;
+      X, Y: Integer); override;
+    procedure MouseLeave; override;
+    procedure RedrawBitmapContent; override;
+    procedure TimerEvent({%H-}Sender: TObject);
+    procedure TimerStart({%H-}Sender: TObject);
+    procedure DrawBackground; virtual;
+  public
+    constructor Create(AOwner: TComponent); override;
+  published
+    property MinValue: integer read FMinValue write SetMinValue default 0;
+    property MaxValue: integer read FMaxValue write SetMaxValue default 100;
+    property Value: integer read FValue write SetValue default 0;
+    property LineColor: TColor read FLineColor write SetLineColor default
+      TColor($009E5A00);
+    property LineBkgColor: TColor read FLineBkgColor write SetLineBkgColor default
+      TColor($00808080);
+    property LineWidth: integer read FLineWidth write SetLineWidth default 0;
+    property Orientation: TSliderOrientation read FOrientation write SetOrientation default pbHorizontal;
+    property ShowTicks: boolean read FShowTicks write SetShowTicks default false;
+    property OnChangeValue: TNotifyEvent read FOnChangeValue write FOnChangeValue;
+    property TickPlacement: TTickPlacement read FTickPlacement write SetTickPlacement default tpBottomRight;
+    property TickFrequency: integer read FTickFrequency write SetTickFrequency default 10;
+    property OnRedraw;
+    property Align;
+    property Anchors;
+    property BorderSpacing;
+    property Enabled;
+    property Hint;
+    property PopupMenu;
+    property Visible;
+    property OnClick;
+    property OnChangeBounds;
+    property OnDragDrop;
+    property OnDragOver;
+    property OnEndDock;
+    property OnEndDrag;
+    property OnMouseDown;
+    property OnMouseEnter;
+    property OnMouseLeave;
+    property OnMouseMove;
+    property OnMouseUp;
+    property OnMouseWheel;
+    property OnMouseWheelDown;
+    property OnMouseWheelUp;
+    property OnResize;
+    property OnStartDock;
+    property OnStartDrag;
+  end;
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+  RegisterComponents('BGRA Controls', [TBCFluentSlider]);
+end;
+
+
+const
+  ThumbPercentArray: array [TBCMouseState] of integer = (50, 62, 41);
+
+function InflateRectF(const R: TRectF; dxy: single): TRectF;
+begin
+  Result:= RectF(R.Left-dxy, R.Top-dxy, R.Right+dxy, R.Bottom+ dxy);
+end;
+
+function InflateRectF(const R: TRectF; dx, dy: single): TRectF;
+begin
+  Result:= RectF(R.Left-dx, R.Top-dy, R.Right+dx, R.Bottom+ dy);
+end;
+
+function CenterOfRectF(const R: TRectF): TPointF;
+begin
+  Result.x:= (R.Left + R.Right)/2;
+  Result.y:= (R.Top + R.Bottom)/2;
+end;
+
+function ContainsInRectF(const R: TRectF; X, Y: integer): boolean;
+begin
+  Result:=  (X>= R.Left) and (X<= R.Right) and (Y>= R.Top) and (Y<= R.Bottom);
+end;
+
+//  TPointF.Offset() not worked for me(
+function MovePointF(const P: TPointF; dx, dy: integer): TPointF;
+begin
+  Result.x:= P.x + dx;
+  Result.y:= P.Y + dy;
+
+end;
+
+{ TBCFluentSlider }
+
+procedure TBCFluentSlider.SetMaxValue(AValue: integer);
+begin
+  if FMaxValue = AValue then
+    exit;
+  FMaxValue := AValue;
+  if FValue > FMaxValue then
+    FValue := FMaxValue;
+  if FMinValue > FMaxValue then
+    FMinValue := FMaxValue;
+  DiscardBitmap;
+end;
+
+procedure TBCFluentSlider.SetLineBkgColor(AValue: TColor);
+begin
+  if FLineBkgColor = AValue then
+    Exit;
+  FLineBkgColor := AValue;
+  DiscardBitmap;
+end;
+
+procedure TBCFluentSlider.SetLineColor(AValue: TColor);
+begin
+  if FLineColor = AValue then
+    Exit;
+  FLineColor := AValue;
+  DiscardBitmap;
+end;
+
+procedure TBCFluentSlider.SetMinValue(AValue: integer);
+begin
+  if FMinValue = AValue then
+    exit;
+  FMinValue := AValue;
+  if FValue < FMinValue then
+    FValue := FMinValue;
+  if FMaxValue < FMinValue then
+    FMaxValue := FMinValue;
+  DiscardBitmap;
+end;
+
+procedure TBCFluentSlider.SetOrientation(AValue: TSliderOrientation);
+var
+  k: integer;
+begin
+  if FOrientation=AValue then Exit;
+  k:= ord(FOrientation) + ord(AValue)+1;
+  FOrientation:=AValue;
+  if odd(k) or (Width=Height) then
+    DiscardBitmap
+  else
+    SetBounds(Left, Top, Height, Width);
+end;
+
+procedure TBCFluentSlider.SetShowTicks(AValue: boolean);
+begin
+  if FShowTicks=AValue then Exit;
+  FShowTicks:=AValue;
+  DiscardBitmap;
+end;
+
+procedure TBCFluentSlider.SetTickFrequency(AValue: integer);
+begin
+  if FTickFrequency=AValue then Exit;
+  FTickFrequency:=AValue;
+  if FShowTicks then
+    DiscardBitmap;
+end;
+
+procedure TBCFluentSlider.SetTickPlacement(AValue: TTickPlacement);
+begin
+  if FTickPlacement=AValue then Exit;
+  FTickPlacement:=AValue;
+  if FShowTicks then
+    DiscardBitmap;
+end;
+
+procedure TBCFluentSlider.SetValue(AValue: integer);
+begin
+  if FValue = AValue then
+    exit;
+  FValue := AValue;
+  if FValue < FMinValue then
+    FValue := FMinValue;
+  if FValue > FMaxValue then
+    FValue := FMaxValue;
+  DiscardBitmap;
+  if Assigned(FOnChangeValue) then FOnChangeValue(self);
+end;
+
+procedure TBCFluentSlider.SetLineWidth(AValue: integer);
+begin
+  if FLineWidth = AValue then exit;
+  FLineWidth := AValue;
+  DiscardBitmap;
+end;
+
+procedure TBCFluentSlider.DrawBackground;
+begin
+  //todo:
+end;
+
+procedure TBCFluentSlider.DrawBackLine;
+var
+  p, p1, p2: TPointF;
+begin
+  p:= CenterOfRectF(FThumbRect);
+  p1:= p;
+  p2:= p;
+  Bitmap.LineCap := pecRound;
+  case FOrientation of
+    pbHorizontal:
+    begin
+      p1.x:= FDrawRect.Right-1;
+      p2.x:= FDrawRect.Left;
+    end;
+    pbVertical:
+    begin
+      p1.y:= FDrawRect.Top;
+      p2.y:= FDrawRect.Bottom-1;
+    end;
+    pbRightToLeft:
+    begin
+      p1.x:= FDrawRect.Left;
+      p2.x:= FDrawRect.Right-1;
+    end;
+    pbTopDown:
+    begin
+      p1.y:= FDrawRect.Bottom-1;
+      p2.y:= FDrawRect.Top;
+    end;
+  end;
+  if FValue < FMaxValue then
+    Bitmap.DrawLineAntialias(p.x, p.y, p1.x, p1.y, FLineBkgColor, FRealLineWidth);
+  if FValue > FMinValue then
+  begin
+    Bitmap.DrawLineAntialias(p2.x, p2.y, p.x, p.y, FRealLineColor, FRealLineWidth);
+  end;
+end;
+
+procedure TBCFluentSlider.DrawTicks;
+var
+  v: integer;
+  p: TPointF;
+  x, y, tickSize, xy1, xy2: single;
+  c: TBGRAPixel;
+begin
+  if (not FShowTicks) or (FTickFrequency<1) then exit;
+  c:= FLineBkgColor;
+  tickSize:= Scale96ToScreen(40)/10;
+  if FTickPlacement = tpBottomRight then
+  begin
+    xy2:= FThumbRadius;
+    xy1:= xy2 - tickSize;
+  end
+  else
+  begin
+    xy2:= -FThumbRadius;
+    xy1:= xy2 + tickSize;
+  end;
+  v:= (FMinValue div FTickFrequency)*FTickFrequency;
+  if v < FMinValue then
+    v+= FTickFrequency;
+
+  while v<= FMaxValue do
+  begin
+    p:= GetXYFromValue(v);
+    if (FOrientation = pbHorizontal) or (FOrientation = pbRightToLeft) then
+    begin
+      if FBorderWidth<2 then x:= round(p.x) else x:= p.x;
+      Bitmap.DrawLineAntialias(x, p.y + xy1, x, p.y+ xy2, c, FBorderWidth);
+    end
+    else
+    begin
+      if FBorderWidth<2 then y:= round(p.y) else y:= p.y;
+      Bitmap.DrawLineAntialias(x + xy1, y, x+ xy2, y, c, FBorderWidth);
+    end;
+    v+= FTickFrequency;
+  end;
+end;
+
+procedure TBCFluentSlider.DrawThumb;
+var
+  r: single;
+  c: TBGRAPixel;
+  p: TPointF;
+begin
+  c:= BGRABlack;
+  c.alpha:= 50;
+  p:= CenterOfRectF(FThumbRect);
+  r:= FThumbRadius-FBorderWidth/2;
+  Bitmap.EllipseAntialias(p.X, p.Y, r, r, c, FBorderWidth);
+  c:= BGRAWhite;
+  c.alpha:= 220;
+  r:= FThumbRadius-FBorderWidth;
+  Bitmap.FillEllipseAntialias(p.X, p.Y, r, r, c);
+  c:= FRealLineColor;
+  if FTimer.Enabled then
+    r:= FThumbRadius*FAnimationPercent/100
+  else
+  begin
+    r:= FThumbRadius*ThumbPercentArray[FThumbState]/100;
+    if FThumbState = msClicked then
+      c.alpha:= 220;
+  end;
+  Bitmap.FillEllipseAntialias(p.X, p.Y, r, r, c);
+end;
+
+procedure TBCFluentSlider.MouseMove(Shift: TShiftState; X, Y: Integer);
+begin
+  if (FThumbState = msClicked) then
+  begin
+    SetValue(GetValueFromMouse(X+FDeltaThumbPos.x, Y+FDeltaThumbPos.y));
+  end
+  else if (FThumbState = msHover) then
+  begin
+    if not ContainsInRectF(FThumbRect, X, Y) then
+      SetStateAnimation(msNone);
+  end
+  else if (FThumbState = msNone) then
+  begin
+    if ContainsInRectF(FThumbRect, X, Y) then
+      SetStateAnimation(msHover);
+  end;
+  inherited MouseMove(Shift, X, Y);
+end;
+
+procedure TBCFluentSlider.SetStateAnimation(NewState: TBCMouseState);
+begin
+  if FTimer.Enabled then
+  begin
+    FStartPercent:= FAnimationPercent;
+    FTimer.Enabled:= false;
+  end
+  else
+  begin
+    FStartPercent:= ThumbPercentArray[FThumbState];
+  end;
+  FThumbState:= NewState;
+  FTimer.Enabled:= true;
+end;
+
+procedure TBCFluentSlider.MouseDown(Button: TMouseButton; Shift: TShiftState;
+  X, Y: Integer);
+begin
+  if Button = mbLeft then
+  begin
+    if FThumbState = msHover then
+    begin
+      FDeltaThumbPos:= MovePointF(CenterOfRectF(FThumbRect), -X, -Y);
+      SetStateAnimation(msClicked);
+    end
+    else
+    begin
+      FThumbState:= msClicked;
+      FDeltaThumbPos:= PointF(0, 0);
+      SetValue(GetValueFromMouse(X, Y));
+    end;
+  end;
+  inherited;
+end;
+
+function TBCFluentSlider.GetValueFromMouse(X, Y: single): integer;
+
+  function GetValPos(k: double): integer; inline;
+  begin
+    Result:= round(FMinValue +(FMaxValue - FMinValue)*k);
+  end;
+
+var
+  R: TRectF;
+begin
+  R:= InflateRectF(FFullRect, - FThumbRadius);
+  case FOrientation of
+    pbHorizontal:
+      begin
+        if X< R.Left then Result:= FMinValue
+        else if X> R.Right then Result:= FMaxValue
+        else Result:= GetValPos((X - R.Left)/(R.Width-1));
+      end;
+    pbVertical:
+      begin
+        if Y> R.Bottom then Result:= FMinValue
+        else if Y< R.Top then Result:= FMaxValue
+        else Result:= GetValPos((R.Bottom - Y)/(R.Height-1));
+      end;
+    pbRightToLeft:
+      begin
+        if X< R.Left then Result:= FMaxValue
+        else if X> R.Right then Result:= FMinValue
+        else Result:= GetValPos((R.Right - X)/(R.Width-1));
+      end;
+    pbTopDown:
+    begin
+      if Y> R.Bottom then Result:= FMaxValue
+      else if Y< R.Top then Result:= FMinValue
+      else Result:= GetValPos((Y - R.Top)/(R.Height-1));
+    end;
+  end;
+end;
+
+procedure TBCFluentSlider.MouseUp(Button: TMouseButton; Shift: TShiftState; X,
+  Y: Integer);
+begin
+  if (Button = mbLeft) and (FThumbState = msClicked) then
+  begin
+    if ContainsInRectF(FThumbRect, X, Y) then
+      SetStateAnimation(msHover)
+    else
+      SetStateAnimation(msNone);
+  end;
+  inherited MouseUp(Button, Shift, X, Y);
+end;
+
+procedure TBCFluentSlider.MouseLeave;
+begin
+  if FThumbState = msHover then
+    SetStateAnimation(msNone);
+  inherited MouseLeave;
+end;
+
+function TBCFluentSlider.GetXYFromValue(v: integer): TPointF;
+var
+  k: double;
+  R: TRectF;
+  p: TPointF;
+begin
+  R:= InflateRectF(FFullRect, -FThumbRadius);
+  k:= (v- FMinValue)/(FMaxValue - FMinValue);
+  p:= FCenterDrawRect;
+  case FOrientation of
+    pbHorizontal:  p.x:=
+      R.Left + (R.Width-1)*k;
+    pbVertical:    p.y:=
+      R.Bottom -1 - (R.Height-1)*k;
+    pbRightToLeft: p.x:=
+      R.Right -1 - (R.Width-1)*k;
+    pbTopDown:     p.y:=
+      R.Top + (R.Height-1)*k;
+  end;
+  Result:= p;
+end;
+
+procedure TBCFluentSlider.CalculateThumbRect;
+var
+  k: double;
+  R: TRectF;
+  p: TPointF;
+begin
+   FThumbRadius:= Scale96ToScreen(11);
+  if FLineWidth<1 then
+    FRealLineWidth:= Scale96ToScreen(40)/10
+  else
+    FRealLineWidth:= Scale96ToScreen(FLineWidth*10)/10;
+  FBorderWidth:= Scale96ToScreen(10)/10;
+  FFullRect:= RectF(ClientRect);
+  FDrawRect:= InflateRectF(FFullRect, -FRealLineWidth/2);
+  R:= InflateRectF(FFullRect, -FThumbRadius);
+  FCenterDrawRect := CenterOfRectF(FDrawRect);
+  k:= (FValue- FMinValue)/(FMaxValue - FMinValue);
+  p:= FCenterDrawRect;
+  case FOrientation of
+    pbHorizontal:  p.x:=
+      R.Left + (R.Width-1)*k;
+    pbVertical:    p.y:=
+      R.Bottom -1 - (R.Height-1)*k;
+    pbRightToLeft: p.x:=
+      R.Right -1 - (R.Width-1)*k;
+    pbTopDown:     p.y:=
+      R.Top + (R.Height-1)*k;
+  end;
+  FThumbRect:= RectF(
+    p.x - FThumbRadius,
+    p.y - FThumbRadius,
+    p.x + FThumbRadius,
+    p.y + FThumbRadius);
+end;
+
+procedure TBCFluentSlider.RedrawBitmapContent;
+begin
+  CalculateThumbRect;
+  DrawBackground;
+  FRealLineColor:= FLineColor;
+  if not Enabled then
+    FRealLineColor:= FRealLineColor.ToGrayscale;
+  DrawBackLine;
+  DrawTicks;
+  DrawThumb;
+  if Assigned(OnRedraw) then
+    OnRedraw(self, FBGRA);
+end;
+
+procedure TBCFluentSlider.TimerEvent(Sender: TObject);
+var
+  TickCount: QWord;
+  FAnimationTime: Int64;
+const
+  Duration = 130; // ms
+begin
+  TickCount:= GetTickCount64;
+  FAnimationTime:= TickCount - FStartTickCount;
+  if FAnimationTime >= Duration then
+    FTimer.Enabled:= false
+  else
+    FAnimationPercent:= FStartPercent+
+      round(FAnimationTime*(ThumbPercentArray[FThumbState] - FStartPercent)/Duration);
+  DiscardBitmap;
+end;
+
+procedure TBCFluentSlider.TimerStart(Sender: TObject);
+begin
+  FStartTickCount:= GetTickCount64;
+end;
+
+constructor TBCFluentSlider.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  FThumbState:= msNone;
+  FOrientation:= pbHorizontal;
+  FTickFrequency:= 10;
+  FTimer:= TTimer.Create(self);
+  FTimer.Interval := 15;
+  FTimer.Enabled := false;
+  FTimer.OnTimer := @TimerEvent;
+  FTimer.OnStartTimer:= @TimerStart;
+
+  with GetControlClassDefaultSize do
+    SetInitialBounds(0, 0, 150, 32);
+  FMaxValue := 100;
+  FMinValue := 0;
+  FValue := 0;
+  FLineWidth:=0;
+  FLineColor := TColor($009E5A00);
+  FLineBkgColor := TColor($00808080);
+end;
+
+
+end.
+
+

+ 129 - 124
bgracontrols.lpk

@@ -15,8 +15,8 @@
           <SyntaxMode Value="Delphi"/>
           <CStyleOperator Value="False"/>
           <AllowLabel Value="False"/>
-          <CPPInline Value="False"/>
           <UseAnsiStrings Value="False"/>
+          <CPPInline Value="False"/>
         </SyntaxOptions>
       </Parsing>
       <CodeGeneration>
@@ -34,7 +34,7 @@
     <Description Value="BGRA Controls is a set of graphical UI elements that you can use with Lazarus LCL applications."/>
     <License Value="Modified LGPL"/>
     <Version Major="9"/>
-    <Files Count="69">
+    <Files Count="70">
       <Item1>
         <Filename Value="atshapelinebgra.pas"/>
         <HasRegisterProc Value="True"/>
@@ -80,297 +80,302 @@
         <UnitName Value="BCEffect"/>
       </Item9>
       <Item10>
-        <Filename Value="bcfilters.pas"/>
-        <UnitName Value="bcfilters"/>
+        <Filename Value="BCExpandPanels.pas"/>
+        <HasRegisterProc Value="True"/>
+        <UnitName Value="BCExpandPanels"/>
       </Item10>
       <Item11>
+        <Filename Value="bcfilters.pas"/>
+        <UnitName Value="bcfilters"/>
+      </Item11>
+      <Item12>
         <Filename Value="bcfluentprogressring.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCFluentProgressRing"/>
-      </Item11>
-      <Item12>
+      </Item12>
+      <Item13>
+        <Filename Value="bcfluentslider.pas"/>
+        <HasRegisterProc Value="True"/>
+        <UnitName Value="BCFluentSlider"/>
+      </Item13>
+      <Item14>
         <Filename Value="bcgamegrid.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCGameGrid"/>
-      </Item12>
-      <Item13>
+      </Item14>
+      <Item15>
         <Filename Value="bcgradientbutton.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCGradientButton"/>
-      </Item13>
-      <Item14>
+      </Item15>
+      <Item16>
         <Filename Value="bcimagebutton.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCImageButton"/>
-      </Item14>
-      <Item15>
+      </Item16>
+      <Item17>
         <Filename Value="bckeyboard.pas"/>
         <AddToUsesPkgSection Value="False"/>
         <UnitName Value="BCKeyboard"/>
-      </Item15>
-      <Item16>
+      </Item17>
+      <Item18>
         <Filename Value="bclabel.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCLabel"/>
-      </Item16>
-      <Item17>
+      </Item18>
+      <Item19>
         <Filename Value="bclistbox.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCListBox"/>
-      </Item17>
-      <Item18>
+      </Item19>
+      <Item20>
         <Filename Value="bclistboxex.pas"/>
         <UnitName Value="BCListBoxEx"/>
-      </Item18>
-      <Item19>
+      </Item20>
+      <Item21>
         <Filename Value="bcmaterialdesignbutton.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCMaterialDesignButton"/>
-      </Item19>
-      <Item20>
+      </Item21>
+      <Item22>
         <Filename Value="bcmaterialedit.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCMaterialEdit"/>
-      </Item20>
-      <Item21>
+      </Item22>
+      <Item23>
         <Filename Value="bcmaterialfloatspinedit.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCMaterialFloatSpinEdit"/>
-      </Item21>
-      <Item22>
+      </Item23>
+      <Item24>
         <Filename Value="bcmaterialprogressbarmarquee.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCMaterialProgressBarMarquee"/>
-      </Item22>
-      <Item23>
+      </Item24>
+      <Item25>
         <Filename Value="bcmaterialspinedit.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCMaterialSpinEdit"/>
-      </Item23>
-      <Item24>
+      </Item25>
+      <Item26>
         <Filename Value="bcmdbutton.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCMDButton"/>
-      </Item24>
-      <Item25>
+      </Item26>
+      <Item27>
         <Filename Value="bcmdbuttonfocus.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCMDButtonFocus"/>
-      </Item25>
-      <Item26>
+      </Item27>
+      <Item28>
         <Filename Value="bcnumerickeyboard.pas"/>
         <AddToUsesPkgSection Value="False"/>
         <UnitName Value="BCNumericKeyboard"/>
-      </Item26>
-      <Item27>
+      </Item28>
+      <Item29>
         <Filename Value="bcpanel.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCPanel"/>
-      </Item27>
-      <Item28>
+      </Item29>
+      <Item30>
         <Filename Value="bcradialprogressbar.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCRadialProgressBar"/>
-      </Item28>
-      <Item29>
+      </Item30>
+      <Item31>
         <Filename Value="bcroundedimage.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCRoundedImage"/>
-      </Item29>
-      <Item30>
+      </Item31>
+      <Item32>
         <Filename Value="bcrtti.pas"/>
         <UnitName Value="BCRTTI"/>
-      </Item30>
-      <Item31>
+      </Item32>
+      <Item33>
         <Filename Value="bcsamples.pas"/>
         <UnitName Value="BCSamples"/>
-      </Item31>
-      <Item32>
+      </Item33>
+      <Item34>
         <Filename Value="bcstylesform.pas"/>
         <UnitName Value="BCStylesForm"/>
-      </Item32>
-      <Item33>
+      </Item34>
+      <Item35>
         <Filename Value="bcsvgbutton.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCSVGButton"/>
-      </Item33>
-      <Item34>
+      </Item35>
+      <Item36>
         <Filename Value="bcsvgviewer.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCSVGViewer"/>
-      </Item34>
-      <Item35>
+      </Item36>
+      <Item37>
         <Filename Value="bcthememanager.pas"/>
         <AddToUsesPkgSection Value="False"/>
         <UnitName Value="BCThemeManager"/>
-      </Item35>
-      <Item36>
+      </Item37>
+      <Item38>
         <Filename Value="bctoolbar.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCToolBar"/>
-      </Item36>
-      <Item37>
+      </Item38>
+      <Item39>
         <Filename Value="bctools.pas"/>
         <AddToUsesPkgSection Value="False"/>
         <UnitName Value="BCTools"/>
-      </Item37>
-      <Item38>
+      </Item39>
+      <Item40>
         <Filename Value="bctrackbarupdown.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BCTrackbarUpdown"/>
-      </Item38>
-      <Item39>
+      </Item40>
+      <Item41>
         <Filename Value="bctypes.pas"/>
         <AddToUsesPkgSection Value="False"/>
         <UnitName Value="BCTypes"/>
-      </Item39>
-      <Item40>
+      </Item41>
+      <Item42>
         <Filename Value="bgracolortheme.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRAColorTheme"/>
-      </Item40>
-      <Item41>
+      </Item42>
+      <Item43>
         <Filename Value="bgracontrolsinfo.pas"/>
         <UnitName Value="bgracontrolsinfo"/>
-      </Item41>
-      <Item42>
+      </Item43>
+      <Item44>
         <Filename Value="bgracustomdrawn.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRACustomDrawn"/>
-      </Item42>
-      <Item43>
+      </Item44>
+      <Item45>
         <Filename Value="bgradrawerflashprogressbar.pas"/>
         <UnitName Value="BGRADrawerFlashProgressBar"/>
-      </Item43>
-      <Item44>
+      </Item45>
+      <Item46>
         <Filename Value="bgraflashprogressbar.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRAFlashProgressBar"/>
-      </Item44>
-      <Item45>
+      </Item46>
+      <Item47>
         <Filename Value="bgragraphiccontrol.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRAGraphicControl"/>
-      </Item45>
-      <Item46>
+      </Item47>
+      <Item48>
         <Filename Value="bgraimagelist.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRAImageList"/>
-      </Item46>
-      <Item47>
+      </Item48>
+      <Item49>
         <Filename Value="bgraimagemanipulation.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRAImageManipulation"/>
-      </Item47>
-      <Item48>
+      </Item49>
+      <Item50>
         <Filename Value="bgraimagetheme.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRAImageTheme"/>
-      </Item48>
-      <Item49>
+      </Item50>
+      <Item51>
         <Filename Value="bgraknob.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRAKnob"/>
-      </Item49>
-      <Item50>
+      </Item51>
+      <Item52>
         <Filename Value="bgraresizespeedbutton.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRAResizeSpeedButton"/>
-      </Item50>
-      <Item51>
+      </Item52>
+      <Item53>
         <Filename Value="bgrashape.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRAShape"/>
-      </Item51>
-      <Item52>
+      </Item53>
+      <Item54>
         <Filename Value="bgraspeedbutton.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRASpeedButton"/>
-      </Item52>
-      <Item53>
+      </Item54>
+      <Item55>
         <Filename Value="bgraspriteanimation.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRASpriteAnimation"/>
-      </Item53>
-      <Item54>
+      </Item55>
+      <Item56>
         <Filename Value="bgrasvgimagelist.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRASVGImageList"/>
-      </Item54>
-      <Item55>
+      </Item56>
+      <Item57>
         <Filename Value="bgrasvgtheme.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRASVGTheme"/>
-      </Item55>
-      <Item56>
+      </Item57>
+      <Item58>
         <Filename Value="bgratheme.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRATheme"/>
-      </Item56>
-      <Item57>
+      </Item58>
+      <Item59>
         <Filename Value="bgrathemebutton.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRAThemeButton"/>
-      </Item57>
-      <Item58>
+      </Item59>
+      <Item60>
         <Filename Value="bgrathemecheckbox.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRAThemeCheckBox"/>
-      </Item58>
-      <Item59>
+      </Item60>
+      <Item61>
         <Filename Value="bgrathemeradiobutton.pas"/>
         <HasRegisterProc Value="True"/>
         <AddToUsesPkgSection Value="False"/>
         <UnitName Value="BGRAThemeRadioButton"/>
-      </Item59>
-      <Item60>
+      </Item61>
+      <Item62>
         <Filename Value="bgravirtualscreen.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="BGRAVirtualScreen"/>
-      </Item60>
-      <Item61>
+      </Item62>
+      <Item63>
         <Filename Value="colorspeedbutton.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="ColorSpeedButton"/>
-      </Item61>
-      <Item62>
+      </Item63>
+      <Item64>
         <Filename Value="dtanalogclock.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="DTAnalogClock"/>
-      </Item62>
-      <Item63>
+      </Item64>
+      <Item65>
         <Filename Value="dtanalogcommon.pas"/>
         <UnitName Value="DTAnalogCommon"/>
-      </Item63>
-      <Item64>
+      </Item65>
+      <Item66>
         <Filename Value="dtanaloggauge.pas"/>
         <HasRegisterProc Value="True"/>
         <AddToUsesPkgSection Value="False"/>
         <UnitName Value="DTAnalogGauge"/>
-      </Item64>
-      <Item65>
+      </Item66>
+      <Item67>
         <Filename Value="dtthemedclock.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="dtthemedclock"/>
-      </Item65>
-      <Item66>
+      </Item67>
+      <Item68>
         <Filename Value="dtthemedgauge.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="dtthemedgauge"/>
-      </Item66>
-      <Item67>
+      </Item68>
+      <Item69>
         <Filename Value="materialcolors.pas"/>
         <UnitName Value="MaterialColors"/>
-      </Item67>
-      <Item68>
+      </Item69>
+      <Item70>
         <Filename Value="bgrasvgimagelistform/bgrasvgimagelistform.pas"/>
         <UnitName Value="bgrasvgimagelistform"/>
-      </Item68>
-      <Item69>
-        <Filename Value="BCExpandPanels.pas"/>
-        <HasRegisterProc Value="True"/>
-        <UnitName Value="BCExpandPanels"/>
-      </Item69>
+      </Item70>
     </Files>
     <CompatibilityMode Value="True"/>
     <LazDoc Paths="fpdoc"/>

+ 17 - 15
bgracontrols.pas

@@ -9,20 +9,21 @@ interface
 
 uses
   atshapelinebgra, BCButton, BCButtonFocus, BCCheckComboBox, BCComboBox, 
-  BCEffect, bcfilters, BCFluentProgressRing, BCGameGrid, BCGradientButton, 
-  BCImageButton, BCLabel, BCListBox, BCListBoxEx, BCMaterialDesignButton, 
-  BCMaterialEdit, BCMaterialFloatSpinEdit, BCMaterialProgressBarMarquee, 
-  BCMaterialSpinEdit, BCMDButton, BCMDButtonFocus, BCPanel, 
-  BCRadialProgressBar, BCRoundedImage, BCRTTI, BCSamples, BCStylesForm, 
-  BCSVGButton, BCSVGViewer, BCToolBar, BCTrackbarUpdown, BGRAColorTheme, 
-  bgracontrolsinfo, BGRACustomDrawn, BGRADrawerFlashProgressBar, 
-  BGRAFlashProgressBar, BGRAGraphicControl, BGRAImageList, 
-  BGRAImageManipulation, BGRAImageTheme, BGRAKnob, BGRAResizeSpeedButton, 
-  BGRAShape, BGRASpeedButton, BGRASpriteAnimation, BGRASVGImageList, 
-  BGRASVGTheme, BGRATheme, BGRAThemeButton, BGRAThemeCheckBox, 
-  BGRAThemeRadioButton, BGRAVirtualScreen, ColorSpeedButton, DTAnalogClock, 
-  DTAnalogCommon, DTAnalogGauge, dtthemedclock, dtthemedgauge, MaterialColors, 
-  bgrasvgimagelistform, BCExpandPanels, LazarusPackageIntf;
+  BCEffect, BCExpandPanels, bcfilters, BCFluentProgressRing, BCFluentSlider, 
+  BCGameGrid, BCGradientButton, BCImageButton, BCLabel, BCListBox, 
+  BCListBoxEx, BCMaterialDesignButton, BCMaterialEdit, 
+  BCMaterialFloatSpinEdit, BCMaterialProgressBarMarquee, BCMaterialSpinEdit, 
+  BCMDButton, BCMDButtonFocus, BCPanel, BCRadialProgressBar, BCRoundedImage, 
+  BCRTTI, BCSamples, BCStylesForm, BCSVGButton, BCSVGViewer, BCToolBar, 
+  BCTrackbarUpdown, BGRAColorTheme, bgracontrolsinfo, BGRACustomDrawn, 
+  BGRADrawerFlashProgressBar, BGRAFlashProgressBar, BGRAGraphicControl, 
+  BGRAImageList, BGRAImageManipulation, BGRAImageTheme, BGRAKnob, 
+  BGRAResizeSpeedButton, BGRAShape, BGRASpeedButton, BGRASpriteAnimation, 
+  BGRASVGImageList, BGRASVGTheme, BGRATheme, BGRAThemeButton, 
+  BGRAThemeCheckBox, BGRAThemeRadioButton, BGRAVirtualScreen, 
+  ColorSpeedButton, DTAnalogClock, DTAnalogCommon, DTAnalogGauge, 
+  dtthemedclock, dtthemedgauge, MaterialColors, bgrasvgimagelistform, 
+  LazarusPackageIntf;
 
 implementation
 
@@ -33,7 +34,9 @@ begin
   RegisterUnit('BCButtonFocus', @BCButtonFocus.Register);
   RegisterUnit('BCCheckComboBox', @BCCheckComboBox.Register);
   RegisterUnit('BCComboBox', @BCComboBox.Register);
+  RegisterUnit('BCExpandPanels', @BCExpandPanels.Register);
   RegisterUnit('BCFluentProgressRing', @BCFluentProgressRing.Register);
+  RegisterUnit('BCFluentSlider', @BCFluentSlider.Register);
   RegisterUnit('BCGameGrid', @BCGameGrid.Register);
   RegisterUnit('BCGradientButton', @BCGradientButton.Register);
   RegisterUnit('BCImageButton', @BCImageButton.Register);
@@ -78,7 +81,6 @@ begin
   RegisterUnit('DTAnalogGauge', @DTAnalogGauge.Register);
   RegisterUnit('dtthemedclock', @dtthemedclock.Register);
   RegisterUnit('dtthemedgauge', @dtthemedgauge.Register);
-  RegisterUnit('BCExpandPanels', @BCExpandPanels.Register);
 end;
 
 initialization

+ 89 - 0
test/test_bcfuentslider/project1.lpi

@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <PathDelim Value="\"/>
+    <General>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="project1"/>
+      <Scaled Value="True"/>
+      <ResourceType Value="res"/>
+      <UseXPManifest Value="True"/>
+      <XPManifest>
+        <DpiAware Value="True"/>
+      </XPManifest>
+      <Icon Value="0"/>
+    </General>
+    <BuildModes>
+      <Item Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <RequiredPackages>
+      <Item>
+        <PackageName Value="bgracontrols"/>
+      </Item>
+      <Item>
+        <PackageName Value="LCL"/>
+      </Item>
+    </RequiredPackages>
+    <Units>
+      <Unit>
+        <Filename Value="project1.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit>
+      <Unit>
+        <Filename Value="unit1.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="Form1"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+        <UnitName Value="Unit1"/>
+      </Unit>
+      <Unit>
+        <Filename Value="bcfluentslider.pas"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="BCFluentSlider"/>
+      </Unit>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="project1"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+    <Linking>
+      <Debugging>
+        <DebugInfoType Value="dsDwarf2Set"/>
+      </Debugging>
+      <Options>
+        <Win32>
+          <GraphicApplication Value="True"/>
+        </Win32>
+      </Options>
+    </Linking>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions>
+      <Item>
+        <Name Value="EAbort"/>
+      </Item>
+      <Item>
+        <Name Value="ECodetoolError"/>
+      </Item>
+      <Item>
+        <Name Value="EFOpenError"/>
+      </Item>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 25 - 0
test/test_bcfuentslider/project1.lpr

@@ -0,0 +1,25 @@
+program project1;
+
+{$mode objfpc}{$H+}
+
+uses
+  {$IFDEF UNIX}
+  cthreads,
+  {$ENDIF}
+  {$IFDEF HASAMIGA}
+  athreads,
+  {$ENDIF}
+  Interfaces, // this includes the LCL widgetset
+  Forms, Unit1, BCFluentSlider
+  { you can add units after this };
+
+{$R *.res}
+
+begin
+  RequireDerivedFormResource:=True;
+  Application.Scaled:=True;
+  Application.Initialize;
+  Application.CreateForm(TForm1, Form1);
+  Application.Run;
+end.
+

+ 40 - 0
test/test_bcfuentslider/unit1.lfm

@@ -0,0 +1,40 @@
+object Form1: TForm1
+  Left = 579
+  Height = 286
+  Top = 224
+  Width = 425
+  Caption = 'Form1'
+  ClientHeight = 286
+  ClientWidth = 425
+  DesignTimePPI = 120
+  OnCreate = FormCreate
+  LCLVersion = '2.2.6.0'
+  object Label1: TLabel
+    Left = 120
+    Height = 37
+    Top = 96
+    Width = 93
+    Caption = 'Value: 0'
+    Font.Height = -27
+    ParentColor = False
+    ParentFont = False
+  end
+  object CheckBox1: TCheckBox
+    Left = 344
+    Height = 24
+    Top = 16
+    Width = 56
+    Caption = 'Ticks'
+    OnChange = CheckBox1Change
+    TabOrder = 0
+  end
+  object CheckBox2: TCheckBox
+    Left = 344
+    Height = 24
+    Top = 48
+    Width = 74
+    Caption = 'Vertical'
+    OnChange = CheckBox2Change
+    TabOrder = 1
+  end
+end

+ 70 - 0
test/test_bcfuentslider/unit1.pas

@@ -0,0 +1,70 @@
+unit Unit1;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  BCFluentSlider;
+
+type
+
+  { TForm1 }
+
+  TForm1 = class(TForm)
+    CheckBox1: TCheckBox;
+    CheckBox2: TCheckBox;
+    Label1: TLabel;
+    procedure CheckBox1Change(Sender: TObject);
+    procedure CheckBox2Change(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+  private
+    procedure SliderChangeValue(Sender: TObject);
+
+  public
+    Slider: TBCFluentSlider;
+  end;
+
+var
+  Form1: TForm1;
+
+implementation
+
+{$R *.lfm}
+
+{ TForm1 }
+
+procedure TForm1.FormCreate(Sender: TObject);
+begin
+  Slider:= TBCFluentSlider.Create(self);
+  with Slider do
+  begin
+    Top:= 10;
+    Left:= 10;
+    Width:= 240;
+    OnChangeValue:= @SliderChangeValue;
+    Parent:= self;
+  end;
+end;
+
+procedure TForm1.CheckBox1Change(Sender: TObject);
+begin
+  Slider.ShowTicks:= CheckBox1.Checked;
+end;
+
+procedure TForm1.CheckBox2Change(Sender: TObject);
+begin
+  if CheckBox2.Checked then
+    Slider.Orientation:= pbVertical
+  else
+    Slider.Orientation:= pbHorizontal;
+end;
+
+procedure TForm1.SliderChangeValue(Sender: TObject);
+begin
+  Label1.Caption:= 'Value: '+IntToStr(Slider.Value);
+end;
+
+end.
+