Author Topic: QGradientTrackPanel: A Fully customizable GradientTrackBar  (Read 1437 times)

Ed78z

  • Jr. Member
  • **
  • Posts: 77
QGradientTrackPanel: A Fully customizable GradientTrackBar
« on: August 08, 2026, 06:11:09 pm »
I'd just like to share my QGradientTrackPanel component! It's very powerful and flexible.

Feel free to use it and share your feedback!

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Spin,
  9.   ComCtrls, ExtCtrls, QGradientTrackPanel;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     ColorButton: TColorButton;
  17.     LblColor: TLabel;
  18.     LblPosition: TLabel;
  19.     LblTransparency: TLabel;
  20.     LblBrightness: TLabel;
  21.     SpinPosition: TSpinEdit;
  22.     SpinTransparency: TSpinEdit;
  23.     SpinBrightness: TSpinEdit;
  24.     TrackPosition: TTrackBar;
  25.     TrackTransparency: TTrackBar;
  26.     TrackBrightness: TTrackBar;
  27.     PreviewPaintBox: TPaintBox;
  28.     procedure FormCreate(Sender: TObject);
  29.     procedure PreviewPaintBoxPaint(Sender: TObject);
  30.   private
  31.     FGradientPanel: TQGradientTrackPanel;
  32.  
  33.     procedure OnStopSelectedHandler(Sender: TObject; {%H-}AIndex: Integer);
  34.     procedure OnStopAddedHandler(Sender: TObject; {%H-}AIndex: Integer);
  35.     procedure OnStopRemovedHandler(Sender: TObject; {%H-}AIndex: Integer);
  36.     procedure OnStopChangedHandler(Sender: TObject);
  37.  
  38.     procedure UpdateControlsFromSelectedStop;
  39.     procedure SpinPositionChange(Sender: TObject);
  40.     procedure TrackPositionChange(Sender: TObject);
  41.     procedure SpinTransparencyChange(Sender: TObject);
  42.     procedure TrackTransparencyChange(Sender: TObject);
  43.     procedure SpinBrightnessChange(Sender: TObject);
  44.     procedure TrackBrightnessChange(Sender: TObject);
  45.     procedure ColorButtonChanged(Sender: TObject);
  46.   public
  47.   end;
  48.  
  49. var
  50.   Form1: TForm1;
  51.  
  52. implementation
  53.  
  54. {$R *.lfm}
  55.  
  56. procedure TForm1.FormCreate(Sender: TObject);
  57. var
  58.   InitialStops: TStopArray = nil;
  59.  
  60. begin
  61.   FGradientPanel := TQGradientTrackPanel.Create(Self);
  62.   FGradientPanel.Parent := Self;
  63.   FGradientPanel.Left := 10;
  64.   FGradientPanel.Top := 20;
  65.   FGradientPanel.Width := Form1.Width - 20;
  66.   FGradientPanel.Height := 44;
  67.   FGradientPanel.BorderWidth:=1;// 0 = No Border
  68.   FGradientPanel.Anchors := [akTop, akLeft, akRight];
  69.  
  70.   FGradientPanel.OnStopSelected := @OnStopSelectedHandler;
  71.   FGradientPanel.OnStopAdded := @OnStopAddedHandler;
  72.   FGradientPanel.OnStopRemoved := @OnStopRemovedHandler;
  73.   FGradientPanel.OnStopChanged := @OnStopChangedHandler;
  74.  
  75.   SetLength(InitialStops, 7);
  76.  
  77.   // Red
  78.   InitialStops[0].Position := 0;
  79.   InitialStops[0].Color := clRed;
  80.   InitialStops[0].Transparency := 0;
  81.   InitialStops[0].Brightness := 0;
  82.  
  83.   // Orange
  84.   InitialStops[1].Position := 16;
  85.   InitialStops[1].Color := $0080FF;
  86.   InitialStops[1].Transparency := 0;
  87.   InitialStops[1].Brightness := 0;
  88.  
  89.   // Yellow
  90.   InitialStops[2].Position := 33;
  91.   InitialStops[2].Color := clYellow;
  92.   InitialStops[2].Transparency := 0;
  93.   InitialStops[2].Brightness := 0;
  94.  
  95.   // Green
  96.   InitialStops[3].Position := 50;
  97.   InitialStops[3].Color := clLime;
  98.   InitialStops[3].Transparency := 0;
  99.   InitialStops[3].Brightness := 0;
  100.  
  101.   // Blue
  102.   InitialStops[4].Position := 66;
  103.   InitialStops[4].Color := clBlue;
  104.   InitialStops[4].Transparency := 0;
  105.   InitialStops[4].Brightness := 0;
  106.  
  107.   // Indigo
  108.   InitialStops[5].Position := 83;
  109.   InitialStops[5].Color := $82004B;
  110.   InitialStops[5].Transparency := 0;
  111.   InitialStops[5].Brightness := 0;
  112.  
  113.   // Violet
  114.   InitialStops[6].Position := 100;
  115.   InitialStops[6].Color := $EE82EE;
  116.   InitialStops[6].Transparency := 0;
  117.   InitialStops[6].Brightness := 0;
  118.  
  119.   FGradientPanel.Stops := InitialStops;
  120.   FGradientPanel.SelectedIndex := 0;
  121.  
  122.   UpdateControlsFromSelectedStop;
  123. end;
  124.  
  125. procedure TForm1.OnStopSelectedHandler(Sender: TObject; AIndex: Integer);
  126. begin
  127.   UpdateControlsFromSelectedStop;
  128. end;
  129.  
  130. procedure TForm1.OnStopAddedHandler(Sender: TObject; AIndex: Integer);
  131. begin
  132.   UpdateControlsFromSelectedStop;
  133.   PreviewPaintBox.Invalidate;
  134. end;
  135.  
  136. procedure TForm1.OnStopRemovedHandler(Sender: TObject; AIndex: Integer);
  137. begin
  138.   UpdateControlsFromSelectedStop;
  139.   PreviewPaintBox.Invalidate;
  140. end;
  141.  
  142. procedure TForm1.OnStopChangedHandler(Sender: TObject);
  143. begin
  144.   if (FGradientPanel.SelectedIndex >= 0) and Assigned(SpinPosition) then
  145.   begin
  146.     SpinPosition.OnChange := nil;
  147.     SpinPosition.Value := FGradientPanel.SelectedPosition;
  148.     SpinPosition.OnChange := @SpinPositionChange;
  149.  
  150.     TrackPosition.OnChange := nil;
  151.     TrackPosition.Position := FGradientPanel.SelectedPosition;
  152.     TrackPosition.OnChange := @TrackPositionChange;
  153.   end;
  154.   PreviewPaintBox.Invalidate;
  155. end;
  156.  
  157. procedure TForm1.PreviewPaintBoxPaint(Sender: TObject);
  158. begin
  159.   if not Assigned(FGradientPanel) or (FGradientPanel.StopsCount = 0) then Exit;
  160.   FGradientPanel.DrawGradient(PreviewPaintBox.Canvas, PreviewPaintBox.ClientRect, True);
  161. end;
  162.  
  163. procedure TForm1.UpdateControlsFromSelectedStop;
  164. begin
  165.   if (FGradientPanel.SelectedIndex >= 0) and Assigned(SpinPosition) then
  166.   begin
  167.     SpinPosition.OnChange := nil;
  168.     TrackPosition.OnChange := nil;
  169.     SpinTransparency.OnChange := nil;
  170.     TrackTransparency.OnChange := nil;
  171.     SpinBrightness.OnChange := nil;
  172.     TrackBrightness.OnChange := nil;
  173.     ColorButton.OnColorChanged := nil;
  174.  
  175.     ColorButton.ButtonColor := FGradientPanel.SelectedColor;
  176.  
  177.     SpinPosition.Value := FGradientPanel.SelectedPosition;
  178.     TrackPosition.Position := FGradientPanel.SelectedPosition;
  179.  
  180.     SpinTransparency.Value := FGradientPanel.SelectedTransparency;
  181.     TrackTransparency.Position := FGradientPanel.SelectedTransparency;
  182.  
  183.     SpinBrightness.Value := FGradientPanel.SelectedBrightness;
  184.     TrackBrightness.Position := FGradientPanel.SelectedBrightness;
  185.  
  186.     SpinPosition.OnChange := @SpinPositionChange;
  187.     TrackPosition.OnChange := @TrackPositionChange;
  188.     SpinTransparency.OnChange := @SpinTransparencyChange;
  189.     TrackTransparency.OnChange := @TrackTransparencyChange;
  190.     SpinBrightness.OnChange := @SpinBrightnessChange;
  191.     TrackBrightness.OnChange := @TrackBrightnessChange;
  192.     ColorButton.OnColorChanged := @ColorButtonChanged;
  193.   end;
  194. end;
  195.  
  196.  
  197. procedure TForm1.SpinPositionChange(Sender: TObject);
  198. begin
  199.   if FGradientPanel.SelectedIndex >= 0 then
  200.   begin
  201.     FGradientPanel.SelectedPosition := SpinPosition.Value;
  202.  
  203.     TrackPosition.OnChange := nil;
  204.     TrackPosition.Position := SpinPosition.Value;
  205.     TrackPosition.OnChange := @TrackPositionChange;
  206.   end;
  207. end;
  208.  
  209. procedure TForm1.TrackPositionChange(Sender: TObject);
  210. begin
  211.   if FGradientPanel.SelectedIndex >= 0 then
  212.   begin
  213.     FGradientPanel.SelectedPosition := TrackPosition.Position;
  214.  
  215.     SpinPosition.OnChange := nil;
  216.     SpinPosition.Value := TrackPosition.Position;
  217.     SpinPosition.OnChange := @SpinPositionChange;
  218.   end;
  219. end;
  220.  
  221.  
  222. procedure TForm1.SpinTransparencyChange(Sender: TObject);
  223. begin
  224.   if FGradientPanel.SelectedIndex >= 0 then
  225.   begin
  226.     FGradientPanel.SelectedTransparency := SpinTransparency.Value;
  227.  
  228.     TrackTransparency.OnChange := nil;
  229.     TrackTransparency.Position := SpinTransparency.Value;
  230.     TrackTransparency.OnChange := @TrackTransparencyChange;
  231.   end;
  232. end;
  233.  
  234. procedure TForm1.TrackTransparencyChange(Sender: TObject);
  235. begin
  236.   if FGradientPanel.SelectedIndex >= 0 then
  237.   begin
  238.     FGradientPanel.SelectedTransparency := TrackTransparency.Position;
  239.  
  240.     SpinTransparency.OnChange := nil;
  241.     SpinTransparency.Value := TrackTransparency.Position;
  242.     SpinTransparency.OnChange := @SpinTransparencyChange;
  243.   end;
  244. end;
  245.  
  246. procedure TForm1.SpinBrightnessChange(Sender: TObject);
  247. begin
  248.   if FGradientPanel.SelectedIndex >= 0 then
  249.   begin
  250.     FGradientPanel.SelectedBrightness := SpinBrightness.Value;
  251.  
  252.     TrackBrightness.OnChange := nil;
  253.     TrackBrightness.Position := SpinBrightness.Value;
  254.     TrackBrightness.OnChange := @TrackBrightnessChange;
  255.   end;
  256. end;
  257.  
  258. procedure TForm1.TrackBrightnessChange(Sender: TObject);
  259. begin
  260.   if FGradientPanel.SelectedIndex >= 0 then
  261.   begin
  262.     FGradientPanel.SelectedBrightness := TrackBrightness.Position;
  263.  
  264.     SpinBrightness.OnChange := nil;
  265.     SpinBrightness.Value := TrackBrightness.Position;
  266.     SpinBrightness.OnChange := @SpinBrightnessChange;
  267.   end;
  268. end;
  269.  
  270. procedure TForm1.ColorButtonChanged(Sender: TObject);
  271. begin
  272.   if FGradientPanel.SelectedIndex >= 0 then
  273.     FGradientPanel.SelectedColor := ColorButton.ButtonColor;
  274. end;
  275.  
  276. end.
  277.  

