Recent

Author Topic: [SOLVED] Custom flat trackbar component with BGRA  (Read 1175 times)

Pe3s

  • Hero Member
  • *****
  • Posts: 647
[SOLVED] Custom flat trackbar component with BGRA
« on: August 05, 2025, 05:35:06 pm »
Hello, I wrote a slider component using the BGRA library, but I encountered a problem: my component does not inherit the form color. How can I fix this?

Code: Pascal  [Select][+][-]
  1. unit FlatSeekBarPro;
  2.  
  3. {$mode ObjFPC}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Controls, Graphics, LMessages, Types, LCLType,
  9.   BGRABitmap, BGRABitmapTypes;
  10.  
  11. type
  12.   TFlatSeekBarPro = class(TCustomControl)
  13.   private
  14.     FValue: integer;
  15.     FMin: integer;
  16.     FMax: integer;
  17.     FDragging: boolean;
  18.     FHovering: boolean;
  19.     FMouseDownOnKnob: boolean;
  20.  
  21.     FTrackColor: TColor;
  22.     FTrackBorderWidth: integer;
  23.  
  24.     FKnobColor: TColor;
  25.     FKnobHoverColor: TColor;
  26.     FKnobBorderColor: TColor;
  27.     FKnobBorderWidth: integer;
  28.     FKnobRadius: integer;
  29.  
  30.     FLeftMargin: integer;
  31.     FRightMargin: integer;
  32.  
  33.     FOnChange: TNotifyEvent;
  34.     FOnMouseDown: TMouseEvent;
  35.     FOnMouseMove: TMouseMoveEvent;
  36.     FOnMouseUp: TMouseEvent;
  37.  
  38.     procedure SetValue(AValue: integer);
  39.     function ValueToPosition(Value: integer): integer;
  40.     function PositionToValue(X: integer): integer;
  41.  
  42.     procedure SetTrackColor(AColor: TColor);
  43.     procedure SetKnobColor(AColor: TColor);
  44.     procedure SetKnobHoverColor(AColor: TColor);
  45.     procedure SetKnobBorderColor(AColor: TColor);
  46.     procedure SetKnobRadius(ARadius: integer);
  47.     procedure SetTrackBorderWidth(AValue: integer);
  48.     procedure SetKnobBorderWidth(AValue: integer);
  49.     procedure SetLeftMargin(AValue: integer);
  50.     procedure SetRightMargin(AValue: integer);
  51.  
  52.   protected
  53.     procedure Paint; override;
  54.     procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
  55.       X, Y: integer); override;
  56.     procedure MouseMove(Shift: TShiftState; X, Y: integer); override;
  57.     procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
  58.     procedure MouseEnter; override;
  59.     procedure MouseLeave; override;
  60.   public
  61.     constructor Create(AOwner: TComponent); override;
  62.  
  63.   published
  64.     property Min: integer read FMin write FMin default 0;
  65.     property Max: integer read FMax write FMax default 100;
  66.     property Value: integer read FValue write SetValue default 0;
  67.  
  68.     property TrackColor: TColor read FTrackColor write SetTrackColor default clGray;
  69.     property TrackBorderWidth: integer read FTrackBorderWidth
  70.       write SetTrackBorderWidth default 2;
  71.  
  72.     property KnobColor: TColor read FKnobColor write SetKnobColor default clWhite;
  73.     property KnobHoverColor: TColor
  74.       read FKnobHoverColor write SetKnobHoverColor default clSilver;
  75.     property KnobBorderColor: TColor read FKnobBorderColor
  76.       write SetKnobBorderColor default clBlack;
  77.     property KnobBorderWidth: integer read FKnobBorderWidth
  78.       write SetKnobBorderWidth default 2;
  79.     property KnobRadius: integer read FKnobRadius write SetKnobRadius default 7;
  80.  
  81.     property LeftMargin: integer read FLeftMargin write SetLeftMargin default 10;
  82.     property RightMargin: integer read FRightMargin write SetRightMargin default 10;
  83.  
  84.     property Align;
  85.     property Anchors;
  86.     property Color;
  87.     property ParentColor;
  88.     property Visible;
  89.     property Enabled;
  90.  
  91.     property OnChange: TNotifyEvent read FOnChange write FOnChange;
  92.     property OnMouseDown: TMouseEvent read FOnMouseDown write FOnMouseDown;
  93.     property OnMouseMove: TMouseMoveEvent read FOnMouseMove write FOnMouseMove;
  94.     property OnMouseUp: TMouseEvent read FOnMouseUp write FOnMouseUp;
  95.   end;
  96.  
  97. procedure Register;
  98.  
  99. implementation
  100.  
  101. procedure Register;
  102. begin
  103.   RegisterComponents('PSDesign', [TFlatSeekBarPro]);
  104. end;
  105.  
  106. { TFlatSeekBarPro }
  107.  
  108. constructor TFlatSeekBarPro.Create(AOwner: TComponent);
  109. begin
  110.   inherited Create(AOwner);
  111.   Width := 150;
  112.   Height := 30;
  113.   FMin := 0;
  114.   FMax := 100;
  115.   FValue := 0;
  116.   FDragging := False;
  117.   FHovering := False;
  118.   FMouseDownOnKnob := False;
  119.  
  120.   FTrackColor := clGray;
  121.   FTrackBorderWidth := 2;
  122.  
  123.   FKnobColor := clWhite;
  124.   FKnobHoverColor := clSilver;
  125.   FKnobBorderColor := clBlack;
  126.   FKnobBorderWidth := 2;
  127.   FKnobRadius := 7;
  128.  
  129.   FLeftMargin := 10;
  130.   FRightMargin := 10;
  131.  
  132.   Color := clDefault;
  133.   DoubleBuffered := True;
  134. end;
  135.  
  136. procedure TFlatSeekBarPro.SetValue(AValue: integer);
  137. begin
  138.   if AValue < FMin then AValue := FMin;
  139.   if AValue > FMax then AValue := FMax;
  140.   if FValue <> AValue then
  141.   begin
  142.     FValue := AValue;
  143.     Invalidate;
  144.     if Assigned(FOnChange) then
  145.       FOnChange(Self);
  146.   end;
  147. end;
  148.  
  149. function TFlatSeekBarPro.ValueToPosition(Value: integer): integer;
  150. begin
  151.   if FMax = FMin then Exit(FLeftMargin);
  152.   Result := FLeftMargin + Round((ClientWidth - FLeftMargin - FRightMargin) *
  153.     (Value - FMin) / (FMax - FMin));
  154. end;
  155.  
  156. function TFlatSeekBarPro.PositionToValue(X: integer): integer;
  157. begin
  158.   Result := FMin + Round((X - FLeftMargin) * (FMax - FMin) /
  159.     (ClientWidth - FLeftMargin - FRightMargin));
  160.   if Result < FMin then Result := FMin;
  161.   if Result > FMax then Result := FMax;
  162. end;
  163.  
  164. procedure TFlatSeekBarPro.Paint;
  165. var
  166.   bmp: TBGRABitmap;
  167.   cx, cy, r: integer;
  168.   borderColor, bgColor: TBGRAPixel;
  169.   rawColor: TColor;
  170. begin
  171.   // Pobierz rzeczywisty kolor tła
  172.   if Color = clDefault then
  173.   begin
  174.     if ParentColor and Assigned(Parent) then
  175.       rawColor := Parent.Color
  176.     else
  177.       rawColor := clBtnFace; // fallback
  178.   end
  179.   else
  180.     rawColor := Color;
  181.  
  182.   bgColor := ColorToBGRA(rawColor);
  183.  
  184.   bmp := TBGRABitmap.Create(ClientWidth, ClientHeight, bgColor);
  185.   try
  186.     cx := ValueToPosition(FValue);
  187.     cy := Height div 2;
  188.     r := FKnobRadius;
  189.  
  190.     // Track
  191.     bmp.CanvasBGRA.Pen.Width := FTrackBorderWidth;
  192.     bmp.CanvasBGRA.Pen.Style := psSolid;
  193.     bmp.CanvasBGRA.Pen.Color := ColorToBGRA(FTrackColor);
  194.     bmp.CanvasBGRA.Line(FLeftMargin, cy, ClientWidth - FRightMargin, cy);
  195.  
  196.     // Knob color
  197.     if FMouseDownOnKnob or FHovering then
  198.       knobColor := ColorToBGRA(FKnobHoverColor)
  199.     else
  200.       knobColor := ColorToBGRA(FKnobColor);
  201.  
  202.     borderColor := ColorToBGRA(FKnobBorderColor);
  203.  
  204.     // Knob
  205.     bmp.FillEllipseAntialias(cx, cy, r, r, knobColor);
  206.     if FKnobBorderWidth > 0 then
  207.       bmp.EllipseAntialias(cx, cy, r, r, borderColor, FKnobBorderWidth);
  208.  
  209.     bmp.Draw(Canvas, 0, 0, True);
  210.   finally
  211.     bmp.Free;
  212.   end;
  213. end;
  214.  
  215. procedure TFlatSeekBarPro.MouseDown(Button: TMouseButton; Shift: TShiftState;
  216.   X, Y: integer);
  217. var
  218.   cx, cy, r: integer;
  219. begin
  220.   inherited MouseDown(Button, Shift, X, Y);
  221.   if Assigned(FOnMouseDown) then
  222.     FOnMouseDown(Self, Button, Shift, X, Y);
  223.  
  224.   if Button = mbLeft then
  225.   begin
  226.     FDragging := True;
  227.     SetValue(PositionToValue(X));
  228.  
  229.     cx := ValueToPosition(FValue);
  230.     cy := Height div 2;
  231.     r := FKnobRadius;
  232.     FMouseDownOnKnob := PtInRect(Rect(cx - r, cy - r, cx + r, cy + r), Point(X, Y));
  233.     Invalidate;
  234.   end;
  235. end;
  236.  
  237. procedure TFlatSeekBarPro.MouseMove(Shift: TShiftState; X, Y: integer);
  238. begin
  239.   inherited MouseMove(Shift, X, Y);
  240.   if Assigned(FOnMouseMove) then
  241.     FOnMouseMove(Self, Shift, X, Y);
  242.  
  243.   if FDragging then
  244.     SetValue(PositionToValue(X));
  245. end;
  246.  
  247. procedure TFlatSeekBarPro.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
  248. begin
  249.   inherited MouseUp(Button, Shift, X, Y);
  250.   if Assigned(FOnMouseUp) then
  251.     FOnMouseUp(Self, Button, Shift, X, Y);
  252.  
  253.   FDragging := False;
  254.   FMouseDownOnKnob := False;
  255.   Invalidate;
  256. end;
  257.  
  258. procedure TFlatSeekBarPro.MouseEnter;
  259. begin
  260.   inherited MouseEnter;
  261.   FHovering := True;
  262.   Invalidate;
  263. end;
  264.  
  265. procedure TFlatSeekBarPro.MouseLeave;
  266. begin
  267.   inherited MouseLeave;
  268.   FHovering := False;
  269.   Invalidate;
  270. end;
  271.  
  272. procedure TFlatSeekBarPro.SetTrackColor(AColor: TColor);
  273. begin
  274.   if FTrackColor <> AColor then
  275.   begin
  276.     FTrackColor := AColor;
  277.     Invalidate;
  278.   end;
  279. end;
  280.  
  281. procedure TFlatSeekBarPro.SetTrackBorderWidth(AValue: integer);
  282. begin
  283.   if FTrackBorderWidth <> AValue then
  284.   begin
  285.     FTrackBorderWidth := AValue;
  286.     Invalidate;
  287.   end;
  288. end;
  289.  
  290. procedure TFlatSeekBarPro.SetKnobColor(AColor: TColor);
  291. begin
  292.   if FKnobColor <> AColor then
  293.   begin
  294.     FKnobColor := AColor;
  295.     Invalidate;
  296.   end;
  297. end;
  298.  
  299. procedure TFlatSeekBarPro.SetKnobHoverColor(AColor: TColor);
  300. begin
  301.   if FKnobHoverColor <> AColor then
  302.   begin
  303.     FKnobHoverColor := AColor;
  304.     Invalidate;
  305.   end;
  306. end;
  307.  
  308. procedure TFlatSeekBarPro.SetKnobBorderColor(AColor: TColor);
  309. begin
  310.   if FKnobBorderColor <> AColor then
  311.   begin
  312.     FKnobBorderColor := AColor;
  313.     Invalidate;
  314.   end;
  315. end;
  316.  
  317. procedure TFlatSeekBarPro.SetKnobBorderWidth(AValue: integer);
  318. begin
  319.   if FKnobBorderWidth <> AValue then
  320.   begin
  321.     FKnobBorderWidth := AValue;
  322.     Invalidate;
  323.   end;
  324. end;
  325.  
  326. procedure TFlatSeekBarPro.SetKnobRadius(ARadius: integer);
  327. begin
  328.   if (ARadius > 1) and (FKnobRadius <> ARadius) then
  329.   begin
  330.     FKnobRadius := ARadius;
  331.     Invalidate;
  332.   end;
  333. end;
  334.  
  335. procedure TFlatSeekBarPro.SetLeftMargin(AValue: integer);
  336. begin
  337.   if FLeftMargin <> AValue then
  338.   begin
  339.     FLeftMargin := AValue;
  340.     Invalidate;
  341.   end;
  342. end;
  343.  
  344. procedure TFlatSeekBarPro.SetRightMargin(AValue: integer);
  345. begin
  346.   if FRightMargin <> AValue then
  347.   begin
  348.     FRightMargin := AValue;
  349.     Invalidate;
  350.   end;
  351. end;
  352.  
  353. end.
  354.  
  355.  
« Last Edit: August 07, 2025, 09:51:29 pm by Pe3s »

Pe3s

  • Hero Member
  • *****
  • Posts: 647
Re: Custom flat trackbar component with BGRA
« Reply #1 on: August 05, 2025, 07:59:15 pm »
Does it mean that BGRA does not support clDefault color ?

Fred vS

  • Hero Member
  • *****
  • Posts: 3945
    • StrumPract is the musicians best friend
Re: Custom flat trackbar component with BGRA
« Reply #2 on: August 05, 2025, 08:25:23 pm »
Does it mean that BGRA does not support clDefault color ?

Not sure to understand what you mean by "BGRA doesn't support the clDefault color."

clDefault is used in BGRABitmap code, for example:

Code: Pascal  [Select][+][-]
  1. property TransparentColor: TColor read FTransparentColor
  2.              write SetTransparentColor default clDefault;
  3.  
 
Code: Pascal  [Select][+][-]
  1. procedure TCustomBGLVirtualScreen.DoOnPaint;
  2. ...
  3.   if Color = clDefault then
  4.     BGLViewPort(ClientWidth,ClientHeight,ColorToBGRA(clWindow))
  5. ...
  6.  
Code: Pascal  [Select][+][-]
  1.  if AValue = clDefault
  2.   then FTransparentMode := tmAuto