AlexTP

  • Hero Member
  • *****
  • Posts: 2740
    • UVviewsoft
Re: QGradientTrackPanel: A Fully customizable GradientTrackBar
« Reply #1 on: August 08, 2026, 06:25:24 pm »
It was not much needed component: in usual GUI it's ok to place a trackbar + the panel below, with gradients on panel.

Ed78z

  • Jr. Member
  • **
  • Posts: 77
Re: QGradientTrackPanel: A Fully customizable GradientTrackBar
« Reply #2 on: August 08, 2026, 07:22:09 pm »
It was not much needed component: in usual GUI it's ok to place a trackbar + the panel below, with gradients on panel.

Thank you AlexTP for your feedback.
I developed this component to use in my SkiaEdit component.
I am curious how to replicate this complex/flexible component (QGradientTrackPanel) with a trackbar + the panel. Could you please share your idea? it may help to simplify my SkiaEdit component.

Boleeman

  • Hero Member
  • *****
  • Posts: 1180
Re: QGradientTrackPanel: A Fully customizable GradientTrackBar
« Reply #3 on: August 10, 2026, 07:13:07 am »
Nice Gradient TrackBar Panel Ed78z

Made a few nice gradients. Easy to use.
Reminds me of some old VB6 versions.

Some suggestions:
Use radial, cosine, HSL instead of just linear interpolations
Perhaps have an angle variable.