etc...

And I did not note problems using it.
But surely I miss something then explain please.
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

Pe3s

  • Hero Member
  • *****
  • Posts: 647
Re: Custom flat trackbar component with BGRA
« Reply #3 on: August 05, 2025, 09:50:53 pm »
Hello @Fred vS, the component code I pasted draws a bar. I don't know what I wrote wrong, but the background color is black. I want to fix it.

Fred vS

  • Hero Member
  • *****
  • Posts: 3945
    • StrumPract is the musicians best friend
Re: Custom flat trackbar component with BGRA
« Reply #4 on: August 05, 2025, 10:10:55 pm »
Hello @Fred vS, the component code I pasted draws a bar. I don't know what I wrote wrong, but the background color is black. I want to fix it.

Could you try this ? :
Code: Pascal  [Select][+][-]
  1.  bmp := TBGRABitmap.Create(ClientWidth, ClientHeight, BGRAPixelTransparent);

 (And we will check later the cldefault problem)

[EDIT]: Maybe try also, after create,  with:

Code: Pascal  [Select][+][-]
  1. bmp.Fill(clDefault);
« Last Edit: August 05, 2025, 10:24:16 pm by Fred vS »
I use Lazarus 2.2.0 32/64 and FPC 3.2.2 32/64 on Debian 11 64 bit, Windows 10, Windows 7 32/64, Windows XP 32,  FreeBSD 64.
Widgetset: fpGUI, MSEgui, Win32, GTK2, Qt.

https://github.com/fredvs
https://gitlab.com/fredvs
https://codeberg.org/fredvs

jamie

  • Hero Member
  • *****
  • Posts: 7767
Re: Custom flat trackbar component with BGRA
« Reply #5 on: August 06, 2025, 01:09:52 am »
I don't know if that is will fix your problem but.

Code: Pascal  [Select][+][-]
  1. If Color = clDefault then Color := GetDefaultColor(dctBrush);
  2.  

That will at least convert the clDefault over to what the default color is.

otherwise, the clDefault has no meaning and it's black.

Jamie
The only true wisdom is knowing you know nothing

Pe3s

  • Hero Member
  • *****
  • Posts: 647
Re: Custom flat trackbar component with BGRA
« Reply #6 on: August 07, 2025, 09:51:09 pm »
Thank you for your help.   :)

 

TinyPortal © 2005-2018