More complex: Ambient lighting


Lastly SkiaEdit component : was not aware of it for Lazarus (thought it was exclusively for Delphi)

Ed78z

  • Jr. Member
  • **
  • Posts: 77
Re: QGradientTrackPanel: A Fully customizable GradientTrackBar
« Reply #4 on: August 17, 2026, 12:04:50 am »
Boleeman,
I like to get your feedback about my QGradientPro demo program (still under progress...)

Download the compiled file here:
https://drive.google.com/drive/u/0/folders/11Q1DPsEUJ8wMdlwjZt_o3qAHpZS4EFjj

Boleeman

  • Hero Member
  • *****
  • Posts: 1180
Re: QGradientTrackPanel: A Fully customizable GradientTrackBar
« Reply #5 on: August 17, 2026, 12:37:18 am »
Hey Ed78z, like the way you are extending the program and becoming quite creative.

Ah no need for saturation as you are using different Interpolation spaces.
   (Didn't want to  spam your reply)

We share the same name (Ed.) !
« Last Edit: August 17, 2026, 06:17:20 am by Boleeman »

Ed78z

  • Jr. Member
  • **
  • Posts: 77
Re: QGradientTrackPanel: A Fully customizable GradientTrackBar
« Reply #6 on: August 17, 2026, 01:24:17 am »
Hey Ed78z, like the way you are extending the program and becoming quite creative.

Noticed you have transparency (alpha) and brightness, but not saturation.


We share the same name (Ed.) !

Thank you Ed! for your feedback.

In my design, there is no need for a saturation value because I am using different Interpolation spaces (isLinearRGB, issRGB, isCosine, isHLS, isHSV, isOklab, isLab). So, everything will be done internally.
« Last Edit: August 17, 2026, 07:47:45 am by Ed78z »

Boleeman

  • Hero Member
  • *****
  • Posts: 1180
Re: QGradientTrackPanel: A Fully customizable GradientTrackBar
« Reply #7 on: August 28, 2026, 01:04:33 pm »
Came across a Lazarus gradient maker by Corpsman here:

https://github.com/PascalCorpsman/mini_projects/tree/main/miniprojects/Gradient_Maker

It has a Gauss mode.


"Boleeman,
I like to get your feedback about my QGradientPro demo program "


Wow. Your latest version has certainly got a lot of great features.

I played around with your presets and then played with the Jet rainbow with spiral and diamond geometries.
When I saved it took quite a while.
Then I realized the "test spiral rainbow.png" was 6131 kB sized to 8192 x 8192 pixels. So you are going for large/high resolution.
I tried changing the Hue direction from the TComboBox to clockwise and counter-clockwise but did not notice much of a change?

Also noticed the transparency slider was not active. When does it become active?

I really like the way when you click on the grid you can change the values with a slider or TSpinEdit  (There is also a Trackbar UpDown  in BgraControls).

Not sure if you are making your source public or not but I tried compiling but it was missing QGradientMath, QGradientEditorDlg, QGradientPreset, QGradient.

With effects, I like your vignette effect. I came across a Lazarus image/paint program that does a bulge effect (like a 3D ball distortion) which may be nice to include an a separate effect (like apply spiral and then bulge it, apply diamond and then bulge it).

Played around with the ripple effect. Fantastic, but how to adjust the transparency?

With distortion, not sure if you can include a dither effect? Actually scrap that (I found it under render effect)

I will play around some more. Can't believe all the features you have included. It's looking fantastic.

« Last Edit: August 28, 2026, 02:09:54 pm by Boleeman »

Boleeman

  • Hero Member
  • *****
  • Posts: 1180
Re: QGradientTrackPanel: A Fully customizable GradientTrackBar
« Reply #8 on: August 28, 2026, 02:27:59 pm »
A few more suggestions to extend your features even further:

I also tried the box effect, which I liked.
Then I thought you could possibly have a polygon effect, so instead of a rectangle you can alter the number of sides and make it like a tunnel effect.

Liked the Geometry Stroke Follow. Thought perhaps you could possibly have different bezier types (quadratic, cubic, quartic)?

Attached the Gauss effect from the Corpsman demo.

Also now attached the Lazarus source for LazView, that does sphere and cylinder bulge which is in vampireimaging component (the zip has some vampireimaging , dexif components to install). Not sure if they could done in BgraBmp?
« Last Edit: August 28, 2026, 03:58:11 pm by Boleeman »

Ed78z

  • Jr. Member
  • **
  • Posts: 77
Re: QGradientTrackPanel: A Fully customizable GradientTrackBar
« Reply #9 on: September 10, 2026, 08:02:25 pm »
Thank you for your detailed review and feedback! I was implementing these upgrades:

1) Bulge/Spherize Effect: Added! It automatically stacks with all shapes (Spirals, Diamonds, etc.) because distortions are calculated before the geometry.
2) Ripple Transparency: If you want flatter waves, lower the Distortion Amp. If you want see-through colors, just add transparency points to the Alpha Stops track.
3) Polygon Tunnels: Added a new Polygon geometry. You can set the exact number of sides (from a 3-sided triangle up to 20 sides) to build custom tunnels.
4) Bezier Curve Types: Upgraded the core math! The engine now automatically calculates the curve type (Quadratic, Cubic, Quartic, etc.) based purely on how many Stroke Nodes you add to the parameters grid.
5) Gaussian Spheres: You can build this using the Radial geometry, setting the Blend Type to Smooth Step, and applying the new Bulge distortion.
6) 3D Cylinders: You can build this using the Spiral geometry, applying the Bulge distortion, and turning on the 3D Lighting Effects or Vignette to shade the rounded edges.
7) Multi-Effect Stacking: You can now select multiple Render Effects at the exact same time! By checking multiple boxes, you can stack Environment/HDRI lighting, Vignette, and Noise Texture together to create incredibly rich, realistic 3D materials.
8] High-Res PNG Exporting: Added a brand new, upward-opening export menu that lets you instantly save your gradients and 3D shapes in resolutions all the way up to 8K.
9) High-DPI Support: The editor's UI, dynamic preview canvas, and track thumbs are now fully DPI-aware, meaning the engine scales flawlessly on 4K and high-resolution monitors.

Let me know what you think of the new effects!

-Ed78z

Download:
https://drive.google.com/file/d/1po55fx2d0pGdRJm4_bvObBlhSdFk4zIl/view?usp=drive_link

 

TinyPortal © 2005-2018