Browse Source

BCLea components

Boban Spasic 1 year ago
parent
commit
37d960ff9f
44 changed files with 10870 additions and 3 deletions
  1. 1423 0
      bclealcddisplay.pas
  2. 211 0
      bclealcddisplay_editor.pas
  3. 223 0
      bclealcddisplay_editorform.lfm
  4. 370 0
      bclealcddisplay_editorform.pas
  5. 27 0
      bclealcddisplay_editorregister.pas
  6. 443 0
      bclealed.pas
  7. 457 0
      bcleaqled.pas
  8. 736 0
      bclearingslider.pas
  9. 778 0
      bcleaselector.pas
  10. 2191 0
      bcleatheme.pas
  11. 26 0
      bcleatypes.pas
  12. 36 1
      bgracontrols.lpk
  13. 10 1
      bgracontrols.pas
  14. BIN
      images/TBCLeaLCDDisplay.png
  15. BIN
      images/TBCLeaLCDDisplay_150.png
  16. BIN
      images/TBCLeaLCDDisplay_200.png
  17. BIN
      images/TBCLeaLED.png
  18. BIN
      images/TBCLeaLED_150.png
  19. BIN
      images/TBCLeaLED_200.png
  20. BIN
      images/TBCLeaQLED.png
  21. BIN
      images/TBCLeaQLED_150.png
  22. BIN
      images/TBCLeaQLED_200.png
  23. BIN
      images/TBCLeaRingSlider.png
  24. BIN
      images/TBCLeaRingSlider_150.png
  25. BIN
      images/TBCLeaRingSlider_200.png
  26. BIN
      images/TBCLeaSelector.png
  27. BIN
      images/TBCLeaSelector_150.png
  28. BIN
      images/TBCLeaSelector_200.png
  29. BIN
      images/TBCLeaTheme.png
  30. BIN
      images/TBCLeaTheme_150.png
  31. BIN
      images/TBCLeaTheme_200.png
  32. BIN
      images/bgracontrols_images.res
  33. 19 1
      images/bgracontrols_images_list.txt
  34. 113 0
      styles/lea_alien.bclea
  35. 113 0
      styles/lea_default.bclea
  36. 113 0
      styles/lea_plastic_morph.bclea
  37. BIN
      test/test_bclea/ThemeBuillder.ico
  38. 161 0
      test/test_bclea/ThemeBuillder.lpi
  39. 24 0
      test/test_bclea/ThemeBuillder.lpr
  40. 113 0
      test/test_bclea/themes/lea_alien.bclea
  41. 113 0
      test/test_bclea/themes/lea_default.bclea
  42. 113 0
      test/test_bclea/themes/lea_plastic_morph.bclea
  43. 1904 0
      test/test_bclea/untThemeBuilder.lfm
  44. 1153 0
      test/test_bclea/untThemeBuilder.pas

+ 1423 - 0
bclealcddisplay.pas

@@ -0,0 +1,1423 @@
+{
+ *****************************************************************************
+  See the file COPYING.modifiedLGPL.txt, included in your Lazarus installation
+  for details about the license.
+ *****************************************************************************
+ Based on LCDLine by Yuriy Tereshchenko
+ Initial Lazarus port and multi-line extension: Boban Spasic ([email protected])
+ Further optimizations and extensions: Werner Pamler
+ Published under the name indLCDDisplay as part of the IndustrialStuff package
+
+ Conversion to BGRABitmap and published as part of the BComponents package
+ under the name BLCDDisplay: Boban Spasic 2024
+}
+unit BCLeaLCDDisplay;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  SysUtils, Classes, Controls, fgl, Graphics, LCLIntf,
+  laz2_dom, laz2_xmlwrite, laz2_xmlread,
+  BGRABitmapTypes, BGRABitmap, BGRAGradients, BCLeaTheme, BCLeaTypes;
+
+type
+  TBCLeaLCDDisplay = class;
+
+  TDotRow = integer;
+  TDotRows = array of TDotRow;
+  TDotMatrixList = specialize TFPGMap<string, TDotRows>;
+
+  TBCLeaCharDefs = class(TPersistent)
+  private
+    FBCLeaLCDDisplay: TBCLeaLCDDisplay;
+    FCharList: TDotMatrixList;
+    FColCount: integer;
+    FRowCount: integer;
+    function GetCharByIndex(AIndex: integer): string;
+    function GetCount: integer;
+    function GetDotRows(AChar: string): TDotRows;
+    function GetDotRowsByIndex(AIndex: integer): TDotRows;
+    procedure SetColCount(AValue: integer);
+    procedure SetDotRows(AChar: string; const AValue: TDotRows);
+    procedure SetRowCount(AValue: integer);
+    function EmptyRows: TDotRows;
+    procedure ReadCharDefs(Reader: TReader);
+    procedure WriteCharDefs(Writer: TWriter);
+  protected
+    procedure DefineProperties(Filer: TFiler); override;
+  public
+    constructor Create(ADisplay: TBCLeaLCDDisplay);
+    destructor Destroy; override;
+    procedure Add(AChar: string; const ADotRows: TDotRows);
+    procedure Assign(ASource: TPersistent); override;
+    procedure Clear;
+    procedure Delete(AChar: string);
+    function DotRowsToString(AChar: string): string;
+    function Find(const AChar: string): boolean;
+    procedure LoadFromFile(const AFileName: string);
+    function SameDotRows(const AChar: string; const ADotRows: TDotRows): boolean;
+    procedure SaveToFile(const AFileName: string);
+    property Count: integer read GetCount;
+    property CharByIndex[AIndex: integer]: string read GetCharByIndex;
+    property DotRows[AChar: string]: TDotRows read GetDotRows write SetDotRows;
+    property DotRowsByIndex[AIndex: integer]: TDotRows read GetDotRowsByIndex;
+  published
+    property ColCount: integer read FColCount write SetColCount;
+    property RowCount: integer read FRowCount write SetRowCount;
+  end;
+
+  TBCLeaLCDDisplay = class(TCustomControl)
+  private
+    FBitmap: TBGRABitmap;
+    FTheme: TBCLeaTheme;
+    {
+    one char consists of Col x Row of dots
+    dots have size and space between dots
+    }
+    FDotSize: integer;  // dot size in pixels
+    FDotsSpace: integer; // inter-dots space in pixels
+    FCharCount: integer;
+    FGlobalDotColsCount: integer;
+    FCharWidth: integer;
+    FFrameSize: integer;
+    FBoardWidth: integer;
+    FBoardHeight: integer;
+    FLEDWidth: integer;
+    FLEDHeight: integer;
+    FFrameColor: TColor;
+    FBoardColor: TColor;
+    FDotColorOn: TColor;
+    FLenText: integer;
+    FDisplayLineCount: integer;
+    FDisplayCharCount: integer;
+    FLines: TStrings;
+    FCountOn: integer;
+    FFrameStyle: TZStyle;
+    FFrameHeight: integer;
+    FFrameAltitude: integer;
+    FDotShape: TDotShape;
+    FCharDefs: TBCLeaCharDefs;
+    FOnChange: TNotifyEvent;
+    FDotBlend: boolean;
+    FDotBlendOperation: TBlendOperation;
+    FDotBlur: boolean;
+    FDotBlurRadius: single;
+    FBoardShadow: TBoardShadow;
+    //global intensity of the light
+    FLightSourceIntensity: single;
+    //minimum distance always added (positive value)
+    FLightSourceDistanceTerm: single;
+    //how much actual distance is taken into account (usually 0 or 1)
+    FLightSourceDistanceFactor: single;
+    //how much the location of the lightened pixel is taken into account (usually 0 or 1)
+    FLightDestFactor: single;
+    //color of the light reflection
+    FLightColor: TColor;
+    //how much light is reflected (0..1)
+    FSpecularFactor: single;
+    //how concentrated reflected light is (positive value)
+    FSpecularIndex: single;
+    //ambiant lighting whereever the point is (0..1)
+    FAmbientFactor: single;
+    //diffusion, i.e. how much pixels are lightened by light source (0..1)
+    FDiffusionFactor: single;
+    //how much hidden surface are darkened (0..1)
+    FNegativeDiffusionFactor: single;
+    //when diffusion saturates, use light color to show it
+    FDiffuseSaturation: boolean;
+    FLightPositionX: integer;
+    FLightPositionY: integer;
+    FLightPositionZ: integer;
+    function GetDotColCount: integer;
+    function GetDotRowCount: integer;
+    procedure SetDotColCount(AValue: integer);
+    procedure SetDotRowCount(AValue: integer);
+    procedure SetDotShape(const Value: TDotShape);
+    procedure SetFrameHeight(const Value: integer);
+    procedure SeTZStyle(const Value: TZStyle);
+    procedure SetFrameAltitude(const Value: integer);
+    function GetCharCount: longint;
+    function GetGlobalDotColsCount: longint;
+    procedure SetDisplayLineCount(const Value: integer);
+    procedure SetDisplayCharCount(const Value: integer);
+    procedure SetLines(const Value: TStrings);
+    procedure SetDotColorOn(const Value: TColor);
+    procedure SetBoardColor(const Value: TColor);
+    procedure SetFrameColor(const Value: TColor);
+    procedure SetFrameSize(const Value: integer);
+    procedure SetDotSize(const Value: integer);
+    procedure SetDotsSpace(const Value: integer);
+    function CalcCharCount: integer;
+    procedure InitCharDefs(ACharDefs: TBCLeaCharDefs; AHorDots, AVertDots: integer);
+    function IsCharDefsStored: boolean;
+    procedure LinesChanged(Sender: TObject);
+    procedure SetTheme(AValue: TBCLeaTheme);
+    //calculate widths and heights of the display matrix, background border and frame
+    procedure Prepare();
+    //draw frame
+    procedure DrawBorder();
+    //call DrawChar for every char
+    procedure DrawText();
+    //call DrawDot for every dot that is on
+    procedure DrawChar(Row, Col, NChar: integer);
+    procedure DrawDot(Row, Col: integer; DotColor: TColor);
+    procedure DrawBitmapToCanvas();
+  protected
+    // Basic method of auto-size calculation
+    procedure CalculatePreferredSize(var PreferredWidth, PreferredHeight: integer;
+    {%H-}WithThemeSpace: boolean); override;
+    // Takes care of high-dpi scaling
+    procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: double); override;
+    procedure DoChange; virtual;
+    // inherited painting routine
+    procedure Paint; override;
+    // Recalculates the geometry if a related property has been changed.
+    procedure UpdateSize;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    // Adds a user-defined character and its dot matrix.
+    procedure AddCharDef(AChar: string; const Dots: TDotRows);
+    property CharCount: longint read GetCharCount;
+    property DotColCount: integer read GetDotColCount;
+    property DotRowCount: integer read GetDotRowCount;
+    property GlobalDotColsCount: longint read GetGlobalDotColsCount;
+    procedure UpdateTheme;
+    procedure ApplyTheme;
+    procedure SaveThemeToFile(AFileName: string);
+    procedure LoadThemeFromFile(AFileName: string);
+    procedure ApplyDefaultTheme;
+  published
+    property AutoSize default True;
+    property BorderSpacing;
+    property ShowHint;
+    property Visible;
+    property OnClick;
+    property OnDblClick;
+    property OnMouseDown;
+    property OnMouseMove;
+    property OnMouseUp;
+    property CharDefs: TBCLeaCharDefs read FCharDefs write FCharDefs stored IsCharDefsStored;
+    property DotSize: integer read FDotSize write SetDotSize default 4;
+    property DotsSpace: integer read FDotsSpace write SetDotsSpace default 1;
+    property FrameSize: integer read FFrameSize write SetFrameSize default 8;
+    property FrameAltitude: integer read FFrameAltitude write SetFrameAltitude default 2;
+    property FrameColor: TColor read FFrameColor write SetFrameColor default clBtnFace;
+    // To use BoardColor, ColorScheme must be set to csCustom
+    property BoardColor: TColor read FBoardColor write SetBoardColor default clBlack;
+    // To use DotColorOn, ColorScheme must be set to csCustom
+    property DotColorOn: TColor read FDotColorOn write SetDotColorOn default clSkyBlue;
+    // Vertical screen size in chars
+    // Without AutoSize, if the frame is too small
+    // a part off the text will not be visible
+    // e.g. frame is big enough for one line
+    // and the text contains 3 lines
+    // - just the middle line will be visible
+    property DisplayLineCount: integer read FDisplayLineCount write SetDisplayLineCount default 2;
+    // Horizontal screen size in chars
+    // Set to <=0 (zero) to have a real AutoSize
+    // Has no effect without AutoSize
+    property DisplayCharCount: integer read FDisplayCharCount write SetDisplayCharCount default 10;
+    // The text to display
+    // It will be truncated according
+    // to ScreenRowCount and ScreenColCount
+    property Lines: TStrings read FLines write SetLines;
+    property FrameStyle: TZStyle read FFrameStyle write SeTZStyle default zsRaised;
+    property FrameHeight: integer read FFrameHeight write SetFrameHeight default 8;
+    property DotShape: TDotShape read FDotShape write SetDotShape default stSquare;
+    property OnChange: TNotifyEvent read FOnChange write FOnChange;
+    property Theme: TBCLeaTheme read FTheme write SetTheme;
+  end;
+
+function CopyDotRows(const ADotRows: array of TDotRow): TDotRows;
+
+procedure Register;
+
+implementation
+
+uses
+  Dialogs, LazUTF8, LazUnicode;
+
+const
+  DEFAULT_DOT_COL_COUNT = 5;
+  DEFAULT_DOT_ROW_COUNT = 7;
+
+procedure Register;
+begin
+  RegisterComponents('BGRA Controls', [TBCLeaLCDDisplay]);
+end;
+
+{ Create a "real" copy to avoid reference counter issues. }
+function CopyDotRows(const ADotRows: array of TDotRow): TDotRows;
+var
+  i: integer;
+begin
+  Result := nil;
+  SetLength(Result, Length(ADotRows));
+  for i := 0 to High(ADotRows) do
+    Result[i] := ADotRows[i];
+end;
+
+
+{ TBCLeaCharDefs }
+
+constructor TBCLeaCharDefs.Create(ADisplay: TBCLeaLCDDisplay);
+begin
+  inherited Create;
+  FBCLeaLCDDisplay := ADisplay;
+  FCharList := TDotMatrixList.Create;
+  FCharList.Sorted := True;
+end;
+
+destructor TBCLeaCharDefs.Destroy;
+begin
+  FCharList.Free;
+  inherited;
+end;
+
+{ Adds a new character dot matrix. }
+procedure TBCLeaCharDefs.Add(AChar: string; const ADotRows: TDotRows);
+begin
+  if Length(ADotRows) <> FRowCount then
+    raise Exception.Create('Incorrect number of rows.');
+  // Make sure to reset the reference counter --> use a local copy of ADotRows!
+  FCharList.Add(AChar, CopyDotRows(ADotRows));
+end;
+
+procedure TBCLeaCharDefs.Assign(ASource: TPersistent);
+var
+  i: integer;
+begin
+  if (ASource is TBCLeaCharDefs) then
+  begin
+    FColCount := TBCLeaCharDefs(ASource).ColCount;
+    FRowCount := TBCLeaCharDefs(ASource).RowCount;
+    Clear;
+    for i := 0 to TBCLeaCharDefs(ASource).Count - 1 do
+      Add(TBCLeaCharDefs(ASource).CharByIndex[i], TBCLeaCharDefs(ASource).DotRowsByIndex[i]);
+  end
+  else
+    inherited;
+end;
+
+{ Clears all characters and their dot matrices. }
+procedure TBCLeaCharDefs.Clear;
+begin
+  FCharList.Clear;
+end;
+
+{ Prepares streaming of the dot matrices }
+procedure TBCLeaCharDefs.DefineProperties(Filer: TFiler);
+begin
+  inherited DefineProperties(Filer);
+  Filer.DefineProperty('CharDefs', @ReadCharDefs, @WriteCharDefs, True);
+end;
+
+{ Deletes the specified character and its dot matrix from the list. }
+procedure TBCLeaCharDefs.Delete(AChar: string);
+var
+  idx: integer;
+begin
+  if FCharList.Find(AChar, idx) then
+    FCharList.Delete(idx);
+end;
+
+{ Display the elements of the RowDots as a string. For debugging purposes. }
+function TBCLeaCharDefs.DotRowsToString(AChar: string): string;
+var
+  lDotRows: TDotRows;
+  i: integer;
+begin
+  lDotRows := DotRows[AChar];
+  Result := IntToStr(lDotRows[0]);
+  for i := 1 to High(lDotRows) do
+    Result := Result + ',' + IntToStr(lDotRows[i]);
+end;
+
+{ Creates an empty row in which not dots are set. }
+function TBCLeaCharDefs.EmptyRows: TDotRows;
+var
+  row: integer;
+begin
+  Result := nil;
+  SetLength(Result, FRowCount);
+  for row := 0 to FRowCount - 1 do
+    Result[row] := 0;
+end;
+
+function TBCLeaCharDefs.GetCharByIndex(AIndex: integer): string;
+begin
+  Result := FCharList.Keys[AIndex];
+end;
+
+{ Returns the number of characters contained. }
+function TBCLeaCharDefs.GetCount: integer;
+begin
+  Result := FCharList.Count;
+end;
+
+{ Returns the dot matrix rows for the specified character. Each row is an 
+  integer in which each bit is interpreted as a dot. }
+function TBCLeaCharDefs.GetDotRows(AChar: string): TDotRows;
+var
+  idx: integer;
+begin
+  if FCharList.Find(AChar, idx) then
+    Result := FCharList.Data[idx]
+  else
+    Result := EmptyRows;
+end;
+
+function TBCLeaCharDefs.GetDotRowsByIndex(AIndex: integer): TDotRows;
+begin
+  Result := FCharList.Data[AIndex];
+end;
+
+function TBCLeaCharDefs.Find(const AChar: string): boolean;
+var
+  idx: integer;
+begin
+  Result := FCharList.Find(AChar, idx);
+end;
+
+{ Reads the list of character name and dot matrices from the LFM file. The data
+  are stored in the LFM as a comma-separated list beginning with the character 
+  name. }
+procedure TBCLeaCharDefs.ReadCharDefs(Reader: TReader);
+var
+  i: integer;
+  s: string;
+  ch: string;
+  sa: TStringArray;
+  rows: TDotRows = nil;
+begin
+  Clear;
+  Reader.ReadListBegin;
+  while not Reader.EndOfList do
+  begin
+    s := Reader.ReadString;
+    if s[1] = ',' then
+    begin
+      ch := ',';
+      System.Delete(s, 1, 2);
+    end
+    else
+    begin
+      i := pos(',', s);
+      ch := copy(s, 1, i - 1);
+      System.Delete(s, 1, i);
+    end;
+    sa := s.Split(',');
+    SetLength(rows, Length(sa));
+    for i := 0 to High(sa) do
+      rows[i] := StrToInt(sa[i]);
+    Add(ch, rows);
+  end;
+  Reader.ReadListEnd;
+end;
+
+function TBCLeaCharDefs.SameDotRows(const AChar: string; const ADotRows: TDotRows): boolean;
+var
+  i: integer;
+  lDotRows: TDotRows;
+begin
+  Result := False;
+  lDotRows := DotRows[AChar];
+  if (Length(lDotRows) <> Length(ADotRows)) then
+    exit;
+  for i := 0 to High(lDotRows) do
+    if lDotRows[i] <> ADotRows[i] then exit;
+  Result := True;
+end;
+
+function DotRowsToStr(ADotRows: TDotRows): string;
+var
+  i: integer;
+begin
+  Result := IntToStr(ADotRows[0]);
+  for i := 1 to High(ADotRows) do
+    Result := Result + ',' + IntToStr(ADotRows[i]);
+end;
+
+function StrToDotRows(AString: string): TDotRows;
+var
+  sa: TStringArray;
+  i: integer;
+begin
+  Result := nil;
+  sa := AString.Split(',');
+  SetLength(Result, Length(sa));
+  for i := 0 to High(sa) do
+    Result[i] := StrToInt(sa[i]);
+end;
+
+procedure TBCLeaCharDefs.LoadFromFile(const AFileName: string);
+var
+  doc: TXMLDocument = nil;
+  rootNode, parentNode, node, childNode: TDOMNode;
+  nodeName: string;
+  s: string;
+  ch: string;
+  dots: TDotRows;
+begin
+  FCharList.Clear;
+
+  try
+    ReadXMLFile(doc, AFileName);
+    rootNode := doc.DocumentElement;
+    parentNode := rootNode.FirstChild;
+    while Assigned(parentNode) do
+    begin
+      nodeName := parentNode.NodeName;
+      if nodeName = 'DotColCount' then
+      begin
+        s := TDOMElement(parentNode).GetAttribute('Value');
+        if s <> '' then
+          FColCount := StrToInt(s)
+        else
+          raise Exception.Create('DotColCount missing');
+      end
+      else
+      if nodeName = 'DotRowCount' then
+      begin
+        s := TDOMElement(parentNode).GetAttribute('Value');
+        if s <> '' then
+          FRowCount := StrToInt(s)
+        else
+          raise Exception.Create('DotRowCount missing');
+      end
+      else
+      if nodeName = 'Chars' then
+      begin
+        node := parentNode.FirstChild;
+        while Assigned(node) do
+        begin
+          childnode := node.FirstChild;
+          ch := '';
+          dots := nil;
+          while Assigned(childnode) do
+          begin
+            nodeName := childNode.NodeName;
+            if nodeName = 'Name' then
+              ch := childNode.TextContent
+            else
+            if nodeName = 'DotRows' then
+            begin
+              s := childNode.TextContent;
+              dots := StrToDotRows(s);
+            end;
+            childNode := childNode.NextSibling;
+          end;
+          if ch = '' then
+            raise Exception.Create('Char "Name" missing.');
+          if dots = nil then
+            raise Exception.Create('Char "DotRows" missing.');
+          Add(ch, dots);
+          node := node.NextSibling;
+        end;
+      end;
+      parentNode := parentNode.NextSibling;
+    end;
+
+    with FBCLeaLCDDisplay do
+    begin
+      if AutoSize then
+      begin
+        InvalidatePreferredSize;
+        AdjustSize;
+      end;
+      Invalidate;
+    end;
+
+  finally
+    doc.Free;
+  end;
+end;
+
+{ Saves the list (character plus dot matrix for each) to an xml file. }
+procedure TBCLeaCharDefs.SaveToFile(const AFileName: string);
+var
+  doc: TXMLDocument;
+  rootNode, parentNode, node, childNode, textNode: TDOMNode;
+  i: integer;
+begin
+  doc := TXMLDocument.Create;
+  try
+    rootNode := doc.CreateElement('LCD-CharDefs');
+    doc.AppendChild(rootNode);
+
+    rootNode := doc.DocumentElement;
+    node := doc.CreateElement('DotColCount');
+    TDOMElement(node).SetAttribute('Value', IntToStr(ColCount));
+    rootNode.AppendChild(node);
+
+    node := doc.CreateElement('DotRowCount');
+    TDOMElement(node).SetAttribute('Value', IntToStr(RowCount));
+    rootNode.AppendChild(node);
+
+    parentNode := doc.CreateElement('Chars');
+    rootNode.AppendChild(parentNode);
+
+    for i := 0 to Count - 1 do
+    begin
+      node := doc.CreateElement('Char');
+      parentNode.AppendChild(node);
+      childNode := doc.CreateElement('Name');
+      node.AppendChild(childNode);
+      textNode := doc.CreateTextNode(CharByIndex[i]);
+      childnode.AppendChild(textNode);
+      childNode := doc.CreateElement('DotRows');
+      node.AppendChild(childNode);
+      textNode := doc.CreateTextNode(DotRowsToStr(DotRowsByIndex[i]));
+      childNode.Appendchild(textNode);
+    end;
+
+    WriteXMLFile(doc, AFileName);
+  finally
+    doc.Free;
+  end;
+end;
+
+{ Returns the number of columns of the dot matrix. }
+procedure TBCLeaCharDefs.SetColCount(AValue: integer);
+begin
+  if FColCount = AValue then
+    exit;
+  FColCount := AValue;
+  FCharList.Clear;
+end;
+
+{ Sets the dot matrix for the specified character }
+procedure TBCLeaCharDefs.SetDotRows(AChar: string; const AValue: TDotRows);
+var
+  idx: integer;
+begin
+  if FCharList.Find(AChar, idx) then
+    Delete(AChar);
+  Add(AChar, AValue);
+end;
+
+{ Returns the number of rows of the dot matrix. }
+procedure TBCLeaCharDefs.SetRowCount(AValue: integer);
+begin
+  if FRowCount = AValue then
+    exit;
+  FRowCount := AValue;
+  FCharList.Clear;
+end;
+
+{ Write the character and its dot matrix to the LFM. Each character is stored
+  as a comma-separated list of character and dotrow values. }
+procedure TBCLeaCharDefs.WriteCharDefs(Writer: TWriter);
+var
+  i, j: integer;
+  ch: string;
+  rows: TDotRows;
+  s: string;
+begin
+  Writer.WriteListBegin;
+  for i := 0 to Count - 1 do
+  begin
+    ch := FCharList.Keys[i];
+    rows := DotRows[ch];
+    s := ch;
+    for j := 0 to FRowCount - 1 do
+      s := s + ',' + IntToStr(rows[j]);
+    Writer.WriteString(s);
+  end;
+  Writer.WriteListEnd;
+end;
+
+(*
+{ TBCLeaLCDDisplayStrings }
+
+type
+  TBCLeaLCDDisplayStrings = class(TStrings)
+  private
+    FOnChange: TNotifyEvent;
+  public
+    property OnChange: TNotifyEvent read FOnChange write FOnChange;
+  end;
+*)
+
+{ TBCLeaLCDDisplay}
+
+constructor TBCLeaLCDDisplay.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  ControlStyle := ControlStyle + [csOpaque];
+
+  Width := 156;
+  Height := 76;
+
+  FDisplayLineCount := 2;
+  FDisplayCharCount := 10;
+  FBoardWidth := 4;
+
+  FCharDefs := TBCLeaCharDefs.Create(self);
+  FCharDefs.ColCount := DEFAULT_DOT_COL_COUNT;
+  FCharDefs.RowCount := DEFAULT_DOT_ROW_COUNT;
+  InitCharDefs(FCharDefs, DotColCount, DotRowCount);
+
+  FBitmap := TBGRABitmap.Create;
+  FCountOn := 255;
+
+  FLines := TStringList.Create;
+  TStringList(FLines).OnChange := @LinesChanged;
+  AutoSize := True;
+
+  ApplyDefaultTheme;
+end;
+
+destructor TBCLeaLCDDisplay.Destroy;
+begin
+  FreeAndNil(FBitmap);
+  FCharDefs.Free;
+  FLines.Free;
+  inherited Destroy;
+end;
+
+procedure TBCLeaLCDDisplay.AddCharDef(AChar: string; const Dots: TDotRows);
+begin
+  FCharDefs.Add(AChar, Dots);
+end;
+
+procedure TBCLeaLCDDisplay.CalculatePreferredSize(var PreferredWidth, PreferredHeight: integer; WithThemeSpace: boolean);
+var
+  nDotCols: integer;
+  nDotRows: integer;
+begin
+  nDotCols := DotColCount;
+  nDotRows := DotRowCount;
+
+  FCharWidth := (DotSize * nDotCols) + (DotsSpace * (nDotCols + 1)); //pixels
+  FCharCount := CalcCharCount;
+  FGlobalDotColsCount := (FCharCount * nDotCols) + (FCharCount - 1);      //dots
+
+  // total matrix width
+  FLEDWidth := (FGlobalDotColsCount * DotSize) + ((FGlobalDotColsCount - 1) * DotsSpace);
+  // total matrix height
+  FLEDHeight := (FDisplayLineCount * nDotRows * (DotSize + DotsSpace)) +
+    ((FDisplayLineCount - 1) * (DotSize + DotsSpace));
+
+  //background around text matrix - left/right pixels
+  FBoardWidth := DotSize + DotsSpace;
+  //background around text matrix - up/down pixels
+  FBoardHeight := DotSize + DotsSpace;
+
+  //Total size incl. frame
+  PreferredWidth := FLEDWidth + (2 * FrameSize) + (2 * FBoardWidth);
+  PreferredHeight := FLEDHeight + (2 * FrameSize) + (2 * FBoardWidth);
+end;
+
+procedure TBCLeaLCDDisplay.DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy; const AXProportion, AYProportion: double);
+begin
+  inherited;
+  if AMode in [lapAutoAdjustWithoutHorizontalScrolling, lapAutoAdjustForDPI] then
+  begin
+    FDotSize := round(FDotSize * AXProportion);
+    FDotsSpace := round(FDotsSpace * AXProportion);
+    FFrameSize := round(FFrameSize * AXProportion);
+  end;
+end;
+
+procedure TBCLeaLCDDisplay.DoChange;
+begin
+  if Assigned(FOnChange) then FOnChange(Self);
+end;
+
+procedure TBCLeaLCDDisplay.Prepare();
+var
+  nDotCols: integer;
+  nDotRows: integer;
+begin
+  nDotCols := DotColCount;
+  nDotRows := DotRowCount;
+
+  FCharWidth := (DotSize * nDotCols) + (DotsSpace * (nDotCols + 1)); //pixels
+  FCharCount := ((Width - (2 * FrameSize)) + DotSize) div (FCharWidth + DotSize);
+  FGlobalDotColsCount := (FCharCount * nDotCols) + (FCharCount - 1);      //dots
+
+  // total matrix width
+  FLEDWidth := (FGlobalDotColsCount * DotSize) + ((FGlobalDotColsCount - 1) * DotsSpace);
+  // total matrix height
+  FLEDHeight := (FDisplayLineCount * nDotRows * (DotSize + DotsSpace)) +
+    ((FDisplayLineCount - 1) * (DotSize + DotsSpace));
+
+  FBoardWidth := (Width - 2 * FrameSize - FLEDWidth) div 2;
+  FBoardHeight := (Height - 2 * FrameSize - FLEDHeight) div 2;
+
+  FBitmap.SetSize(Width, Height);
+  FBitmap.Fill(FBoardColor);
+  FBitmap.Canvas2D.resetTransform;
+end;
+
+procedure TBCLeaLCDDisplay.DrawBorder();
+var
+  ScaledPhongSize: integer;
+  EffectiveLineWidth: single;
+  Blur, Mask, TempBMP, ShadowBoard: TBGRABitmap;
+  Phong: TPhongShading;
+begin
+
+  if FFrameHeight = 0 then
+    EffectiveLineWidth := Height / 12
+  else
+    EffectiveLineWidth := FFrameHeight;
+
+  FBitmap.Canvas2D.lineWidth := EffectiveLineWidth;
+
+  FBitmap.Canvas2D.lineCapLCL := pecRound;
+  FBitmap.Canvas2D.strokeStyle(FrameColor);
+  FBitmap.Canvas2D.beginPath;
+  FBitmap.Canvas2D.rect(FFrameHeight / 2, FFrameHeight / 2, Width - FFrameHeight, Height - FFrameHeight);
+  FBitmap.Canvas2D.stroke;
+
+  if (FFrameStyle = zsLowered) or (FFRameStyle = zsRaised) then
+  begin
+    //make a copy for bsOwn
+    ShadowBoard := TBGRABitmap.Create(Width, Height, BGRABlack);
+    ShadowBoard.PutImage(0, 0, FBitmap, dmSet);
+    //draw frame inclusive board
+    ScaledPhongSize := round(EffectiveLineWidth / 2);
+    Mask := FBitmap.FilterGrayscale as TBGRABitmap;
+    if FFRameStyle = zsLowered then
+      Mask.Negative;
+    Blur := Mask.FilterBlurRadial(ScaledPhongSize, ScaledPhongSize, rbFast) as TBGRABitmap;
+    Blur.FillMask(0, 0, Mask, BGRAPixelTransparent, dmSet);
+    Mask.Free;
+    //make it 3D
+    Phong := TPhongShading.Create;
+    if assigned(FTheme) then
+    begin
+      Phong.AmbientFactor := FAmbientFactor;
+      Phong.SpecularIndex := FSpecularIndex;
+      Phong.LightDestFactor := FLightDestFactor;
+      Phong.LightPosition := Point(FLightPositionX, FLightPositionY);
+      Phong.LightPositionZ := FLightPositionZ;
+      Phong.LightSourceIntensity := FLightSourceIntensity;
+      Phong.LightSourceDistanceTerm := FLightSourceDistanceTerm;
+      Phong.LightSourceDistanceFactor := FLightSourceDistanceFactor;
+      Phong.NegativeDiffusionFactor := FNegativeDiffusionFactor;
+      Phong.SpecularFactor := FSpecularFactor;
+      Phong.DiffusionFactor := FDiffusionFactor;
+      Phong.DiffuseSaturation := FDiffuseSaturation;
+      Phong.LightColor := FLightColor;
+    end;
+
+    Phong.Draw(FBitmap, Blur, FFrameAltitude, 0, 0, FBitmap);
+    Phong.Free;
+    //now are both the frame and the board processed with phong effect and stored in FBitmap
+
+    //re-draw board (without frame)
+    if FBoardShadow = bsNone then
+    begin
+      //create mask for the frame
+      Mask := TBGRABitmap.Create(Width, Height, BGRABlack);
+      Mask.Canvas2D.lineWidth := EffectiveLineWidth;
+      Mask.Canvas2D.lineCapLCL := pecRound;
+      Mask.Canvas2D.strokeStyle(BGRAWhite);
+      Mask.Canvas2D.beginPath;
+      Mask.Canvas2D.rect(FFrameHeight / 2, FFrameHeight / 2, Width - FFrameHeight, Height - FFrameHeight);
+      Mask.Canvas2D.stroke;
+      //create new bitmap in BoardColor and add just the frame
+      TempBMP := TBGRABitmap.Create(Width, Height, ColorToBGRA(ColorToRGB(FBoardColor)));
+      TempBMP.PutImage(0, 0, FBitmap, dmSet);
+      TempBMP.ApplyMask(Mask);
+      Mask.Free;
+      FBitmap.Fill(FBoardColor);
+      FBitmap.PutImage(0, 0, TempBMP, dmDrawWithTransparency);
+      TempBMP.Free;
+    end;
+    if FBoardShadow = bsOwn then
+    begin
+      //ToDo - not sure about this
+      Phong := TPhongShading.Create;
+      if assigned(FTheme) then
+      begin
+        Phong.AmbientFactor := FAmbientFactor;
+        Phong.SpecularIndex := FSpecularIndex;
+        Phong.LightDestFactor := FLightDestFactor;
+        Phong.LightPosition := Point(FLightPositionX, FLightPositionY);
+        Phong.LightPositionZ := FLightPositionZ;
+        Phong.LightSourceIntensity := FLightSourceIntensity;
+        Phong.LightSourceDistanceTerm := FLightSourceDistanceTerm;
+        Phong.LightSourceDistanceFactor := FLightSourceDistanceFactor;
+        Phong.NegativeDiffusionFactor := FNegativeDiffusionFactor;
+        Phong.SpecularFactor := FSpecularFactor;
+        Phong.DiffusionFactor := FDiffusionFactor;
+        Phong.DiffuseSaturation := FDiffuseSaturation;
+        Phong.LightColor := FLightColor;
+      end;
+      Phong.Draw(ShadowBoard, Blur, 1, 0, 0, ShadowBoard);
+      Phong.Free;
+      //create mask for the frame
+      Mask := TBGRABitmap.Create(Width, Height, BGRAWhite);
+      Mask.Canvas2D.lineWidth := EffectiveLineWidth;
+      Mask.Canvas2D.lineCapLCL := pecRound;
+      Mask.Canvas2D.strokeStyle(BGRABlack);
+      Mask.Canvas2D.beginPath;
+      Mask.Canvas2D.rect(FFrameHeight / 2, FFrameHeight / 2, Width - FFrameHeight, Height - FFrameHeight);
+      Mask.Canvas2D.stroke;
+      ShadowBoard.ApplyMask(Mask);
+      Mask.Free;
+      FBitmap.PutImage(0, 0, ShadowBoard, dmDrawWithTransparency);
+    end;
+    ShadowBoard.Free;
+    Blur.Free;
+  end;
+end;
+
+procedure TBCLeaLCDDisplay.DrawText();
+var
+  x, y, c: integer;
+  dots: TDotRows;
+  dotRow: TDotRow;
+  dotOn: boolean;
+  i: integer;
+  line: string;
+  ch: string;
+begin
+  for i := 0 to FDisplayLineCount - 1 do
+  begin
+    if i < FLines.Count then
+    begin
+      line := FLines[i];
+      FLenText := UTF8Length(line);
+
+      c := 0;
+      for ch in line do
+      begin
+        Inc(c);
+        dots := FCharDefs.DotRows[ch];
+        for y := 0 to DotRowCount - 1 do
+        begin
+          DotRow := dots[y];
+          for x := 0 to 4 do
+          begin
+            DotOn := DotRow and (1 shl (5 - x - 1)) > 0;
+            if DotOn then
+              DrawChar(y + 8 * i, x, c);
+          end; // for x
+        end;  // for y
+      end;  // for ch
+    end;
+  end;
+end;
+
+
+procedure TBCLeaLCDDisplay.DrawChar(Row, Col, NChar: integer);
+begin
+
+  Col := Col + ((DotColCount + 1) * (NChar - 1));
+  if Col > FGlobalDotColsCount - 1 then
+    Exit;
+  if Col < 0 then
+    Exit;
+  DrawDot(Row, Col, FDotColorOn);
+
+end;
+
+procedure TBCLeaLCDDisplay.DrawDot(Row, Col: integer; DotColor: TColor);
+var
+  DotR: TRect;
+  Mask: TBGRABitmap;
+begin
+  DotR.Left := FrameSize + FBoardWidth + (DotSize + DotsSpace) * Col;
+  DotR.Top := FrameSize + FBoardHeight + (DotSize + DotsSpace) * Row;
+  DotR.Right := DotR.Left + DotSize;
+  DotR.Bottom := DotR.Top + DotSize;
+  //todo
+  if FFrameHeight = 4 then
+  begin
+    if (DotR.Top <= FFrameSize) or (DotR.Bottom >= Height - FFrameSize) then
+      exit;
+    if (DotR.Left <= FFrameSize) or (DotR.Right >= Width - FFrameSize) then
+      exit;
+  end
+  else
+  begin
+    if (DotR.Top <= FFrameSize + 1) or (DotR.Bottom >= Height - FFrameSize - 1) then
+      exit;
+    if (DotR.Left <= FFrameSize + 1) or (DotR.Right >= Width - FFrameSize - 1) then
+      exit;
+  end;
+
+  Mask := TBGRABitmap.Create(Width, Height);
+  if DotShape = stSquare then
+    Mask.FillRect(DotR, DotColor)
+  else
+    Mask.FillEllipseAntialias(DotR.Left + DotSize / 2, DotR.Top + DotSize / 2, DotSize / 2, DotSize / 2, DotColor);
+  if FDotBlur then
+    Mask := Mask.FilterBlurRadial(DotSize * FDotBlurRadius, DotSize * FDotBlurRadius, rbFast);
+  if FDotBlend then
+    FBitmap.BlendImageOver(0, 0, Mask, FDotBlendOperation)
+  else
+    FBitmap.PutImage(0, 0, Mask, dmDrawWithTransparency);
+  Mask.Free;
+end;
+
+procedure TBCLeaLCDDisplay.DrawBitmapToCanvas();
+begin
+  FBitmap.Draw(Canvas, 0, 0, True);
+end;
+
+procedure TBCLeaLCDDisplay.Paint();
+begin
+  Prepare();
+  DrawBorder();
+  DrawText();
+  DrawBitmapToCanvas();
+end;
+
+// Find the longest's line length
+function TBCLeaLCDDisplay.CalcCharCount: integer;
+var
+  len: integer;
+  i, tmp: integer;
+begin
+  len := 1;
+  if FDisplayCharCount > 0 then
+    Result := FDisplayCharCount
+  else
+  begin
+    for i := 0 to FDisplayLineCount - 1 do
+    begin
+      if i < Lines.Count then
+      begin
+        tmp := UTF8Length(Lines[i]);
+        if tmp > Len then Len := tmp;
+      end;
+    end;
+    Result := Len;
+  end;
+end;
+
+procedure TBCLeaLCDDisplay.InitCharDefs(ACharDefs: TBCLeaCharDefs; AHorDots, AVertDots: integer);
+begin
+  ACharDefs.Clear;
+  if (AHorDots = DEFAULT_DOT_COL_COUNT) and (AVertDots = DEFAULT_DOT_ROW_COUNT) then
+  begin
+    // Note: Passing the array via CopyDotRows is for compilation with FPC before v3.2
+    ACharDefs.Add('!', CopyDotRows([4, 4, 4, 4, 4, 0, 4]));        // #33
+    ACharDefs.Add('"', CopyDotRows([10, 10, 0, 0, 0, 0, 0]));      // #34
+    ACharDefs.Add('#', CopyDotRows([0, 10, 31, 10, 31, 10, 0]));   // #35
+    ACharDefs.Add('$', CopyDotRows([4, 15, 20, 14, 5, 30, 4]));    // #36
+    ACharDefs.Add('%', CopyDotRows([25, 26, 2, 4, 8, 11, 19]));    // #37
+    ACharDefs.Add('&', CopyDotRows([12, 18, 20, 8, 21, 18, 13]));  // #38
+    ACharDefs.Add('''', CopyDotRows([4, 4, 0, 0, 0, 0, 0]));       // #39
+    ACharDefs.Add('(', CopyDotRows([2, 4, 8, 8, 8, 4, 2]));        // #40
+    ACharDefs.Add(')', CopyDotRows([8, 4, 2, 2, 2, 4, 8]));        // #41
+    ACharDefs.Add('*', CopyDotRows([0, 4, 21, 14, 21, 4, 0]));     // #42
+    ACharDefs.Add('+', CopyDotRows([0, 4, 4, 31, 4, 4, 0]));       // #43
+    ACharDefs.Add(',', CopyDotRows([0, 0, 0, 0, 12, 4, 8]));       // #44
+    ACharDefs.Add('-', CopyDotRows([0, 0, 0, 14, 0, 0, 0]));       // #45
+    ACharDefs.Add('.', CopyDotRows([0, 0, 0, 0, 0, 12, 12]));      // #46
+    ACharDefs.Add('/', CopyDotRows([1, 1, 2, 4, 8, 16, 16]));      // #47
+    ACharDefs.Add('0', CopyDotRows([14, 17, 19, 21, 25, 17, 14])); // #48
+    ACharDefs.Add('1', CopyDotRows([4, 12, 4, 4, 4, 4, 14]));      // #49
+    ACharDefs.Add('2', CopyDotRows([14, 17, 1, 2, 4, 8, 31]));     // #50
+    ACharDefs.Add('3', CopyDotRows([14, 17, 1, 6, 1, 17, 14]));    // #51
+    ACharDefs.Add('4', CopyDotRows([2, 6, 10, 18, 31, 2, 2]));     // #52
+    ACharDefs.Add('5', CopyDotRows([31, 16, 30, 1, 1, 17, 14]));   // #53
+    ACharDefs.Add('6', CopyDotRows([14, 17, 16, 30, 17, 17, 14])); // #54
+    ACharDefs.Add('7', CopyDotRows([31, 1, 1, 2, 4, 4, 4]));       // #55
+    ACharDefs.Add('8', CopyDotRows([14, 17, 17, 14, 17, 17, 14])); // #56
+    ACharDefs.Add('9', CopyDotRows([14, 17, 17, 15, 1, 17, 14]));  // #57
+    ACharDefs.Add(':', CopyDotRows([0, 12, 12, 0, 12, 12, 0]));    // #58
+    ACharDefs.Add(';', CopyDotRows([0, 12, 12, 0, 12, 4, 8]));     // #59
+    ACharDefs.Add('<', CopyDotRows([2, 4, 8, 16, 8, 4, 2]));       // #60
+    ACharDefs.Add('=', CopyDotRows([0, 0, 31, 0, 31, 0, 0]));      // #61
+    ACharDefs.Add('>', CopyDotRows([8, 4, 2, 1, 2, 4, 8]));        // #62
+    ACharDefs.Add('?', CopyDotRows([14, 17, 1, 2, 4, 0, 4]));      // #63
+    ACharDefs.Add('@', CopyDotRows([14, 17, 19, 21, 23, 16, 15])); // #64
+    ACharDefs.Add('A', CopyDotRows([14, 17, 17, 31, 17, 17, 17])); // #65
+    ACharDefs.Add('B', CopyDotRows([30, 17, 17, 30, 17, 17, 30])); // #66
+    ACharDefs.Add('C', CopyDotRows([14, 17, 16, 16, 16, 17, 14])); // #67
+    ACharDefs.Add('D', CopyDotRows([30, 17, 17, 17, 17, 17, 30])); // #68
+    ACharDefs.Add('E', CopyDotRows([31, 16, 16, 30, 16, 16, 31])); // #69
+    ACharDefs.Add('F', CopyDotRows([31, 16, 16, 30, 16, 16, 16])); // #70
+    ACharDefs.Add('G', CopyDotRows([14, 17, 16, 19, 17, 17, 14])); // #71
+    ACharDefs.Add('H', CopyDotRows([17, 17, 17, 31, 17, 17, 17])); // #72
+    ACharDefs.Add('I', CopyDotRows([14, 4, 4, 4, 4, 4, 14]));      // #73
+    ACharDefs.Add('J', CopyDotRows([1, 1, 1, 1, 17, 17, 14]));     // #74
+    ACharDefs.Add('K', CopyDotRows([17, 18, 20, 24, 20, 18, 17])); // #75
+    ACharDefs.Add('L', CopyDotRows([16, 16, 16, 16, 16, 16, 31])); // #76
+    ACharDefs.Add('M', CopyDotRows([17, 27, 21, 21, 17, 17, 17])); // #77
+    ACharDefs.Add('N', CopyDotRows([17, 25, 21, 19, 17, 17, 17])); // #78
+    ACharDefs.Add('O', CopyDotRows([14, 17, 17, 17, 17, 17, 14])); // #79
+    ACharDefs.Add('P', CopyDotRows([30, 17, 17, 30, 16, 16, 16])); // #80
+    ACharDefs.Add('Q', CopyDotRows([14, 17, 17, 17, 17, 14, 1]));  // #81
+    ACharDefs.Add('R', CopyDotRows([30, 17, 17, 30, 17, 17, 17])); // #82
+    ACharDefs.Add('S', CopyDotRows([14, 17, 16, 14, 1, 17, 14]));  // #83
+    ACharDefs.Add('T', CopyDotRows([31, 4, 4, 4, 4, 4, 4]));       // #84
+    ACharDefs.Add('U', CopyDotRows([17, 17, 17, 17, 17, 17, 14])); // #85
+    ACharDefs.Add('V', CopyDotRows([17, 17, 17, 17, 17, 10, 4]));  // #86
+    ACharDefs.Add('W', CopyDotRows([17, 17, 17, 17, 21, 27, 17])); // #87
+    ACharDefs.Add('X', CopyDotRows([17, 10, 4, 4, 4, 10, 17]));    // #88
+    ACharDefs.Add('Y', CopyDotRows([17, 17, 17, 10, 4, 4, 4]));    // #89
+    ACharDefs.Add('Z', CopyDotRows([31, 1, 2, 4, 8, 16, 31]));     // #90
+    ACharDefs.Add('[', CopyDotRows([12, 8, 8, 8, 8, 8, 12]));      // #91
+    ACharDefs.Add('\', CopyDotRows([0, 16, 8, 4, 2, 1, 0]));       // #92
+    ACharDefs.Add(']', CopyDotRows([6, 2, 2, 2, 2, 2, 6]));        // #93
+    ACharDefs.Add('^', CopyDotRows([4, 10, 17, 0, 0, 0, 0]));      // #94
+    ACharDefs.Add('_', CopyDotRows([0, 0, 0, 0, 0, 0, 31]));       // #95
+    ACharDefs.Add('`', CopyDotRows([6, 4, 2, 0, 0, 0, 0]));        // #96
+    ACharDefs.Add('a', CopyDotRows([0, 0, 14, 1, 15, 17, 15]));    // #97
+    ACharDefs.Add('b', CopyDotRows([16, 16, 30, 17, 17, 17, 30])); // #98
+    ACharDefs.Add('c', CopyDotRows([0, 0, 15, 16, 16, 16, 15]));   // #99
+    ACharDefs.Add('d', CopyDotRows([1, 1, 15, 17, 17, 17, 15]));  // #100
+    ACharDefs.Add('e', CopyDotRows([0, 0, 14, 17, 31, 16, 14]));  // #101
+    ACharDefs.Add('f', CopyDotRows([3, 4, 31, 4, 4, 4, 4]));      // #102
+    ACharDefs.Add('g', CopyDotRows([0, 0, 15, 17, 15, 1, 14]));   // #103
+    ACharDefs.Add('h', CopyDotRows([16, 16, 22, 25, 17, 17, 17]));// #104
+    ACharDefs.Add('i', CopyDotRows([4, 0, 12, 4, 4, 4, 14]));     // #105
+    ACharDefs.Add('j', CopyDotRows([2, 0, 6, 2, 2, 18, 12]));     // #106
+    ACharDefs.Add('k', CopyDotRows([16, 16, 18, 20, 24, 20, 18]));// #107
+    ACharDefs.Add('l', CopyDotRows([12, 4, 4, 4, 4, 4, 14]));     // #108
+    ACharDefs.Add('m', CopyDotRows([0, 0, 26, 21, 21, 21, 21]));  // #109
+    ACharDefs.Add('n', CopyDotRows([0, 0, 22, 25, 17, 17, 17]));  // #110
+    ACharDefs.Add('o', CopyDotRows([0, 0, 14, 17, 17, 17, 14]));  // #111
+    ACharDefs.Add('p', CopyDotRows([0, 0, 30, 17, 30, 16, 16]));  // #112
+    ACharDefs.Add('q', CopyDotRows([0, 0, 15, 17, 15, 1, 1]));    // #113
+    ACharDefs.Add('r', CopyDotRows([0, 0, 11, 12, 8, 8, 8]));     // #114
+    ACharDefs.Add('s', CopyDotRows([0, 0, 14, 16, 14, 1, 30]));   // #115
+    ACharDefs.Add('t', CopyDotRows([4, 4, 31, 4, 4, 4, 3]));      // #116
+    ACharDefs.Add('u', CopyDotRows([0, 0, 17, 17, 17, 19, 13]));  // #117
+    ACharDefs.Add('v', CopyDotRows([0, 0, 17, 17, 17, 10, 4]));   // #118
+    ACharDefs.Add('w', CopyDotRows([0, 0, 17, 17, 21, 21, 10]));  // #119
+    ACharDefs.Add('x', CopyDotRows([0, 0, 17, 10, 4, 10, 17]));   // #120
+    ACharDefs.Add('y', CopyDotRows([0, 0, 17, 17, 15, 1, 14]));   // #121
+    ACharDefs.Add('z', CopyDotRows([0, 0, 31, 2, 4, 8, 31]));     // #122
+    ACharDefs.Add('{', CopyDotRows([3, 4, 4, 8, 4, 4, 3]));       // #123
+    ACharDefs.Add('|', CopyDotRows([4, 4, 4, 4, 4, 4, 4]));       // #124
+    ACharDefs.Add('}', CopyDotRows([24, 4, 4, 2, 4, 4, 24]));     // #125
+    ACharDefs.Add('~', CopyDotRows([8, 21, 2, 0, 0, 0, 0]));      // #126
+  end;
+end;
+
+{ Determines whether the character definitons must be stored in the lfm file.
+  They are NOT stored when the currently used defs are exactly the same as those
+  generated by IniTBCLeaCharDefs. }
+function TBCLeaLCDDisplay.IsCharDefsStored: boolean;
+var
+  defs: TBCLeaCharDefs;
+  i: integer;
+  ch1, ch2: string;
+  dotRows1: TDotRows;
+begin
+  Result := True;
+  if (DotRowCount <> DEFAULT_DOT_ROW_COUNT) or (DotColCount <> DEFAULT_DOT_COL_COUNT) then
+    exit;
+  defs := TBCLeaCharDefs.Create(self);
+  try
+    defs.ColCount := DEFAULT_DOT_COL_COUNT;
+    defs.RowCount := DEFAULT_DOT_ROW_COUNT;
+    InitCharDefs(defs, defs.ColCount, defs.RowCount);
+    if defs.Count <> FCharDefs.Count then
+      exit;
+    for i := 0 to defs.Count - 1 do
+    begin
+      ch1 := defs.CharByIndex[i];
+      ch2 := FCharDefs.CharByIndex[i];
+      ;
+      if (ch1 <> ch2) then
+        exit;
+      dotRows1 := defs.DotRowsByIndex[i];
+      if not FCharDefs.SameDotRows(ch1, dotRows1) then
+        exit;
+    end;
+    Result := False;
+  finally
+    defs.Free;
+  end;
+end;
+
+procedure TBCLeaLCDDisplay.SetBoardColor(const Value: TColor);
+begin
+  if Value = FBoardColor then
+    Exit;
+  FBoardColor := Value;
+end;
+
+procedure TBCLeaLCDDisplay.SetDotColorOn(const Value: TColor);
+begin
+  if Value = FDotColorOn then
+    Exit;
+  FDotColorOn := Value;
+end;
+
+procedure TBCLeaLCDDisplay.SetDotSize(const Value: integer);
+begin
+  if Value = DotSize then
+    Exit;
+  FDotSize := Value;
+  UpdateSize;
+end;
+
+procedure TBCLeaLCDDisplay.SetDotsSpace(const Value: integer);
+begin
+  if Value = DotsSpace then
+    Exit;
+  FDotsSpace := Value;
+  UpdateSize;
+end;
+
+procedure TBCLeaLCDDisplay.SetDotShape(const Value: TDotShape);
+begin
+  if Value = DotShape then
+    Exit;
+  FDotShape := Value;
+  Invalidate;
+end;
+
+procedure TBCLeaLCDDisplay.SetFrameColor(const Value: TColor);
+begin
+  if Value = FrameColor then
+    Exit;
+  FFrameColor := Value;
+  Invalidate;
+end;
+
+procedure TBCLeaLCDDisplay.SetFrameHeight(const Value: integer);
+begin
+  if Value = FrameHeight then
+    Exit;
+  FFrameHeight := Value;
+  if FFrameSize < FFrameHeight then FFrameSize := FFrameHeight;
+  UpdateSize;
+end;
+
+procedure TBCLeaLCDDisplay.SetFrameSize(const Value: integer);
+begin
+  if Value = FrameSize then
+    Exit;
+  FFrameSize := Value;
+  if FFrameSize < FFrameHeight then FFrameHeight := FFrameSize;
+  UpdateSize;
+end;
+
+//Added with conversion to BGRABitmap
+procedure TBCLeaLCDDisplay.SetFrameAltitude(const Value: integer);
+begin
+  if Value = FrameAltitude then
+    Exit;
+  FFrameAltitude := Value;
+  Invalidate;
+end;
+
+procedure TBCLeaLCDDisplay.SeTZStyle(const Value: TZStyle);
+begin
+  if Value = FrameStyle then
+    Exit;
+  FFrameStyle := Value;
+  UpdateSize;
+end;
+
+procedure TBCLeaLCDDisplay.SetDisplayLineCount(const Value: integer);
+begin
+  if Value = FDisplayLineCount then
+    Exit;
+  FDisplayLineCount := Value;
+  UpdateSize;
+end;
+
+procedure TBCLeaLCDDisplay.SetDisplayCharCount(const Value: integer);
+begin
+  if Value = FDisplayCharCount then
+    Exit;
+  FDisplayCharCount := Value;
+  UpdateSize;
+end;
+
+procedure TBCLeaLCDDisplay.SetLines(const Value: TStrings);
+var
+  i: integer;
+begin
+  FLines.Clear;
+  for i := 0 to FDisplayLineCount - 1 do
+  begin
+    if i < Value.Count then
+      FLines.Add(Value[i])
+    else
+      FLines.Add(' ');
+  end;
+  LinesChanged(self);
+end;
+
+function TBCLeaLCDDisplay.GetCharCount: longint;
+begin
+  Prepare();
+  Result := FCharCount;
+end;
+
+function TBCLeaLCDDisplay.GetGlobalDotColsCount: longint;
+begin
+  Prepare();
+  Result := FGlobalDotColsCount;
+end;
+
+function TBCLeaLCDDisplay.GetDotColCount: integer;
+begin
+  Result := FCharDefs.ColCount;
+end;
+
+function TBCLeaLCDDisplay.GetDotRowCount: integer;
+begin
+  Result := FCharDefs.RowCount;
+end;
+
+procedure TBCLeaLCDDisplay.SetDotColCount(AValue: integer);
+begin
+  if AValue = DotColCount then
+    exit;
+  FCharDefs.ColCount := AValue;
+  UpdateSize;
+end;
+
+procedure TBCLeaLCDDisplay.SetDotRowCount(AValue: integer);
+begin
+  if AValue = DotRowCount then
+    exit;
+  FCharDefs.RowCount := AValue;
+  UpdateSize;
+end;
+
+procedure TBCLeaLCDDisplay.LinesChanged(Sender: TObject);
+begin
+  UpdateSize;
+  DoChange;
+end;
+
+procedure TBCLeaLCDDisplay.UpdateSize;
+begin
+  if AutoSize then
+  begin
+    InvalidatePreferredSize;
+    AdjustSize;
+  end;
+  Invalidate;
+end;
+
+procedure TBCLeaLCDDisplay.SetTheme(AValue: TBCLeaTheme);
+begin
+  if FTheme = AValue then
+    Exit;
+  if Assigned(FTheme) then
+    FTheme := nil;
+  FTheme := AValue;
+  ApplyTheme;
+end;
+
+procedure TBCLeaLCDDisplay.UpdateTheme;
+begin
+  if Assigned(FTheme) then
+  begin
+    FTheme.LCD_FrameColor := FFrameColor;
+    FTheme.LCD_BoardColor := FBoardColor;
+    FTheme.LCD_DotColorOn := FDotColorOn;
+    FTheme.LCD_DotShape := FDotShape;
+    FTheme.LCD_DotSize := FDotSize;
+    FTheme.LCD_DotsSpace := FDotsSpace;
+    FTheme.LCD_DotBlend := FDotBlend;
+    FTheme.LCD_DotBlendOperation := FDotBlendOperation;
+    FTheme.LCD_DotBlur := FDotBlur;
+    FTheme.LCD_DotBlurRadius := FDotBlurRadius;
+    FTheme.LCD_FrameStyle := FrameStyle;
+    FTheme.LCD_FrameHeight := FFrameHeight;
+    FTheme.LCD_FrameAltitude := FFrameAltitude;
+    FTheme.LCD_FrameSize := FFrameSize;
+    FTheme.LCD_BoardShadow := FBoardShadow;
+  end;
+end;
+
+procedure TBCLeaLCDDisplay.ApplyTheme;
+begin
+  if Assigned(FTheme) then
+  begin
+    FFrameColor := FTheme.LCD_FrameColor;
+    FBoardColor := FTheme.LCD_BoardColor;
+    FDotColorOn := FTheme.LCD_DotColorOn;
+    FDotShape := FTheme.LCD_DotShape;
+    FDotSize := FTheme.LCD_DotSize;
+    FDotsSpace := FTheme.LCD_DotsSpace;
+    FDotBlend := FTheme.LCD_DotBlend;
+    FDotBlendOperation := FTheme.LCD_DotBlendOperation;
+    FDotBlur := FTheme.LCD_DotBlur;
+    FDotBlurRadius := FTheme.LCD_DotBlurRadius;
+    FFrameStyle := FTheme.LCD_FrameStyle;
+    FFrameHeight := FTheme.LCD_FrameHeight;
+    FFrameAltitude := FTheme.LCD_FrameAltitude;
+    FFrameSize := FTheme.LCD_FrameSize;
+    FBoardShadow := FTheme.LCD_BoardShadow;
+    FLightSourceIntensity := FTheme.COM_LightSourceIntensity;
+    FLightSourceDistanceTerm := FTheme.COM_LightSourceDistanceTerm;
+    FLightSourceDistanceFactor := FTheme.COM_LightSourceDistanceFactor;
+    FLightDestFactor := FTheme.COM_LightDestFactor;
+    FLightColor := FTheme.COM_LightColor;
+    FSpecularFactor := FTheme.COM_SpecularFactor;
+    FSpecularIndex := FTheme.COM_SpecularIndex;
+    FAmbientFactor := FTheme.COM_AmbientFactor;
+    FDiffusionFactor := FTheme.COM_DiffusionFactor;
+    FNegativeDiffusionFactor := FTheme.COM_NegativeDiffusionFactor;
+    FDiffuseSaturation := FTheme.COM_DiffuseSaturation;
+    FLightPositionX := FTheme.COM_LightPositionX;
+    FLightPositionY := FTheme.COM_LightPositionY;
+    FLightPositionZ := FTheme.COM_LightPositionZ;
+    UpdateSize;
+    Invalidate;
+  end
+  else
+  begin
+    ApplyDefaultTheme;
+  end;
+end;
+
+procedure TBCLeaLCDDisplay.SaveThemeToFile(AFileName: string);
+begin
+  if Assigned(FTheme) then
+    FTheme.SaveThemeToFile(AFileName);
+end;
+
+procedure TBCLeaLCDDisplay.LoadThemeFromFile(AFileName: string);
+begin
+  if Assigned(FTheme) then
+    FTheme.LoadThemeFromFile(AFileName);
+end;
+
+procedure TBCLeaLCDDisplay.ApplyDefaultTheme;
+begin
+  FDotSize := 4;
+  FDotsSpace := 1;
+  FDotShape := stRound;
+  FDotBlend := False;
+  FDotBlendOperation := boGlow;
+  FDotBlur := False;
+  FDotBlurRadius := 0.8;
+  FFrameSize := 8;
+  FFrameHeight := 8;
+  FFrameAltitude := 2;
+  FFrameStyle := zsRaised;
+  FBoardShadow := bsFrame;
+  FFrameColor := clBtnFace;
+  FBoardColor := clBlack;
+  FDotColorOn := clSkyBlue;
+  FAmbientFactor := 0.3;
+  FSpecularIndex := 10;
+  FSpecularFactor := 0.6;
+  FLightDestFactor := 1;
+  FLightPositionX := -100;
+  FLightPositionY := -100;
+  FLightPositionZ := 100;
+  FLightSourceIntensity := 500;
+  FLightSourceDistanceTerm := 150;
+  FLightSourceDistanceFactor := 1;
+  FNegativeDiffusionFactor := 0.1;
+  FLightColor := clWhite;
+  FDiffuseSaturation := False;
+  FDiffusionFactor := 0.9;
+end;
+
+end.

+ 211 - 0
bclealcddisplay_editor.pas

@@ -0,0 +1,211 @@
+unit BCLeaLCDDisplay_Editor;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, PropEdits, ComponentEditors,
+  BCLeaLCDDisplay;
+
+type
+  TBCLeaLCDDisplayCharDefsPropertyEditor = class(TPersistentPropertyEditor)
+  public
+    procedure Edit; override;
+    procedure ExecuteVerb(Index: integer); override;
+    function GetAttributes: TPropertyAttributes; override;
+    function GetVerb(Index: integer): string; override;
+    function GetVerbCount: integer; override;
+    function BCLeaLCDDisplay: TBCLeaLCDDisplay;
+  end;
+
+  TBCLeaLCDDisplayComponentEditor = class(TComponentEditor)
+  private
+    procedure EditLines;
+  public
+    procedure Edit; override;
+    procedure ExecuteVerb(Index: integer); override;
+    function GetVerb(Index: integer): string; override;
+    function GetVerbCount: integer; override;
+    function BCLeaLCDDisplay: TBCLeaLCDDisplay;
+  end;
+
+procedure EditCharDefs(ABCLeaLCDDisplay: TBCLeaLCDDisplay);
+
+implementation
+
+uses
+  Controls, StdCtrls, Dialogs, ButtonPanel, Forms,
+  BCLeaLCDDisplay_EditorForm;
+
+{ Opens the char def editor. }
+procedure EditCharDefs(ABCLeaLCDDisplay: TBCLeaLCDDisplay);
+var
+  F: TBCLeaLCDCharDefsEditor;
+begin
+  F := TBCLeaLCDCharDefsEditor.Create(nil);
+  try
+    F.Position := poScreenCenter;
+    F.BCLeaLCDDisplay := TBCLeaLCDDisplay(ABCLeaLCDDisplay);
+    F.ShowModal;  // Cancel has been handled by the editor form.
+  finally
+    F.Free;
+  end;
+end;
+
+{ Loads the char defs of the specified BCLeaLCDDisplay from an xml file. }
+procedure LoadCharDefsFromFile(ABCLeaLCDDisplay: TBCLeaLCDDisplay);
+var
+  dlg: TOpenDialog;
+begin
+  dlg := TOpenDialog.Create(nil);
+  try
+    dlg.FileName := '';
+    dlg.Filter := 'XML files (*.xml)|*.xml';
+    if dlg.Execute then
+    begin
+      ABCLeaLCDDisplay.CharDefs.LoadFromFile(dlg.FileName);
+      ABCLeaLCDDisplay.Invalidate;
+    end;
+  finally
+    dlg.Free;
+  end;
+end;
+
+{ Saves the chardefs of the specified BCLeaLCDDisplay to an xml file. }
+procedure SaveCharDefsToFile(ABCLeaLCDDisplay: TBCLeaLCDDisplay);
+var
+  dlg: TOpenDialog;
+begin
+  dlg := TSaveDialog.Create(nil);
+  try
+    dlg.FileName := '';
+    dlg.Filter := 'XML files (*.xml)|*.xml';
+    if dlg.Execute then
+      ABCLeaLCDDisplay.CharDefs.SaveToFile(dlg.FileName);
+  finally
+    dlg.Free;
+  end;
+end;
+
+
+{ TBCLeaLCDDisplayCharDefsPropertyEditor }
+
+{ Opens the chardefs editor. }
+procedure TBCLeaLCDDisplayCharDefsPropertyEditor.Edit;
+begin
+  EditCharDefs(BCLeaLCDDisplay);
+end;
+
+{ Executes the routines assigned to the CharDefs context menu }
+procedure TBCLeaLCDDisplayCharDefsPropertyEditor.ExecuteVerb(Index: integer);
+begin
+  case Index of
+    0: Edit;
+    1: LoadCharDefsFromFile(BCLeaLCDDisplay);
+    2: SaveCharDefsToFile(BCLeaLCDDisplay);
+  end;
+end;
+
+{ The property editor should open the CharDefs editor. }
+function TBCLeaLCDDisplayCharDefsPropertyEditor.GetAttributes: TPropertyAttributes;
+begin
+  Result := inherited GetAttributes + [paDialog];
+end;
+
+{ Determines how many items will be added to the CharDefs context menu. }
+function TBCLeaLCDDisplayCharDefsPropertyEditor.GetVerbCount: integer;
+begin
+  Result := 3;
+end;
+
+{ Determines the menu item text for CharDefs context menu. }
+function TBCLeaLCDDisplayCharDefsPropertyEditor.GetVerb(Index: integer): string;
+begin
+  case Index of
+    0: Result := 'Edit...';
+    1: Result := 'Load from file...';
+    2: Result := 'Save to file...';
+  end;
+end;
+
+function TBCLeaLCDDisplayCharDefsPropertyEditor.BCLeaLCDDisplay: TBCLeaLCDDisplay;
+begin
+  Result := TBCLeaLCDDisplay(GetComponent(0));
+end;
+
+
+{ TBCLeaLCDDisplayComponentEditor }
+
+procedure TBCLeaLCDDisplayComponentEditor.Edit;
+begin
+  ExecuteVerb(0);
+end;
+
+procedure TBCLeaLCDDisplayComponentEditor.EditLines;
+var
+  F: TForm;
+  Memo: TMemo;
+begin
+  F := TForm.CreateNew(nil);
+  try
+    F.Caption := 'Edit BCLeaLCDDisplay text';
+    F.Position := poScreenCenter;
+    F.Width := 300;
+    F.Height := 200;
+    Memo := TMemo.Create(F);
+    with Memo do
+    begin
+      Align := alClient;
+      BorderSpacing.Around := 8;
+      Parent := F;
+      Lines.Assign(BCLeaLCDDisplay.Lines);
+    end;
+    with TButtonPanel.Create(F) do
+    begin
+      ShowButtons := [pbOK, pbCancel];
+      Parent := F;
+    end;
+    if F.ShowModal = mrOk then
+    begin
+      BCLeaLCDDisplay.Lines.Assign(Memo.Lines);
+      BCLeaLCDDisplay.Invalidate;
+    end;
+  finally
+    F.Free;
+  end;
+end;
+
+procedure TBCLeaLCDDisplayComponentEditor.ExecuteVerb(Index: integer);
+begin
+  case Index of
+    0: EditLines;
+    1: EditCharDefs(BCLeaLCDDisplay);
+    2: LoadCharDefsFromFile(BCLeaLCDDisplay);
+    3: SaveCharDefsToFile(BCLeaLCDDisplay);
+  end;
+end;
+
+{ Determines how many items will be added to the BCLeaLCDDisplay context menu. }
+function TBCLeaLCDDisplayComponentEditor.GetVerbCount: integer;
+begin
+  Result := 4;
+end;
+
+{ Determines the menu item text for BCLeaLCDDisplay context menu. }
+function TBCLeaLCDDisplayComponentEditor.GetVerb(Index: integer): string;
+begin
+  case Index of
+    0: Result := 'Lines text...';
+    1: Result := 'Edit character defs...';
+    2: Result := 'Load character defs from file...';
+    3: Result := 'Save character defs to file...';
+  end;
+end;
+
+function TBCLeaLCDDisplayComponentEditor.BCLeaLCDDisplay: TBCLeaLCDDisplay;
+begin
+  Result := TBCLeaLCDDisplay(GetComponent);
+end;
+
+end.

+ 223 - 0
bclealcddisplay_editorform.lfm

@@ -0,0 +1,223 @@
+object BCLeaLCDCharDefsEditor: TBCLeaLCDCharDefsEditor
+  Left = 899
+  Height = 276
+  Top = 168
+  Width = 273
+  AutoSize = True
+  BorderStyle = bsDialog
+  Caption = 'LCD Dot Matrix Editor'
+  ClientHeight = 276
+  ClientWidth = 273
+  OnActivate = FormActivate
+  OnCloseQuery = FormCloseQuery
+  OnDestroy = FormDestroy
+  LCLVersion = '3.4.0.0'
+  object Label1: TLabel
+    AnchorSideLeft.Control = Owner
+    AnchorSideTop.Control = Owner
+    Left = 12
+    Height = 15
+    Top = 12
+    Width = 105
+    BorderSpacing.Left = 12
+    BorderSpacing.Top = 12
+    Caption = 'Available characters'
+    ParentColor = False
+  end
+  object cbCharSelector: TComboBox
+    AnchorSideLeft.Control = Label1
+    AnchorSideTop.Control = Label1
+    AnchorSideTop.Side = asrBottom
+    AnchorSideRight.Control = dgDotMatrix
+    AnchorSideRight.Side = asrBottom
+    Left = 12
+    Height = 23
+    Top = 29
+    Width = 159
+    Anchors = [akTop, akLeft, akRight]
+    AutoComplete = True
+    AutoCompleteText = [cbactEnabled, cbactEndOfLineComplete, cbactSearchCaseSensitive, cbactSearchAscending]
+    BorderSpacing.Top = 2
+    ItemHeight = 15
+    MaxLength = 1
+    TabOrder = 0
+    Text = 'cbCharSelector'
+    OnChange = cbCharSelectorChange
+  end
+  object pnOKCancel: TPanel
+    AnchorSideLeft.Control = Owner
+    AnchorSideTop.Control = dgDotMatrix
+    AnchorSideTop.Side = asrBottom
+    AnchorSideRight.Control = Owner
+    AnchorSideRight.Side = asrBottom
+    Left = 12
+    Height = 26
+    Top = 212
+    Width = 249
+    Anchors = [akTop, akLeft, akRight]
+    AutoSize = True
+    BorderSpacing.Left = 12
+    BorderSpacing.Top = 10
+    BorderSpacing.Right = 12
+    BorderSpacing.Bottom = 12
+    BevelOuter = bvNone
+    ClientHeight = 26
+    ClientWidth = 249
+    TabOrder = 1
+    object btOK: TBitBtn
+      AnchorSideLeft.Control = pnOKCancel
+      AnchorSideTop.Control = pnOKCancel
+      AnchorSideTop.Side = asrCenter
+      Left = 0
+      Height = 26
+      Top = 0
+      Width = 62
+      AutoSize = True
+      Default = True
+      DefaultCaption = True
+      Kind = bkOK
+      ModalResult = 1
+      TabOrder = 0
+    end
+    object btCancel: TBitBtn
+      AnchorSideTop.Control = pnOKCancel
+      AnchorSideTop.Side = asrCenter
+      AnchorSideRight.Control = pnOKCancel
+      AnchorSideRight.Side = asrBottom
+      Left = 167
+      Height = 26
+      Top = 0
+      Width = 82
+      Anchors = [akTop, akRight]
+      AutoSize = True
+      Cancel = True
+      DefaultCaption = True
+      Kind = bkCancel
+      ModalResult = 2
+      TabOrder = 1
+    end
+  end
+  object pnButtons: TPanel
+    AnchorSideLeft.Control = dgDotMatrix
+    AnchorSideLeft.Side = asrBottom
+    AnchorSideTop.Control = dgDotMatrix
+    Left = 176
+    Height = 88
+    Top = 57
+    Width = 89
+    AutoSize = True
+    BorderSpacing.Left = 5
+    BorderSpacing.Right = 12
+    BevelOuter = bvNone
+    ClientHeight = 88
+    ClientWidth = 89
+    TabOrder = 2
+    object btReplace: TBitBtn
+      AnchorSideLeft.Control = pnButtons
+      AnchorSideTop.Control = btAdd
+      AnchorSideTop.Side = asrBottom
+      Left = 0
+      Height = 26
+      Top = 31
+      Width = 89
+      AutoSize = True
+      BorderSpacing.Top = 5
+      Caption = 'Replace'
+      Margin = 6
+      Images = ImageList1
+      ImageIndex = 1
+      OnClick = btReplaceClick
+      Spacing = 6
+      TabOrder = 0
+    end
+    object btDelete: TBitBtn
+      AnchorSideLeft.Control = pnButtons
+      AnchorSideTop.Control = btReplace
+      AnchorSideTop.Side = asrBottom
+      AnchorSideRight.Control = btReplace
+      AnchorSideRight.Side = asrBottom
+      Left = 0
+      Height = 26
+      Top = 62
+      Width = 89
+      Anchors = [akTop, akLeft, akRight]
+      AutoSize = True
+      BorderSpacing.Top = 5
+      Caption = 'Delete'
+      Margin = 6
+      Images = ImageList1
+      ImageIndex = 3
+      OnClick = btDeleteClick
+      Spacing = 6
+      TabOrder = 1
+    end
+    object btAdd: TBitBtn
+      AnchorSideLeft.Control = pnButtons
+      AnchorSideTop.Control = pnButtons
+      AnchorSideRight.Control = btReplace
+      AnchorSideRight.Side = asrBottom
+      Left = 0
+      Height = 26
+      Top = 0
+      Width = 89
+      Anchors = [akTop, akLeft, akRight]
+      AutoSize = True
+      Caption = 'Add as...'
+      Margin = 6
+      Images = ImageList1
+      ImageIndex = 2
+      OnClick = btAddClick
+      Spacing = 6
+      TabOrder = 2
+    end
+  end
+  object dgDotMatrix: TDrawGrid
+    AnchorSideLeft.Control = Label1
+    AnchorSideTop.Control = cbCharSelector
+    AnchorSideTop.Side = asrBottom
+    Left = 12
+    Height = 145
+    Top = 57
+    Width = 159
+    BorderSpacing.Top = 5
+    BorderStyle = bsNone
+    DefaultColWidth = 22
+    ExtendedSelect = False
+    FixedCols = 0
+    FixedRows = 0
+    ScrollBars = ssNone
+    TabOrder = 3
+    OnKeyDown = dgDotMatrixKeyDown
+    OnMouseDown = dgDotMatrixMouseDown
+    OnMouseMove = dgDotMatrixMouseMove
+    OnPrepareCanvas = dgDotMatrixPrepareCanvas
+  end
+  object ImageList1: TImageList
+    Left = 208
+    Top = 8
+    Bitmap = {
+      4C7A040000001000000010000000990200000000000078DAED934B6F524114C7
+      4984B65C5EE5B6B5696929D0C2454A2BB8D6785DFAEAD20FE0CA0FE0A2E5D54B
+      91BA706781F2EA23AE75E34A3F84317E89C6C4B0D0C45445FD7BE6DE4B432D8F
+      3BC5184C9CE49F4C66E637FF3367CE319986778CF8EDF288CF2E9F979DCE5FC1
+      C55C1C16CE3B2C8CDD26361FC3542E86C9EC6558166C321F1BC7D4A31826B656
+      212A2B10335198FBDC31D262B7E398646C6E15EEEC0AC633CB70A52370A52230
+      7B05B9E77B996FBE8DDD5C86337D098E64188E840467228C0B5DEE680DE1C6B4
+      226E11AB68AC3D29C1726D42319A3F2BF1EE6C14AE4C04F69404211182F9AA68
+      9C9789DF8CAADE36F2B66E04F979CA9933453C795BD797B878E13AF1698A3F49
+      6FA79C09EB416E5E247E3C19A19C8761DB08C1C2C1FF1FFA3F5A2599E93CAC20
+      48B224ED2314DA83D51A92F97CC3C41E12BB8F60B04EAA1ABE43105AEC0171FB
+      585CAC2110A8C0EF2F636C2C281B630F75B64E6C153E5F190B0B2552B1EB1DDA
+      7B0FC0C4D8A5A53D62EBC456E0F5EE627EBE482AA81A1DED1D8728AE291A5B55
+      D9B9B9221C8E5B86EBD7ED5E53FCFE2AC55B26BF123C9E02F13739F8BBC4574E
+      BC67677760B7F3F07714966FAFB7447C0133334FB9F9406097F8A2CAF3FA8BE2
+      6DE24B943F2DE71ECF0ED7FBFFE6003064FA4E3A363D4BDFC7EB7246159BB335
+      6DAF1FDF247D3231EEFD9B57AAD89CAD01DFF4333FBBF832F633A9D181FFA0EF
+      7DED12C7B149F360E78E3AF047FADE47FDEC69BEFDBD4CEF5ED64E78366FDFD3
+      F2719A6FF7EB272D9E3FCB0F1A3FF045CF5FA347FE1AFA99E301FEAFD9A78E7A
+      D54F73E0FAFD3174FD369CFD5F7B78CFF4E2F103556CCEDBFF8C7BFBFC892A36
+      E7EDFFB33C5FFF9FE5F9FABF97FE85FEE78DFFF7FEEF9C3FE3FDDFFDFF8CF57F
+      E7FA690E5CBFC3D6FFBF005C61B822
+    }
+  end
+end

+ 370 - 0
bclealcddisplay_editorform.pas

@@ -0,0 +1,370 @@
+unit BCLeaLCDDisplay_EditorForm;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  LCLIntf, Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls,
+  Grids, ExtCtrls, Buttons, BCLeaLCDDisplay;
+
+type
+
+  { TBCLeaLCDCharDefsEditor }
+
+  TBCLeaLCDCharDefsEditor = class(TForm)
+    btAdd: TBitBtn;
+    btReplace: TBitBtn;
+    btDelete: TBitBtn;
+    btOK: TBitBtn;
+    btCancel: TBitBtn;
+    cbCharSelector: TComboBox;
+    dgDotMatrix: TDrawGrid;
+    ImageList1: TImageList;
+    Label1: TLabel;
+    pnButtons: TPanel;
+    pnOKCancel: TPanel;
+    procedure btAddClick(Sender: TObject);
+    procedure btDeleteClick(Sender: TObject);
+    procedure btReplaceClick(Sender: TObject);
+    procedure cbCharSelectorChange(Sender: TObject);
+    procedure dgDotMatrixKeyDown(Sender: TObject; var Key: word;
+    {%H-}Shift: TShiftState);
+    procedure dgDotMatrixMouseDown(Sender: TObject; {%H-}Button: TMouseButton;
+    {%H-}Shift: TShiftState; X, Y: integer);
+    procedure dgDotMatrixMouseMove(Sender: TObject; Shift: TShiftState; X, Y: integer);
+    procedure dgDotMatrixPrepareCanvas({%H-}Sender: TObject; aCol, aRow: integer;
+    {%H-}aState: TGridDrawState);
+    procedure FormActivate(Sender: TObject);
+    procedure FormCloseQuery(Sender: TObject; var CanClose: boolean);
+    procedure FormDestroy(Sender: TObject);
+  private
+    FBCLeaLCDDisplay: TBCLeaLCDDisplay;
+    FModified: boolean;
+    FSavedCharDefs: TBCLeaCharDefs;
+    FSelectedChar: string;
+    FTmpDotRows: TDotRows;
+    FOldRow, FOldCol: integer;
+    procedure SetBCLeaLCDDisplay(AValue: TBCLeaLCDDisplay);
+    procedure PopulateCharSelector;
+    procedure SaveCharDefs;
+    procedure ClearEditorGrid;
+    procedure SetupEditorGrid;
+    function GetDotMatrix: TDotRows;
+
+    function DotSet(ACol, ARow: integer): boolean;
+    procedure SetDot(ACol, ARow: integer; AValue: boolean);
+    procedure ToggleDot(ACol, ARow: integer);
+  public
+    property BCLeaLCDDisplay: TBCLeaLCDDisplay read FBCLeaLCDDisplay write SetBCLeaLCDDisplay;
+
+  end;
+
+var
+  BCLeaLCDCharDefsEditor: TBCLeaLCDCharDefsEditor;
+
+implementation
+
+{$R *.lfm}
+
+uses
+  Math, ButtonPanel;
+
+function CharInputBox(const ACaption, APrompt, ADefault: string): string;
+var
+  F: TForm;
+  ed: TEdit;
+  lbl: TLabel;
+  bp: TButtonPanel;
+begin
+  F := TForm.CreateNew(nil);
+  try
+    F.Caption := ACaption;
+    F.BorderStyle := bsDialog;
+    lbl := TLabel.Create(F);
+    lbl.AnchorSideTop.Control := F;
+    lbl.AnchorSideLeft.Control := F;
+    lbl.BorderSpacing.Top := F.Scale96ToFont(12);
+    lbl.BorderSpacing.Bottom := F.Scale96ToFont(2);
+    lbl.BorderSpacing.Left := F.Scale96ToFont(12);
+    lbl.BorderSpacing.Right := F.Scale96ToFont(12);
+    lbl.WordWrap := True;
+    lbl.AutoSize := True;
+    lbl.Caption := APrompt;
+    lbl.Parent := F;
+    lbl.AdjustSize;
+    ed := TEdit.Create(F);
+    ed.AnchorSideTop.Control := lbl;
+    ed.AnchorSideTop.Side := asrBottom;
+    ed.AnchorSideLeft.Control := F;
+    ed.AnchorSideRight.Control := F;
+    ed.AnchorSideRight.Side := asrRight;
+    ed.Anchors := [akLeft, akTop, akRight];
+    ed.BorderSpacing.Left := F.Scale96ToFont(12);
+    ed.BorderSpacing.Right := F.Scale96ToFont(12);
+    ed.BorderSpacing.Bottom := F.Scale96ToFont(18);
+    ed.MaxLength := 1;
+    ed.Text := ADefault;
+    ed.Parent := F;
+    ed.AdjustSize;
+    bp := TButtonPanel.Create(F);
+    bp.ShowButtons := [pbOK, pbCancel];
+    bp.Parent := F;
+    bp.AdjustSize;
+    F.Constraints.MinHeight := ed.Top + ed.Height + ed.BorderSpacing.Bottom + bp.Height + 2 * bp.BorderSpacing.Around;
+    F.AutoSize := True;
+    F.Position := poScreenCenter;
+    if F.ShowModal = mrOk then
+      Result := ed.Text
+    else
+      Result := ADefault;
+  finally
+    F.Free;
+  end;
+end;
+
+procedure TBCLeaLCDCharDefsEditor.PopulateCharSelector;
+var
+  i: integer;
+begin
+  cbCharSelector.DropdownCount := 24;
+  cbCharSelector.Items.BeginUpdate;
+  try
+    cbCharSelector.Clear;
+    for i := 0 to FBCLeaLCDDisplay.CharDefs.Count - 1 do
+      cbCharSelector.Items.Add(FBCLeaLCDDisplay.CharDefs.CharByIndex[i]);
+  finally
+    cbCharSelector.Items.EndUpdate;
+  end;
+end;
+
+procedure TBCLeaLCDCharDefsEditor.btDeleteClick(Sender: TObject);
+begin
+  if FSelectedChar <> '' then
+  begin
+    FBCLeaLCDDisplay.CharDefs.Delete(FSelectedChar);
+    FBCLeaLCDDisplay.Invalidate;
+  end;
+  PopulateCharSelector;
+end;
+
+procedure TBCLeaLCDCharDefsEditor.btAddClick(Sender: TObject);
+var
+  newChar: string;
+begin
+  newChar := CharInputBox('Dot matrix for...', 'Character', '');
+  if newChar = '' then
+    exit;
+
+  // Check whether the new character already has a dot matrix.
+  if FBCLeaLCDDisplay.CharDefs.Find(newChar) then
+  begin
+    MessageDlg(Format('Character "%s" already exists and cannot be added.', [newChar]),
+      mtError, [mbOK], 0);
+    exit;
+  end;
+
+  // Add new character and its dot matrix to the BCLeaLCDDisplay...
+  FSelectedChar := newChar;
+  FBCLeaLCDDisplay.CharDefs.Add(FSelectedChar, GetDotMatrix);
+  FBCLeaLCDDisplay.Invalidate;
+  // ... and update the editor form
+  PopulateCharSelector;
+  cbCharSelector.ItemIndex := cbCharSelector.Items.IndexOf(FSelectedChar);
+  FModified := False;
+end;
+
+{ Replaces the dotmatrix of the currently loaded character by the dotmatrix in
+  the editor. }
+procedure TBCLeaLCDCharDefsEditor.btReplaceClick(Sender: TObject);
+begin
+  if FSelectedChar <> '' then
+  begin
+    FBCLeaLCDDisplay.CharDefs.DotRows[FSelectedChar] := GetDotMatrix;
+    FBCLeaLCDDisplay.Invalidate;
+    FModified := False;
+  end;
+end;
+
+procedure TBCLeaLCDCharDefsEditor.cbCharSelectorChange(Sender: TObject);
+begin
+  FSelectedChar := cbCharSelector.Text;
+  if FSelectedChar <> '' then
+    FTmpDotRows := FBCLeaLCDDisplay.CharDefs.DotRows[FSelectedChar]
+  else
+    ClearEditorGrid;
+  dgDotMatrix.Invalidate;
+  FModified := False;
+end;
+
+procedure TBCLeaLCDCharDefsEditor.dgDotMatrixKeyDown(Sender: TObject; var Key: word; Shift: TShiftState);
+var
+  r, c: integer;
+begin
+  r := dgDotMatrix.Row;
+  c := dgDotMatrix.Col;
+  if Key = 32 then
+  begin
+    ToggleDot(c, r);
+    dgDotMatrix.InvalidateCell(c, r);
+    FModified := True;
+  end;
+end;
+
+procedure TBCLeaLCDCharDefsEditor.dgDotMatrixMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+var
+  r, c: integer;
+begin
+  dgDotMatrix.MouseToCell(X, Y, c, r);
+  ToggleDot(c, r);
+  dgDotMatrix.InvalidateCell(c, r);
+  FOldRow := r;
+  FOldCol := c;
+  FModified := True;
+end;
+
+procedure TBCLeaLCDCharDefsEditor.dgDotMatrixMouseMove(Sender: TObject; Shift: TShiftState; X, Y: integer);
+var
+  r, c: integer;
+begin
+  if Shift = [ssLeft] then
+  begin
+    dgDotMatrix.MouseToCell(X, Y, c, r);
+    if (c <> FOldCol) or (r <> FOldRow) then
+    begin
+      ToggleDot(c, r);
+      dgDotMatrix.InvalidateCell(c, r);
+      FOldRow := r;
+      FOldCol := c;
+      FModified := True;
+    end;
+  end;
+end;
+
+procedure TBCLeaLCDCharDefsEditor.dgDotMatrixPrepareCanvas(Sender: TObject; aCol, aRow: integer; aState: TGridDrawState);
+begin
+  if DotSet(ACol, ARow) then
+    dgDotMatrix.Canvas.Brush.Color := clBlack
+  else
+    dgDotMatrix.Canvas.Brush.Color := clWhite;
+end;
+
+procedure TBCLeaLCDCharDefsEditor.FormActivate(Sender: TObject);
+var
+  w: integer;
+begin
+  w := Max(btOK.Width, btCancel.Width);
+  btOK.Constraints.MinWidth := w;
+  btCancel.Constraints.MinWidth := w;
+end;
+
+procedure TBCLeaLCDCharDefsEditor.FormCloseQuery(Sender: TObject; var CanClose: boolean);
+const
+  mrReplace = -20;
+  mrAddAs = -21;
+var
+  res: integer;
+begin
+  if FModified and (ModalResult = mrOk) then
+  begin
+    res := QuestionDlg('Confirmation', 'Current dotmatrix of "' + FSelectedChar + '" has not yet been applied. What do you want to do?',
+      mtConfirmation, [mrReplace, 'Replace', mrAddAs, 'Add as...', 'isDefault', mrCancel, 'Cancel'], 0);
+    case res of
+      mrReplace:
+        btReplaceClick(nil);
+      mrAddAs:
+        btAddClick(nil);
+      mrCancel:
+        ;
+    end;
+    CanClose := (res <> mrCancel) and (not FModified);
+  end;
+
+  if CanClose and (ModalResult <> mrOk) then
+  begin
+    FBCLeaLCDDisplay.CharDefs.Assign(FSavedCharDefs);
+    FBCLeaLCDDisplay.Invalidate;
+  end;
+end;
+
+procedure TBCLeaLCDCharDefsEditor.FormDestroy(Sender: TObject);
+begin
+  FreeAndNil(FSavedCharDefs);
+end;
+
+function TBCLeaLCDCharDefsEditor.GetDotMatrix: TDotRows;
+begin
+  Result := FTmpDotRows;
+end;
+
+{ Tests whether the dot corresponding to the specified grid column and row is
+  set. Note that the low-bit is at the right! }
+function TBCLeaLCDCharDefsEditor.DotSet(ACol, ARow: integer): boolean;
+var
+  c: integer;
+begin
+  c := dgDotMatrix.ColCount - 1 - ACol;
+  Result := FTmpDotRows[ARow] and (1 shl c) <> 0;  // avoid integer helper to keep usability with old fpc versions
+end;
+
+{ Sets the dot in the specified grid column and row if AValue is true, 
+  or clears it if AValue is false. 
+  Note that the low-bit is at the right of the grid! }
+procedure TBCLeaLCDCharDefsEditor.SetDot(ACol, ARow: integer; AValue: boolean);
+var
+  c: integer;
+  lDotRows: TDotRows;
+begin
+  c := dgDotMatrix.ColCount - 1 - ACol;
+  lDotRows := CopyDotRows(FTmpDotRows);
+  if AValue then
+    lDotRows[ARow] := lDotRows[ARow] or (1 shl c)
+  else
+    lDotRows[ARow] := lDotRows[ARow] and not (1 shl c);  // avoid integer helper to keep usability with old fpc version
+  FTmpDotRows := CopyDotRows(lDotRows);
+end;
+
+{ Toggles the dot in the specified grid column/row }
+procedure TBCLeaLCDCharDefsEditor.ToggleDot(ACol, ARow: integer);
+begin
+  SetDot(ACol, ARow, not DotSet(ACol, ARow));
+end;
+
+{ Save the char defs so that they can be restored if the form is not closed by OK. }
+procedure TBCLeaLCDCharDefsEditor.SaveCharDefs;
+begin
+  FSavedCharDefs.Free;
+  FSavedCharDefs := TBCLeaCharDefs.Create(nil);
+  FSavedCharDefs.Assign(FBCLeaLCDDisplay.CharDefs);
+end;
+
+procedure TBCLeaLCDCharDefsEditor.SetBCLeaLCDDisplay(AValue: TBCLeaLCDDisplay);
+begin
+  FBCLeaLCDDisplay := AValue;
+  SetLength(FTmpDotRows, FBCLeaLCDDisplay.DotRowCount);
+  SaveCharDefs;
+  PopulateCharSelector;
+  SetupEditorGrid;
+end;
+
+procedure TBCLeaLCDCharDefsEditor.ClearEditorGrid;
+var
+  i: integer;
+begin
+  for i := 0 to High(FTmpDotRows) do
+    FTmpDotRows[i] := 0;
+end;
+
+{ Reads the size of the dot matrix from FBCLeaLCDDisplay and use it to define the
+  number of rows and columns in the editor grid. }
+procedure TBCLeaLCDCharDefsEditor.SetupEditorGrid;
+begin
+  dgDotMatrix.RowCount := FBCLeaLCDDisplay.DotRowCount;
+  ClearEditorGrid;
+  dgDotmatrix.ClientWidth := dgDotMatrix.ColCount * dgDotMatrix.DefaultColWidth;
+  dgDotMatrix.ClientHeight := dgDotMatrix.RowCount * dgDotMatrix.DefaultRowHeight;
+  dgDotMatrix.Constraints.MinWidth := dgDotMatrix.Width;
+  dgDotMatrix.Constraints.MinHeight := dgDotMatrix.Height;
+end;
+
+end.

+ 27 - 0
bclealcddisplay_editorregister.pas

@@ -0,0 +1,27 @@
+
+{**********************************************************************
+ Register the BCLeaLCDDisplay editor
+***********************************************************************}
+
+unit BCLeaLCDDisplay_EditorRegister;
+
+interface
+
+uses
+  Classes, LResources, BCLeaLCDDisplay, BCLeaLCDDisplay_Editor;
+
+procedure Register;
+
+implementation
+
+uses
+  PropEdits, ComponentEditors;
+
+//==========================================================
+procedure Register;
+begin
+  RegisterPropertyEditor(TypeInfo(TBCLeaCharDefs), TBCLeaLCDDisplay, 'CharDefs', TBCLeaLCDDisplayCharDefsPropertyEditor);
+  RegisterComponentEditor(TBCLeaLCDDisplay, TBCLeaLCDDisplayComponentEditor);
+end;
+
+end.

+ 443 - 0
bclealed.pas

@@ -0,0 +1,443 @@
+{
+ *****************************************************************************
+  See the file COPYING.modifiedLGPL.txt, included in this distribution,
+  for details about the license.
+ *****************************************************************************
+
+ Author: Boban Spasic
+ Credits to: circular from Lazarus forum
+}
+
+unit BCLeaLED;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Controls, LResources, Graphics,
+  BGRABitmapTypes, BGRABitmap, BGRAGradients, BCLeaTheme, BCLeaTypes;
+
+type
+  TBCLeaLED = class(TCustomControl)
+  private
+    FBitmap: TBGRABitmap;
+    FTheme: TBCLeaTheme;
+    FOnChangeValue: TNotifyEvent;
+    FValue: boolean;
+    FColorOn: TColor;
+    FColorOff: TColor;
+    FBkgColor: TColor;
+    FStyle: TZStyle;
+    FSize: integer;
+    FAltitude: integer;
+    FClickable: boolean;
+    //global intensity of the light
+    FLightSourceIntensity: single;
+    //minimum distance always added (positive value)
+    FLightSourceDistanceTerm: single;
+    //how much actual distance is taken into account (usually 0 or 1)
+    FLightSourceDistanceFactor: single;
+    //how much the location of the lightened pixel is taken into account (usually 0 or 1)
+    FLightDestFactor: single;
+    //color of the light reflection
+    FLightColor: TColor;
+    //how much light is reflected (0..1)
+    FSpecularFactor: single;
+    //how concentrated reflected light is (positive value)
+    FSpecularIndex: single;
+    //ambiant lighting whereever the point is (0..1)
+    FAmbientFactor: single;
+    //diffusion, i.e. how much pixels are lightened by light source (0..1)
+    FDiffusionFactor: single;
+    //how much hidden surface are darkened (0..1)
+    FNegativeDiffusionFactor: single;
+    //when diffusion saturates, use light color to show it
+    FDiffuseSaturation: boolean;
+    FLightPositionX: integer;
+    FLightPositionY: integer;
+    FLightPositionZ: integer;
+    procedure SetValue(AValue: boolean);
+    procedure SetAltitude(AValue: integer);
+    procedure SetColorOn(AValue: TColor);
+    procedure SetColorOff(AValue: TColor);
+    procedure SetBkgColor(AValue: TColor);
+    procedure SetStyle(AValue: TZStyle);
+    procedure SetSize(AValue: integer);
+    procedure SetClickable(AValue: boolean);
+    procedure SetTheme(AValue: TBCLeaTheme);
+  protected
+    procedure SetEnabled(Value: boolean); override;
+    procedure SetVisible(Value: boolean); override;
+    procedure Paint; override;
+    procedure Redraw;
+    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
+    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
+    procedure MouseMove(Shift: TShiftState; X, Y: integer); override;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure UpdateTheme;
+    procedure ApplyTheme;
+    procedure SaveThemeToFile(AFileName: string);
+    procedure LoadThemeFromFile(AFileName: string);
+    procedure ApplyDefaultTheme;
+  published
+    property Align;
+    property Cursor;
+    property Enabled;
+    property Font;
+    property ParentColor;
+    property ParentFont;
+    property ParentShowHint;
+    property PopupMenu;
+    property ShowHint;
+    property TabOrder;
+    property TabStop default True;
+    property Anchors;
+    property Constraints;
+    property Visible;
+    property OnClick;
+    property OnDblClick;
+    property OnEnter;
+    property OnExit;
+    property OnMouseMove;
+    property OnMouseDown;
+    property OnMouseUp;
+    property OnMouseWheel;
+    property OnMouseWheelDown;
+    property OnMouseWheelUp;
+    property OnKeyDown;
+    property OnKeyUp;
+    property OnKeyPress;
+    property OnContextPopup;
+    property Value: boolean read FValue write SetValue default False;
+    property ColorOn: TColor read FColorOn write SetColorOn default TColor($00FF9C15);
+    property ColorOff: TColor read FColorOff write SetColorOff default TColor($009E5A00);
+    property BackgroundColor: TColor read FBkgColor write SetBkgColor default clBtnFace;
+    property Size: integer read FSize write SetSize default 15;
+    property OnChangeValue: TNotifyEvent read FOnChangeValue write FOnChangeValue;
+    property Style: TZStyle read FStyle write SetStyle default zsRaised;
+    property Clickable: boolean read FClickable write SetClickable default False;
+    property Theme: TBCLeaTheme read FTheme write SetTheme;
+    property Altitude: integer read FAltitude write SetAltitude default 2;
+  end;
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+  RegisterComponents('BGRA Controls', [TBCLeaLED]);
+end;
+
+constructor TBCLeaLED.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+
+  with GetControlClassDefaultSize do
+    SetInitialBounds(0, 0, 50, 50);
+  FValue := False;
+  FBitmap := TBGRABitmap.Create(Width, Height, FBkgColor);
+  FClickable := False;
+  ApplyDefaultTheme;
+end;
+
+destructor TBCLeaLED.Destroy;
+begin
+  FreeAndNil(FBitmap);
+  inherited Destroy;
+end;
+
+procedure TBCLeaLED.SetEnabled(Value: boolean);
+begin
+  inherited SetEnabled(Value);
+  Invalidate;
+end;
+
+procedure TBCLeaLED.SetVisible(Value: boolean);
+begin
+  inherited SetVisible(Value);
+  Invalidate;
+end;
+
+procedure TBCLeaLED.Paint;
+begin
+  inherited Paint;
+  Redraw;
+end;
+
+procedure TBCLeaLED.SetStyle(AValue: TZStyle);
+begin
+  if FStyle = AValue then
+    Exit;
+  FStyle := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaLED.SetValue(AValue: boolean);
+begin
+  if FValue = AValue then
+    exit;
+  FValue := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaLED.SetSize(AValue: integer);
+begin
+  if FSize = AValue then
+    exit;
+  FSize := AValue;
+  if FSize < 1 then FSize := 1;
+  Invalidate;
+end;
+
+procedure TBCLeaLED.SetColorOn(AValue: TColor);
+begin
+  if FColorOn = AValue then
+    Exit;
+  FColorOn := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaLED.SetColorOff(AValue: TColor);
+begin
+  if FColorOff = AValue then
+    Exit;
+  FColorOff := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaLED.SetBkgColor(AValue: TColor);
+begin
+  if FBkgColor = AValue then
+    Exit;
+  FBkgColor := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaLED.SetAltitude(AValue: integer);
+begin
+  if FAltitude = AValue then
+    Exit;
+  FAltitude := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaLED.SetClickable(AValue: boolean);
+begin
+  if FClickable = AValue then
+    Exit;
+  FClickable := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaLED.SetTheme(AValue: TBCLeaTheme);
+begin
+  if FTheme = AValue then
+    Exit;
+  if Assigned(FTheme) then
+    FTheme := nil;
+  FTheme := AValue;
+  ApplyTheme;
+end;
+
+procedure TBCLeaLED.UpdateTheme;
+begin
+  if Assigned(FTheme) then
+  begin
+    FTheme.LED_ColorOn := FColorOn;
+    FTheme.LED_ColorOff := FColorOff;
+    FTheme.LED_BkgColor := FBkgColor;
+    FTheme.LED_Style := FStyle;
+    FTheme.LED_Size := FSize;
+    FTheme.LED_Altitude := FAltitude;
+  end;
+end;
+
+procedure TBCLeaLED.ApplyTheme;
+begin
+  if Assigned(FTheme) then
+  begin
+    FColorOn := FTheme.LED_ColorOn;
+    FColorOff := FTheme.LED_ColorOff;
+    FBkgColor := FTheme.LED_BkgColor;
+    FStyle := FTheme.LED_Style;
+    FSize := FTheme.LED_Size;
+    FAltitude := FTHeme.LED_Altitude;
+    FLightSourceIntensity := FTheme.COM_LightSourceIntensity;
+    FLightSourceDistanceTerm := FTheme.COM_LightSourceDistanceTerm;
+    FLightSourceDistanceFactor := FTheme.COM_LightSourceDistanceFactor;
+    FLightDestFactor := FTheme.COM_LightDestFactor;
+    FLightColor := FTheme.COM_LightColor;
+    FSpecularFactor := FTheme.COM_SpecularFactor;
+    FSpecularIndex := FTheme.COM_SpecularIndex;
+    FAmbientFactor := FTheme.COM_AmbientFactor;
+    FDiffusionFactor := FTheme.COM_DiffusionFactor;
+    FNegativeDiffusionFactor := FTheme.COM_NegativeDiffusionFactor;
+    FDiffuseSaturation := FTheme.COM_DiffuseSaturation;
+    FLightPositionX := FTheme.COM_LightPositionX;
+    FLightPositionY := FTheme.COM_LightPositionY;
+    FLightPositionZ := FTheme.COM_LightPositionZ;
+    Invalidate;
+  end
+  else
+  begin
+    ApplyDefaultTheme;
+  end;
+end;
+
+procedure TBCLeaLED.SaveThemeToFile(AFileName: string);
+begin
+  if Assigned(FTheme) then
+    FTheme.SaveThemeToFile(AFileName);
+end;
+
+procedure TBCLeaLED.LoadThemeFromFile(AFileName: string);
+begin
+  if Assigned(FTheme) then
+    FTheme.LoadThemeFromFile(AFileName);
+end;
+
+procedure TBCLeaLED.ApplyDefaultTheme;
+begin
+  FColorOn := TColor($00FF9C15);
+  FColorOff := TColor($009E5A00);
+  FBkgColor := clBtnFace;
+  FStyle := zsRaised;
+  FSize := 15;
+  FAltitude := 2;
+  FAmbientFactor := 0.3;
+  FSpecularIndex := 10;
+  FSpecularFactor := 0.6;
+  FLightDestFactor := 1;
+  FLightPositionX := -100;
+  FLightPositionY := -100;
+  FLightPositionZ := 100;
+  FLightSourceIntensity := 500;
+  FLightSourceDistanceTerm := 150;
+  FLightSourceDistanceFactor := 1;
+  FNegativeDiffusionFactor := 0.1;
+  FLightColor := clWhite;
+  FDiffuseSaturation := False;
+  FDiffusionFactor := 0.9;
+end;
+
+procedure TBCLeaLED.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseDown(Button, Shift, X, Y);
+  if FClickable and (Button = mbLeft) then
+  begin
+    FValue := not FValue;
+    Redraw;
+    if Assigned(FOnChangeValue) then
+      FOnChangeValue(Self);
+  end;
+end;
+
+procedure TBCLeaLED.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseUp(Button, Shift, X, Y);
+end;
+
+procedure TBCLeaLED.MouseMove(Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseMove(Shift, X, Y);
+end;
+
+procedure TBCLeaLED.Redraw;
+var
+  EffectiveSize: integer;
+  Blur: TBGRABitmap;
+  Mask, Mask2: TBGRABitmap;
+  Phong: TPhongShading;
+  ScaledPhongSize, ScaledSize: integer;
+begin
+  FBitmap.SetSize(Width, Height);
+  FBitmap.Fill(FBkgColor);
+
+  if Width < Height then
+    EffectiveSize := Width
+  else
+    EffectiveSize := Height;
+  if EffectiveSize < 2 then exit;
+  ScaledSize := Scale96ToForm(FSize);
+  ScaledPhongSize := Scale96ToForm(5);
+
+  if Enabled then
+  begin
+    if FValue then
+      FBitmap.FillEllipseAntialias((EffectiveSize - 1) / 2, (EffectiveSize - 1) / 2, ScaledSize, ScaledSize, FColorOn)
+    else
+      FBitmap.FillEllipseAntialias((EffectiveSize - 1) / 2, (EffectiveSize - 1) / 2, ScaledSize, ScaledSize, FColorOff);
+  end
+  else
+    FBitmap.FillEllipseAntialias((EffectiveSize - 1) / 2, (EffectiveSize - 1) / 2, ScaledSize, ScaledSize, clGray);
+
+  if (FStyle = zsRaised) or (FStyle = zsLowered) then
+  begin
+    Mask := FBitmap.FilterGrayscale as TBGRABitmap;
+    if (FStyle = zsRaised) then
+      Mask.Negative;
+    Blur := Mask.FilterBlurRadial(ScaledPhongSize, ScaledPhongSize, rbFast) as TBGRABitmap;
+    Blur.FillMask(0, 0, Mask, BGRAPixelTransparent, dmSet);
+    Mask.Free;
+
+    Phong := TPhongShading.Create;
+    if assigned(FTheme) then
+    begin
+      Phong.AmbientFactor := FAmbientFactor;
+      Phong.SpecularIndex := FSpecularIndex;
+      Phong.LightDestFactor := FLightDestFactor;
+      Phong.LightPosition := Point(FLightPositionX, FLightPositionY);
+      Phong.LightPositionZ := FLightPositionZ;
+      Phong.LightSourceIntensity := FLightSourceIntensity;
+      Phong.LightSourceDistanceTerm := FLightSourceDistanceTerm;
+      Phong.LightSourceDistanceFactor := FLightSourceDistanceFactor;
+      Phong.NegativeDiffusionFactor := FNegativeDiffusionFactor;
+      Phong.SpecularFactor := FSpecularFactor;
+      Phong.DiffusionFactor := FDiffusionFactor;
+      Phong.DiffuseSaturation := FDiffuseSaturation;
+      Phong.LightColor := FLightColor;
+    end;
+    Phong.Draw(FBitmap, Blur, FAltitude, 0, 0, FBitmap);
+    Phong.Free;
+    Blur.Free;
+
+    Mask := TBGRABitmap.Create(EffectiveSize, EffectiveSize, BGRABlack);
+    Mask.FillEllipseAntialias((EffectiveSize - 1) / 2, (EffectiveSize - 1) / 2, ScaledSize, ScaledSize, BGRAWhite);
+    Mask2 := TBGRABitmap.Create(EffectiveSize, EffectiveSize, ColorToBGRA(ColorToRGB(FBkgColor)));
+    Mask2.PutImage(0, 0, FBitmap, dmSet);
+    Mask2.ApplyMask(Mask);
+    Mask.Free;
+    FBitmap.Fill(FBkgColor);
+    FBitmap.PutImage(0, 0, Mask2, dmDrawWithTransparency);
+    Mask2.Free;
+  end
+  else
+  begin
+    Mask := TBGRABitmap.Create(EffectiveSize, EffectiveSize, BGRABlack);
+    Mask.FillEllipseAntialias((EffectiveSize - 1) / 2, (EffectiveSize - 1) / 2, ScaledSize, ScaledSize, BGRAWhite);
+    Mask2 := TBGRABitmap.Create(EffectiveSize, EffectiveSize, ColorToBGRA(ColorToRGB(FBkgColor)));
+    Mask2.PutImage(0, 0, FBitmap, dmSet);
+    Mask2.ApplyMask(Mask);
+    Mask.Free;
+    FBitmap.Fill(FBkgColor);
+    FBitmap.PutImage(0, 0, Mask2, dmDrawWithTransparency);
+    Mask2.Free;
+  end;
+
+  if FValue then
+  begin
+    Mask := TBGRABitmap.Create(EffectiveSize, EffectiveSize);
+    Mask.FillEllipseAntialias((EffectiveSize - 1) / 2, (EffectiveSize - 1) / 2, ScaledSize, ScaledSize, FColorOn);
+    Mask := Mask.FilterBlurRadial(ScaledPhongSize * 2, ScaledPhongSize * 2, rbFast);
+    FBitmap.BlendImageOver(0, 0, Mask, boGlow);
+    Mask.Free;
+  end;
+
+  FBitmap.Draw(Canvas, 0, 0, True);
+end;
+
+end.

+ 457 - 0
bcleaqled.pas

@@ -0,0 +1,457 @@
+{
+ *****************************************************************************
+  See the file COPYING.modifiedLGPL.txt, included in this distribution,
+  for details about the license.
+ *****************************************************************************
+
+ Author: Boban Spasic
+ Credits to: circular from Lazarus forum
+}
+
+unit BCLeaQLED;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Controls, LResources, Graphics,
+  BGRABitmapTypes, BGRABitmap, BGRAGradients, BCLeaTheme, BCLeaTypes;
+
+type
+  TBCLeaQLED = class(TCustomControl)
+  private
+    FBitmap: TBGRABitmap;
+    FTheme: TBCLeaTheme;
+    FOnChangeValue: TNotifyEvent;
+    FValue: boolean;
+    FColorOn: TColor;
+    FColorOff: TColor;
+    FBkgColor: TColor;
+    FStyle: TZStyle;
+    FSize: integer;
+    FAltitude: integer;
+    FClickable: boolean;
+    FRounding: integer;
+    //global intensity of the light
+    FLightSourceIntensity: single;
+    //minimum distance always added (positive value)
+    FLightSourceDistanceTerm: single;
+    //how much actual distance is taken into account (usually 0 or 1)
+    FLightSourceDistanceFactor: single;
+    //how much the location of the lightened pixel is taken into account (usually 0 or 1)
+    FLightDestFactor: single;
+    //color of the light reflection
+    FLightColor: TColor;
+    //how much light is reflected (0..1)
+    FSpecularFactor: single;
+    //how concentrated reflected light is (positive value)
+    FSpecularIndex: single;
+    //ambiant lighting whereever the point is (0..1)
+    FAmbientFactor: single;
+    //diffusion, i.e. how much pixels are lightened by light source (0..1)
+    FDiffusionFactor: single;
+    //how much hidden surface are darkened (0..1)
+    FNegativeDiffusionFactor: single;
+    //when diffusion saturates, use light color to show it
+    FDiffuseSaturation: boolean;
+    FLightPositionX: integer;
+    FLightPositionY: integer;
+    FLightPositionZ: integer;
+    procedure SetValue(AValue: boolean);
+    procedure SetAltitude(AValue: integer);
+    procedure SetColorOn(AValue: TColor);
+    procedure SetColorOff(AValue: TColor);
+    procedure SetBkgColor(AValue: TColor);
+    procedure SetStyle(AValue: TZStyle);
+    procedure SetSize(AValue: integer);
+    procedure SetClickable(AValue: boolean);
+    procedure SetTheme(AValue: TBCLeaTheme);
+    procedure SetRounding(AValue: integer);
+  protected
+    procedure SetEnabled(Value: boolean); override;
+    procedure SetVisible(Value: boolean); override;
+    procedure Paint; override;
+    procedure Redraw;
+    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
+    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
+    procedure MouseMove(Shift: TShiftState; X, Y: integer); override;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure UpdateTheme;
+    procedure ApplyTheme;
+    procedure SaveThemeToFile(AFileName: string);
+    procedure LoadThemeFromFile(AFileName: string);
+    procedure ApplyDefaultTheme;
+  published
+    property Align;
+    property Cursor;
+    property Enabled;
+    property Font;
+    property ParentColor;
+    property ParentFont;
+    property ParentShowHint;
+    property PopupMenu;
+    property ShowHint;
+    property TabOrder;
+    property TabStop default True;
+    property Anchors;
+    property Constraints;
+    property Visible;
+    property OnClick;
+    property OnDblClick;
+    property OnEnter;
+    property OnExit;
+    property OnMouseMove;
+    property OnMouseDown;
+    property OnMouseUp;
+    property OnMouseWheel;
+    property OnMouseWheelDown;
+    property OnMouseWheelUp;
+    property OnKeyDown;
+    property OnKeyUp;
+    property OnKeyPress;
+    property OnContextPopup;
+    property Value: boolean read FValue write SetValue default False;
+    property ColorOn: TColor read FColorOn write SetColorOn default TColor($00FF9C15);
+    property ColorOff: TColor read FColorOff write SetColorOff default TColor($009E5A00);
+    property BackgroundColor: TColor read FBkgColor write SetBkgColor default clBtnFace;
+    property Size: integer read FSize write SetSize default 20;
+    property OnChangeValue: TNotifyEvent read FOnChangeValue write FOnChangeValue;
+    property Style: TZStyle read FStyle write SetStyle default zsRaised;
+    property Clickable: boolean read FClickable write SetClickable default False;
+    property Theme: TBCLeaTheme read FTheme write SetTheme;
+    property Altitude: integer read FAltitude write SetAltitude default 2;
+    property Rounding: integer read FRounding write SetRounding default 3;
+  end;
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+  RegisterComponents('BGRA Controls', [TBCLeaQLED]);
+end;
+
+constructor TBCLeaQLED.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+
+  with GetControlClassDefaultSize do
+    SetInitialBounds(0, 0, 50, 50);
+  FValue := False;
+  FBitmap := TBGRABitmap.Create(Width, Height, FBkgColor);
+  FClickable := False;
+  ApplyDefaultTheme;
+end;
+
+destructor TBCLeaQLED.Destroy;
+begin
+  FreeAndNil(FBitmap);
+  inherited Destroy;
+end;
+
+procedure TBCLeaQLED.SetEnabled(Value: boolean);
+begin
+  inherited SetEnabled(Value);
+  Invalidate;
+end;
+
+procedure TBCLeaQLED.SetVisible(Value: boolean);
+begin
+  inherited SetVisible(Value);
+  Invalidate;
+end;
+
+procedure TBCLeaQLED.Paint;
+begin
+  inherited Paint;
+  Redraw;
+end;
+
+procedure TBCLeaQLED.SetStyle(AValue: TZStyle);
+begin
+  if FStyle = AValue then
+    Exit;
+  FStyle := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaQLED.SetValue(AValue: boolean);
+begin
+  if FValue = AValue then
+    exit;
+  FValue := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaQLED.SetSize(AValue: integer);
+begin
+  if FSize = AValue then
+    exit;
+  FSize := AValue;
+  if FSize < 1 then FSize := 1;
+  Invalidate;
+end;
+
+procedure TBCLeaQLED.SetColorOn(AValue: TColor);
+begin
+  if FColorOn = AValue then
+    Exit;
+  FColorOn := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaQLED.SetColorOff(AValue: TColor);
+begin
+  if FColorOff = AValue then
+    Exit;
+  FColorOff := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaQLED.SetBkgColor(AValue: TColor);
+begin
+  if FBkgColor = AValue then
+    Exit;
+  FBkgColor := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaQLED.SetAltitude(AValue: integer);
+begin
+  if FAltitude = AValue then
+    Exit;
+  FAltitude := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaQLED.SetRounding(AValue: integer);
+begin
+  if FRounding = AValue then
+    Exit;
+  FRounding := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaQLED.SetClickable(AValue: boolean);
+begin
+  if FClickable = AValue then
+    Exit;
+  FClickable := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaQLED.SetTheme(AValue: TBCLeaTheme);
+begin
+  if FTheme = AValue then
+    Exit;
+  if Assigned(FTheme) then
+    FTheme := nil;
+  FTheme := AValue;
+  ApplyTheme;
+end;
+
+procedure TBCLeaQLED.UpdateTheme;
+begin
+  if Assigned(FTheme) then
+  begin
+    FTheme.QLED_ColorOn := FColorOn;
+    FTheme.QLED_ColorOff := FColorOff;
+    FTheme.QLED_BkgColor := FBkgColor;
+    FTheme.QLED_Style := FStyle;
+    FTheme.QLED_Size := FSize;
+    FTheme.QLED_Altitude := FAltitude;
+    FTheme.QLED_Rounding := FRounding;
+  end;
+end;
+
+procedure TBCLeaQLED.ApplyTheme;
+begin
+  if Assigned(FTheme) then
+  begin
+    FColorOn := FTheme.QLED_ColorOn;
+    FColorOff := FTheme.QLED_ColorOff;
+    FBkgColor := FTheme.QLED_BkgColor;
+    FStyle := FTheme.QLED_Style;
+    FSize := FTheme.QLED_Size;
+    FAltitude := FTHeme.QLED_Altitude;
+    FRounding := FTheme.QLED_Rounding;
+    FLightSourceIntensity := FTheme.COM_LightSourceIntensity;
+    FLightSourceDistanceTerm := FTheme.COM_LightSourceDistanceTerm;
+    FLightSourceDistanceFactor := FTheme.COM_LightSourceDistanceFactor;
+    FLightDestFactor := FTheme.COM_LightDestFactor;
+    FLightColor := FTheme.COM_LightColor;
+    FSpecularFactor := FTheme.COM_SpecularFactor;
+    FSpecularIndex := FTheme.COM_SpecularIndex;
+    FAmbientFactor := FTheme.COM_AmbientFactor;
+    FDiffusionFactor := FTheme.COM_DiffusionFactor;
+    FNegativeDiffusionFactor := FTheme.COM_NegativeDiffusionFactor;
+    FDiffuseSaturation := FTheme.COM_DiffuseSaturation;
+    FLightPositionX := FTheme.COM_LightPositionX;
+    FLightPositionY := FTheme.COM_LightPositionY;
+    FLightPositionZ := FTheme.COM_LightPositionZ;
+    Invalidate;
+  end
+  else
+  begin
+    ApplyDefaultTheme;
+  end;
+end;
+
+procedure TBCLeaQLED.SaveThemeToFile(AFileName: string);
+begin
+  if Assigned(FTheme) then
+    FTheme.SaveThemeToFile(AFileName);
+end;
+
+procedure TBCLeaQLED.LoadThemeFromFile(AFileName: string);
+begin
+  if Assigned(FTheme) then
+    FTheme.LoadThemeFromFile(AFileName);
+end;
+
+procedure TBCLeaQLED.ApplyDefaultTheme;
+begin
+  FColorOn := TColor($00FF9C15);
+  FColorOff := TColor($009E5A00);
+  FBkgColor := clBtnFace;
+  FStyle := zsRaised;
+  FSize := 20;
+  FAltitude := 2;
+  FRounding := 3;
+  FAmbientFactor := 0.3;
+  FSpecularIndex := 10;
+  FSpecularFactor := 0.6;
+  FLightDestFactor := 1;
+  FLightPositionX := -100;
+  FLightPositionY := -100;
+  FLightPositionZ := 100;
+  FLightSourceIntensity := 500;
+  FLightSourceDistanceTerm := 150;
+  FLightSourceDistanceFactor := 1;
+  FNegativeDiffusionFactor := 0.1;
+  FLightColor := clWhite;
+  FDiffuseSaturation := False;
+  FDiffusionFactor := 0.9;
+end;
+
+procedure TBCLeaQLED.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseDown(Button, Shift, X, Y);
+  if FClickable and (Button = mbLeft) then
+  begin
+    FValue := not FValue;
+    Redraw;
+    if Assigned(FOnChangeValue) then
+      FOnChangeValue(Self);
+  end;
+end;
+
+procedure TBCLeaQLED.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseUp(Button, Shift, X, Y);
+end;
+
+procedure TBCLeaQLED.MouseMove(Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseMove(Shift, X, Y);
+end;
+
+procedure TBCLeaQLED.Redraw;
+var
+  EffectiveSize: integer;
+  Blur: TBGRABitmap;
+  Mask, Mask2: TBGRABitmap;
+  Phong: TPhongShading;
+  ScaledPhongSize, ScaledSize: integer;
+begin
+  FBitmap.SetSize(Width, Height);
+  FBitmap.Fill(FBkgColor);
+
+  if Width < Height then
+    EffectiveSize := Width
+  else
+    EffectiveSize := Height;
+  if EffectiveSize < 2 then exit;
+  ScaledSize := Scale96ToForm(FSize);
+  ScaledPhongSize := Scale96ToForm(5);
+
+  if Enabled then
+  begin
+    if FValue then
+      FBitmap.FillRoundRectAntialias((EffectiveSize / 2) - ScaledSize, (EffectiveSize / 2) - ScaledSize, (EffectiveSize / 2) + ScaledSize, (EffectiveSize / 2) + ScaledSize, FRounding, FRounding, FColorOn)
+    else
+      FBitmap.FillRoundRectAntialias((EffectiveSize / 2) - ScaledSize, (EffectiveSize / 2) - ScaledSize, (EffectiveSize / 2) + ScaledSize, (EffectiveSize / 2) + ScaledSize, FRounding, FRounding, FColorOff);
+  end
+  else
+    FBitmap.FillRoundRectAntialias((EffectiveSize / 2) - ScaledSize, (EffectiveSize / 2) - ScaledSize, (EffectiveSize / 2) + ScaledSize, (EffectiveSize / 2) + ScaledSize, FRounding, FRounding, clGray);
+
+  if (FStyle = zsRaised) or (FStyle = zsLowered) then
+  begin
+    Mask := FBitmap.FilterGrayscale as TBGRABitmap;
+    if (FStyle = zsRaised) then
+      Mask.Negative;
+    Blur := Mask.FilterBlurRadial(ScaledPhongSize, ScaledPhongSize, rbFast) as TBGRABitmap;
+    Blur.FillMask(0, 0, Mask, BGRAPixelTransparent, dmSet);
+    Mask.Free;
+
+    Phong := TPhongShading.Create;
+    if assigned(FTheme) then
+    begin
+      Phong.AmbientFactor := FAmbientFactor;
+      Phong.SpecularIndex := FSpecularIndex;
+      Phong.LightDestFactor := FLightDestFactor;
+      Phong.LightPosition := Point(FLightPositionX, FLightPositionY);
+      Phong.LightPositionZ := FLightPositionZ;
+      Phong.LightSourceIntensity := FLightSourceIntensity;
+      Phong.LightSourceDistanceTerm := FLightSourceDistanceTerm;
+      Phong.LightSourceDistanceFactor := FLightSourceDistanceFactor;
+      Phong.NegativeDiffusionFactor := FNegativeDiffusionFactor;
+      Phong.SpecularFactor := FSpecularFactor;
+      Phong.DiffusionFactor := FDiffusionFactor;
+      Phong.DiffuseSaturation := FDiffuseSaturation;
+      Phong.LightColor := FLightColor;
+    end;
+    Phong.Draw(FBitmap, Blur, FAltitude, 0, 0, FBitmap);
+    Phong.Free;
+    Blur.Free;
+
+    Mask := TBGRABitmap.Create(EffectiveSize, EffectiveSize, BGRABlack);
+    Mask.FillRoundRectAntialias((EffectiveSize / 2) - ScaledSize, (EffectiveSize / 2) - ScaledSize, (EffectiveSize / 2) + ScaledSize, (EffectiveSize / 2) + ScaledSize, FRounding, FRounding, BGRAWhite);
+    Mask2 := TBGRABitmap.Create(EffectiveSize, EffectiveSize, ColorToBGRA(ColorToRGB(FBkgColor)));
+    Mask2.PutImage(0, 0, FBitmap, dmSet);
+    Mask2.ApplyMask(Mask);
+    Mask.Free;
+    FBitmap.Fill(FBkgColor);
+    FBitmap.PutImage(0, 0, Mask2, dmDrawWithTransparency);
+    Mask2.Free;
+  end
+  else
+  begin
+    Mask := TBGRABitmap.Create(EffectiveSize, EffectiveSize, BGRABlack);
+    Mask.FillRoundRectAntialias((EffectiveSize / 2) - ScaledSize, (EffectiveSize / 2) - ScaledSize, (EffectiveSize / 2) + ScaledSize, (EffectiveSize / 2) + ScaledSize, FRounding, FRounding, BGRAWhite);
+    Mask2 := TBGRABitmap.Create(EffectiveSize, EffectiveSize, ColorToBGRA(ColorToRGB(FBkgColor)));
+    Mask2.PutImage(0, 0, FBitmap, dmSet);
+    Mask2.ApplyMask(Mask);
+    Mask.Free;
+    FBitmap.Fill(FBkgColor);
+    FBitmap.PutImage(0, 0, Mask2, dmDrawWithTransparency);
+    Mask2.Free;
+  end;
+
+  if FValue then
+  begin
+    Mask := TBGRABitmap.Create(EffectiveSize, EffectiveSize);
+    Mask.FillRoundRectAntialias((EffectiveSize / 2) - ScaledSize, (EffectiveSize / 2) - ScaledSize, (EffectiveSize / 2) + ScaledSize, (EffectiveSize / 2) + ScaledSize, FRounding, FRounding, FColorOn);
+    Mask := Mask.FilterBlurRadial(ScaledPhongSize * 2, ScaledPhongSize * 2, rbFast);
+    FBitmap.BlendImageOver(0, 0, Mask, boGlow);
+    Mask.Free;
+  end;
+
+  FBitmap.Draw(Canvas, 0, 0, True);
+end;
+
+end.

+ 736 - 0
bclearingslider.pas

@@ -0,0 +1,736 @@
+{
+ *****************************************************************************
+  See the file COPYING.modifiedLGPL.txt, included in this distribution,
+  for details about the license.
+ *****************************************************************************
+
+ Author: Boban Spasic
+ Credits to: hedgehog, circular and lainz from Lazarus forum
+ Based on TFluentProgressRing from hedgehog
+}
+
+unit BCLeaRingSlider;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Controls, Graphics, ExtCtrls, LResources,
+  BGRABitmapTypes, BGRABitmap, BGRATextFX, BGRAGradients, BCLeaTheme, BCLeaTypes;
+
+type
+
+  { TBCLeaRingSlider }
+
+  TBCLeaRingSlider = class(TCustomControl)
+  private
+    FBitmap: TBGRABitmap;
+    FTheme: TBCLeaTheme;
+    FOnChangeValue: TNotifyEvent;
+    FMaxValue: integer;
+    FMinValue: integer;
+    FOffset: integer;
+    FValue: integer;
+    FLineColor: TColor;
+    FLineBkgColor: TColor;
+    FLineWidth: integer;
+    FVerticalPos: single;
+    FDeltaPos: single;
+    FSettingVerticalPos: boolean;
+    FSensitivity: integer;
+    FMinAngle: integer;
+    FMaxAngle: integer;
+    FFontShadowColor: TColor;
+    FFontShadowOffsetX: integer;
+    FFontShadowOffsetY: integer;
+    FFontShadowRadius: integer;
+    FDrawText: boolean;
+    FDrawPointer: boolean;
+    FBkgColor: TColor;
+    FStyle: TZStyle;
+    FDrawTextPhong: boolean;
+    FPointerColor: TColor;
+    FPointerSize: integer;
+    FAltitude: integer;
+    //global intensity of the light
+    FLightSourceIntensity: single;
+    //minimum distance always added (positive value)
+    FLightSourceDistanceTerm: single;
+    //how much actual distance is taken into account (usually 0 or 1)
+    FLightSourceDistanceFactor: single;
+    //how much the location of the lightened pixel is taken into account (usually 0 or 1)
+    FLightDestFactor: single;
+    //color of the light reflection
+    FLightColor: TColor;
+    //how much light is reflected (0..1)
+    FSpecularFactor: single;
+    //how concentrated reflected light is (positive value)
+    FSpecularIndex: single;
+    //ambiant lighting whereever the point is (0..1)
+    FAmbientFactor: single;
+    //diffusion, i.e. how much pixels are lightened by light source (0..1)
+    FDiffusionFactor: single;
+    //how much hidden surface are darkened (0..1)
+    FNegativeDiffusionFactor: single;
+    //when diffusion saturates, use light color to show it
+    FDiffuseSaturation: boolean;
+    FLightPositionX: integer;
+    FLightPositionY: integer;
+    FLightPositionZ: integer;
+    procedure SetLineBkgColor(AValue: TColor);
+    procedure SetLineColor(AValue: TColor);
+    procedure SetMaxValue(AValue: integer);
+    procedure SetMinValue(AValue: integer);
+    procedure SetValue(AValue: integer);
+    procedure SetLineWidth(AValue: integer);
+    procedure UpdateVerticalPos(X, Y: integer);
+    procedure SetSensitivity(AValue: integer);
+    procedure SetMinAngle(AValue: integer);
+    procedure SetMaxAngle(AValue: integer);
+    procedure SetDrawText(AValue: boolean);
+    procedure SetDrawPointer(AValue: boolean);
+    procedure SetBkgColor(AValue: TColor);
+    procedure SetFFontShadowColor(AValue: TColor);
+    procedure SetFFontShadowOffsetX(AValue: integer);
+    procedure SetFFontShadowOffsetY(AValue: integer);
+    procedure SetFFontShadowRadius(AValue: integer);
+    procedure SetStyle(AValue: TZStyle);
+    procedure SetDrawTextPhong(AValue: boolean);
+    procedure SetPointerColor(AValue: TColor);
+    procedure SetPointerSize(AValue: integer);
+    procedure SetAltitude(AValue: integer);
+    procedure SetTheme(AValue: TBCLeaTheme);
+
+  protected
+    procedure SetEnabled(Value: boolean); override;
+    procedure SetVisible(Value: boolean); override;
+    procedure Paint; override;
+    procedure Redraw;
+    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
+    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
+    procedure MouseMove(Shift: TShiftState; X, Y: integer); override;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure UpdateTheme;
+    procedure ApplyTheme;
+    procedure SaveThemeToFile(AFileName: string);
+    procedure LoadThemeFromFile(AFileName: string);
+    procedure ApplyDefaultTheme;
+  published
+    property Align;
+    property Caption;
+    property Color;
+    property Cursor;
+    property Enabled;
+    property Font;
+    property ParentColor;
+    property ParentFont;
+    property ParentShowHint;
+    property PopupMenu;
+    property ShowHint;
+    property TabOrder;
+    property TabStop default True;
+    property Anchors;
+    property Constraints;
+    property Visible;
+    property OnClick;
+    property OnDblClick;
+    property OnEnter;
+    property OnExit;
+    property OnMouseMove;
+    property OnMouseDown;
+    property OnMouseUp;
+    property OnMouseWheel;
+    property OnMouseWheelDown;
+    property OnMouseWheelUp;
+    property OnKeyDown;
+    property OnKeyUp;
+    property OnKeyPress;
+    property OnConTextPopup;
+    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($00D3D3D3);
+    property LineWidth: integer read FLineWidth write SetLineWidth default 8;
+    property OnChangeValue: TNotifyEvent read FOnChangeValue write FOnChangeValue;
+    //Greater value is less sensitive
+    property Sensitivity: integer read FSensitivity write SetSensitivity default 10;
+    property MinAngle: integer read FMinAngle write SetMinAngle default 20;
+    property MaxAngle: integer read FMaxAngle write SetMaxAngle default 340;
+    property FontShadowColor: TColor read FFontShadowColor write SetFFontShadowColor default clBlack;
+    property FontShadowOffsetX: integer read FFontShadowOffsetX write SetFFontShadowOffsetX default 2;
+    property FontShadowOffsetY: integer read FFontShadowOffsetY write SetFFontShadowOffsetY default 2;
+    property FontShadowRadius: integer read FFontSHadowRadius write SetFFontShadowRadius default 4;
+    property DrawText: boolean read FDrawText write SetDrawText default True;
+    property DrawPointer: boolean read FDrawPointer write SetDrawPointer default False;
+    property BackgroundColor: TColor read FBkgColor write SetBkgColor default clBtnFace;
+    property Style: TZStyle read FStyle write SetStyle default zsRaised;
+    property DrawTextPhong: boolean read FDrawTextPhong write SetDrawTextPhong default False;
+    property PointerColor: TColor read FPointerColor write SetPointerColor default TColor($00FF9C15);
+    property PointerSize: integer read FPointerSize write SetPointerSize default 2;
+    property Altitude: integer read FAltitude write SetAltitude default 2;
+    property Theme: TBCLeaTheme read FTheme write SetTheme;
+  end;
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+  RegisterComponents('BGRA Controls', [TBCLeaRingSlider]);
+end;
+
+{ TBCLeaRingSlider }
+
+procedure TBCLeaRingSlider.SetMaxAngle(AValue: integer);
+begin
+  if FMaxAngle = AValue then
+    exit;
+  FMaxAngle := AValue;
+  if FMaxAngle > 350 then
+    FMaxAngle := 350;
+  if FMinAngle > FMaxAngle then
+    FMaxAngle := FMinAngle;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetMinAngle(AValue: integer);
+begin
+  if FMinAngle = AValue then
+    exit;
+  FMinAngle := AValue;
+  if FMinAngle < 10 then
+    FMinAngle := 10;
+  if FMinAngle > FMaxAngle then
+    FMinAngle := FMaxAngle;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetSensitivity(AValue: integer);
+begin
+  if FSensitivity = AValue then
+    exit;
+  if AValue <> 0 then
+    FSensitivity := AValue
+  else
+    FSensitivity := 10;
+end;
+
+procedure TBCLeaRingSlider.SetMaxValue(AValue: integer);
+begin
+  if FMaxValue = AValue then
+    exit;
+  FMaxValue := AValue;
+  if FValue > FMaxValue then
+    FValue := FMaxValue;
+  if FMinValue > FMaxValue then
+    FMinValue := FMaxValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetLineBkgColor(AValue: TColor);
+begin
+  if FLineBkgColor = AValue then
+    Exit;
+  FLineBkgColor := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetLineColor(AValue: TColor);
+begin
+  if FLineColor = AValue then
+    Exit;
+  FLineColor := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetMinValue(AValue: integer);
+begin
+  if FMinValue = AValue then
+    exit;
+  FMinValue := AValue;
+  if FMinValue <> 0 then FOffset := -FMinValue;
+  if FValue < FMinValue then
+    FValue := FMinValue;
+  if FMaxValue < FMinValue then
+    FMaxValue := FMinValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetValue(AValue: integer);
+begin
+  if FValue = AValue then
+    exit;
+  FValue := AValue;
+  if FValue < FMinValue then
+    FValue := FMinValue;
+  if FValue > FMaxValue then
+    FValue := FMaxValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetLineWidth(AValue: integer);
+begin
+  if FLineWidth = AValue then exit;
+  FLineWidth := AValue;
+  if Visible then Redraw;
+end;
+
+procedure TBCLeaRingSlider.SetEnabled(Value: boolean);
+begin
+  inherited SetEnabled(Value);
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetVisible(Value: boolean);
+begin
+  inherited SetVisible(Value);
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.Paint;
+begin
+  inherited Paint;
+  Redraw;
+end;
+
+procedure TBCLeaRingSlider.Redraw;
+const
+  pi15 = pi * 1.5;
+var
+  TextBmp: TBGRABitmap;
+  TextStr: string;
+  EffectiveSize, ScaledPhongSize: integer;
+  EffectiveLineWidth: single;
+  r: single;
+  RMinAngle, RMaxAngle: single;
+  Blur: TBGRABitmap;
+  Mask, Mask2: TBGRABitmap;
+  Phong: TPhongShading;
+
+  procedure DoDrawArc(a, b: single; c: TColor);
+  begin
+    FBitmap.Canvas2D.strokeStyle(c);
+    FBitmap.Canvas2D.beginPath;
+    FBitmap.Canvas2D.arc(0, 0, r, a, b, False);
+    FBitmap.Canvas2D.stroke;
+  end;
+
+  procedure DoDrawPointer(a: single; c: TColor);
+  begin
+    FBitmap.Canvas2D.strokeStyle(c);
+    FBitmap.Canvas2D.beginPath;
+    FBitmap.Canvas2D.arc(0, 0, r, a - (FPointerSize / 100), a + (FPointerSize / 100), False);
+    FBitmap.Canvas2D.stroke;
+  end;
+
+  procedure DoDrawTick(a, b: single; c: TColor);
+  begin
+    FBitmap.Canvas2D.strokeStyle(c);
+    FBitmap.Canvas2D.lineWidth := 5;
+    FBitmap.Canvas2D.beginPath;
+    FBitmap.Canvas2D.lineTo(0 - a, 0 - b);
+    FBitmap.Canvas2D.lineTo(5 - a, -2 - b);
+    FBitmap.Canvas2D.lineTo(5 - a, 2 - b);
+    FBitmap.Canvas2D.lineTo(0 - a, 0 - b);
+    FBitmap.Canvas2D.stroke;
+  end;
+
+begin
+  FBitmap.SetSize(Width, Height);
+  FBitmap.Fill(FBkgColor);
+
+  if Width < Height then
+    EffectiveSize := Width
+  else
+    EffectiveSize := Height;
+
+  if EffectiveSize < 2 then exit;
+
+
+  FBitmap.Canvas2D.resetTransform;
+  FBitmap.Canvas2D.translate(FBitmap.Width / 2, FBitmap.Height / 2);
+  FBitmap.Canvas2D.rotate(pi15);
+
+  if FLineWidth = 0 then
+    EffectiveLineWidth := EffectiveSize / 12
+  else
+    EffectiveLineWidth := FLineWidth;
+  r := (EffectiveSize - EffectiveLineWidth) / 2;
+
+  FBitmap.Canvas2D.lineWidth := EffectiveLineWidth;
+
+  RMinAngle := (180 + FMinAngle) * pi / 180;
+  RMaxAngle := ((180 + FMaxAngle) * pi / 180) - RMinAngle;
+
+  FBitmap.Canvas2D.lineCapLCL := pecRound;
+  // background line
+  if FLineBkgColor <> clNone then
+    DoDrawArc(RMinAngle, (RMaxAngle + RMinAngle), FLineBkgColor);
+
+  if Enabled then
+  begin
+    if FValue > FMinValue then
+    begin
+      DoDrawArc(RMinAngle, (RMaxAngle / (FMaxValue + FOffset)) * ((FValue + FOffset) - ((FMaxValue + FOffset) / 2)), FLineColor);
+      if FDrawPointer then
+        DoDrawPointer((RMaxAngle / (FMaxValue + FOffset)) * ((FValue + FOffset) - ((FMaxValue + FOffset) / 2)), FPointerColor);
+    end;
+  end
+  else
+    DoDrawArc(RMinAngle, (RMaxAngle / (FMaxValue + FOffset)) * ((FValue + FOffset) - ((FMaxValue + FOffset) / 2)), clGray);
+
+  if FDrawText and FDrawTextPhong then
+  begin
+    TextStr := IntToStr(FValue);
+    TextBmp := TextShadow(EffectiveSize, EffectiveSize, TextStr, Font.Height,
+      Font.Color, FontShadowColor, FontShadowOFfsetX,
+      FontShadowOffsetY, FontShadowRadius, Font.Style, Font.Name) as TBGRABitmap;
+    FBitmap.PutImage(0, 0, TextBmp, dmDrawWithTransparency);
+    TextBmp.Free;
+  end;
+
+  if (FStyle = zsRaised) or (FStyle = zsLowered) then
+  begin
+    ScaledPhongSize := round(EffectiveLineWidth / 2);
+    Mask := FBitmap.FilterGrayscale as TBGRABitmap;
+    if FStyle = zsRaised then
+      Mask.Negative;
+    Blur := Mask.FilterBlurRadial(ScaledPhongSize, ScaledPhongSize, rbFast) as TBGRABitmap;
+    Blur.FillMask(0, 0, Mask, BGRAPixelTransparent, dmSet);
+    Mask.Free;
+
+    Phong := TPhongShading.Create;
+    if Assigned(FTheme) then
+    begin
+      Phong.AmbientFactor := FAmbientFactor;
+      Phong.SpecularIndex := FSpecularIndex;
+      Phong.LightDestFactor := FLightDestFactor;
+      Phong.LightPosition := Point(FLightPositionX, FLightPositionY);
+      Phong.LightPositionZ := FLightPositionZ;
+      Phong.LightSourceIntensity := FLightSourceIntensity;
+      Phong.LightSourceDistanceTerm := FLightSourceDistanceTerm;
+      Phong.LightSourceDistanceFactor := FLightSourceDistanceFactor;
+      Phong.NegativeDiffusionFactor := FNegativeDiffusionFactor;
+      Phong.SpecularFactor := FSpecularFactor;
+      Phong.DiffusionFactor := FDiffusionFactor;
+      Phong.DiffuseSaturation := FDiffuseSaturation;
+      Phong.LightColor := FLightColor;
+    end;
+    Phong.Draw(FBitmap, Blur, FAltitude, 0, 0, FBitmap);
+    Phong.Free;
+    Blur.Free;
+
+    Mask := TBGRABitmap.Create(EffectiveSize, EffectiveSize, BGRABlack);
+    Mask.FillEllipseAntialias(EffectiveSize div 2, EffectiveSize div 2, EffectiveSize div 2, EffectiveSize div 2, BGRAWhite);
+    Mask2 := TBGRABitmap.Create(EffectiveSize, EffectiveSize, ColorToBGRA(ColorToRGB(FBkgColor)));
+    Mask2.PutImage(0, 0, FBitmap, dmSet);
+    Mask2.ApplyMask(Mask);
+    Mask.Free;
+    FBitmap.Fill(FBkgColor);
+    FBitmap.PutImage(0, 0, Mask2, dmDrawWithTransparency);
+    Mask2.Free;
+  end;
+
+  if FDrawText and not FDrawTextPhong then
+  begin
+    TextStr := IntToStr(FValue);
+    TextBmp := TextShadow(EffectiveSize, EffectiveSize, TextStr, Font.Height,
+      Font.Color, FontShadowColor, FontShadowOFfsetX,
+      FontShadowOffsetY, FontShadowRadius, Font.Style, Font.Name) as TBGRABitmap;
+    FBitmap.PutImage(0, 0, TextBmp, dmDrawWithTransparency);
+    TextBmp.Free;
+  end;
+
+  FBitmap.Draw(Canvas, 0, 0, True);
+end;
+
+constructor TBCLeaRingSlider.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+
+  with GetControlClassDefaultSize do
+    SetInitialBounds(0, 0, 100, 100);
+  FMaxValue := 100;
+  FMinValue := 0;
+  FOffset := 0;
+  FMinAngle := 20;
+  FMaxAngle := 340;
+  FValue := 0;
+  FDeltaPos := 0;
+  FSensitivity := 10;
+  Font.Color := clBlack;
+  Font.Height := 20;
+  FDrawText := True;
+  FDrawPointer := False;
+  FBitmap := TBGRABitmap.Create(Width, Height, FBkgColor);
+  ApplyDefaultTheme;
+end;
+
+destructor TBCLeaRingSlider.Destroy;
+begin
+  FreeAndNil(FBitmap);
+  inherited Destroy;
+end;
+
+procedure TBCLeaRingSlider.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseDown(Button, Shift, X, Y);
+  if Button = mbLeft then
+  begin
+    FDeltaPos := ((ClientHeight / FSensitivity) - (Y / FSensitivity)) * (FMaxValue / ClientHeight);
+    FSettingVerticalPos := True;
+  end;
+end;
+
+procedure TBCLeaRingSlider.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseUp(Button, Shift, X, Y);
+  if Button = mbLeft then
+    FSettingVerticalPos := False;
+end;
+
+procedure TBCLeaRingSlider.MouseMove(Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseMove(Shift, X, Y);
+  if FSettingVerticalPos then
+    UpdateVerticalPos(X, Y);
+end;
+
+procedure TBCLeaRingSlider.UpdateVerticalPos(X, Y: integer);
+var
+  FPreviousPos: single;
+  FCurrPos: single;
+begin
+  FPreviousPos := FVerticalPos;
+  FCurrPos := ((ClientHeight / FSensitivity) - (Y / FSensitivity)) * (FMaxValue / ClientHeight);
+
+  FVerticalPos := FVerticalPos - FDeltaPos + FCurrPos;
+  if FVerticalPos < FMinValue then FVerticalPos := FMinValue;
+  if FVerticalPos > FMaxValue then FVerticalPos := FMaxValue;
+
+  FValue := round(FVerticalPos);
+  if FValue < FMinValue then
+    FValue := FMinValue;
+  if FValue > FMaxValue then
+    FValue := FMaxValue;
+
+  Redraw;
+  if (FPreviousPos <> FVerticalPos) and Assigned(FOnChangeValue) then
+    FOnChangeValue(Self);
+end;
+
+procedure TBCLeaRingSlider.SetFFontShadowColor(AValue: TColor);
+begin
+  if FFontShadowColor = AValue then
+    Exit;
+  FFontShadowColor := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetDrawText(AValue: boolean);
+begin
+  if FDrawText = AValue then Exit;
+  FDrawText := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetFFontShadowOffsetX(AValue: integer);
+begin
+  if FFontShadowOffsetX = AValue then
+    Exit;
+  FFontShadowOffsetX := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetFFontShadowOffsetY(AValue: integer);
+begin
+  if FFontShadowOffsetY = AValue then
+    Exit;
+  FFontShadowOffsetY := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetFFontShadowRadius(AValue: integer);
+begin
+  if FFontSHadowRadius = AValue then
+    Exit;
+  FFontSHadowRadius := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetBkgColor(AValue: TColor);
+begin
+  if FBkgColor = AValue then
+    Exit;
+  FBkgColor := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetDrawPointer(AValue: boolean);
+begin
+  if FDrawPointer = AValue then
+    Exit;
+  FDrawPointer := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetStyle(AValue: TZStyle);
+begin
+  if FStyle = AValue then
+    Exit;
+  FStyle := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetDrawTextPhong(AValue: boolean);
+begin
+  if FDrawTextPhong = AValue then
+    Exit;
+  FDrawTextPhong := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetPointerColor(AValue: TColor);
+begin
+  if FPointerColor = AValue then
+    Exit;
+  FPointerColor := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetPointerSize(AValue: integer);
+begin
+  if FPointerSize = AValue then
+    Exit;
+  FPointerSize := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetAltitude(AValue: integer);
+begin
+  if FAltitude = AValue then
+    Exit;
+  FAltitude := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaRingSlider.SetTheme(AValue: TBCLeaTheme);
+begin
+  if FTheme = AValue then
+    Exit;
+  if Assigned(FTheme) then
+    FTheme := nil;
+  FTheme := AValue;
+  ApplyTheme;
+end;
+
+procedure TBCLeaRingSlider.UpdateTheme;
+begin
+  if Assigned(FTheme) then
+  begin
+    FTheme.RS_LineWidth := FLineWidth;
+    FTheme.RS_LineColor := FLineColor;
+    FTheme.RS_LineBkgColor := FLineBkgColor;
+    FTheme.RS_BkgColor := FBkgColor;
+    FTheme.RS_FontShadowColor := FFontShadowColor;
+    FTheme.RS_FontShadowOffsetX := FFontShadowOffsetX;
+    FTheme.RS_FontShadowOffsetY := FFontShadowOffsetY;
+    FTheme.RS_FontShadowRadius := FFontShadowRadius;
+    FTheme.RS_PointerSize := FPointerSize;
+    FTheme.RS_PointerColor := FPointerColor;
+    FTheme.RS_Style := FStyle;
+    FTheme.RS_DrawTextPhong := FDrawTextPhong;
+    FTheme.RS_Altitude := FAltitude;
+  end;
+end;
+
+procedure TBCLeaRingSlider.ApplyTheme;
+begin
+  if Assigned(FTheme) then
+  begin
+    FLineWidth := FTheme.RS_LineWidth;
+    FLineColor := FTheme.RS_LineColor;
+    FLineBkgColor := FTheme.RS_LineBkgColor;
+    FBkgColor := FTheme.RS_BkgColor;
+    FFontShadowColor := FTheme.RS_FontShadowColor;
+    FFontShadowOffsetX := FTheme.RS_FontShadowOffsetX;
+    FFontShadowOffsetY := FTheme.RS_FontShadowOffsetY;
+    FFontShadowRadius := FTheme.RS_FontShadowRadius;
+    FPointerSize := FTheme.RS_PointerSize;
+    FPointerColor := Ftheme.RS_PointerColor;
+    FStyle := FTheme.RS_Style;
+    FDrawTextPhong := FTheme.RS_DrawTextPhong;
+    FAltitude := FTheme.RS_Altitude;
+
+    FLightSourceIntensity := FTheme.COM_LightSourceIntensity;
+    FLightSourceDistanceTerm := FTheme.COM_LightSourceDistanceTerm;
+    FLightSourceDistanceFactor := FTheme.COM_LightSourceDistanceFactor;
+    FLightDestFactor := FTheme.COM_LightDestFactor;
+    FLightColor := FTheme.COM_LightColor;
+    FSpecularFactor := FTheme.COM_SpecularFactor;
+    FSpecularIndex := FTheme.COM_SpecularIndex;
+    FAmbientFactor := FTheme.COM_AmbientFactor;
+    FDiffusionFactor := FTheme.COM_DiffusionFactor;
+    FNegativeDiffusionFactor := FTheme.COM_NegativeDiffusionFactor;
+    FDiffuseSaturation := FTheme.COM_DiffuseSaturation;
+    FLightPositionX := FTheme.COM_LightPositionX;
+    FLightPositionY := FTheme.COM_LightPositionY;
+    FLightPositionZ := FTheme.COM_LightPositionZ;
+    Invalidate;
+  end
+  else
+  begin
+    ApplyDefaultTheme;
+  end;
+end;
+
+procedure TBCLeaRingSlider.SaveThemeToFile(AFileName: string);
+begin
+  if Assigned(FTheme) then
+    FTheme.SaveThemeToFile(AFileName);
+end;
+
+procedure TBCLeaRingSlider.LoadThemeFromFile(AFileName: string);
+begin
+  if Assigned(FTheme) then
+    FTheme.LoadThemeFromFile(AFileName);
+end;
+
+procedure TBCLeaRingSlider.ApplyDefaultTheme;
+begin
+  FLineWidth := 8;
+  FLineColor := TColor($009E5A00);
+  FLineBkgColor := TColor($00D3D3D3);
+  FBkgColor := clBtnFace;
+  FFontShadowColor := clBlack;
+  FFontShadowOffsetX := 2;
+  FFontShadowOffsetY := 2;
+  FFontShadowRadius := 4;
+  FPointerSize := 3;
+  FPointerColor := TColor($00FF9C15);
+  FStyle := zsRaised;
+  FDrawTextPhong := False;
+  FAltitude := 2;
+
+  FAmbientFactor := 0.3;
+  FSpecularIndex := 10;
+  FSpecularFactor := 0.6;
+  FLightDestFactor := 1;
+  FLightPositionX := -100;
+  FLightPositionY := -100;
+  FLightPositionZ := 100;
+  FLightSourceIntensity := 500;
+  FLightSourceDistanceTerm := 150;
+  FLightSourceDistanceFactor := 1;
+  FNegativeDiffusionFactor := 0.1;
+  FLightColor := clWhite;
+  FDiffuseSaturation := False;
+  FDiffusionFactor := 0.9;
+end;
+
+end.

+ 778 - 0
bcleaselector.pas

@@ -0,0 +1,778 @@
+{
+ *****************************************************************************
+  See the file COPYING.modifiedLGPL.txt, included in this distribution,
+  for details about the license.
+ *****************************************************************************
+
+ Author: Boban Spasic
+ Credits to: hedgehog, circular and lainz from Lazarus forum
+ Based on TFluentProgressRing from hedgehog
+}
+
+unit BCLeaSelector;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Controls, Graphics, ExtCtrls, LResources,
+  BGRABitmapTypes, BGRABitmap, BGRATextFX, BGRAGradients, BCLeaTypes, BCLeaTheme;
+
+type
+
+  { TBCLeaSelector }
+
+  TBCLeaSelector = class(TCustomControl)
+  private
+    FBitmap: TBGRABitmap;
+    FTheme: TBCLeaTheme;
+    FOnChangeValue: TNotifyEvent;
+    FTicksCount: integer;
+    FOffset: integer;
+    FValue: integer;
+    FLineColor: TColor;
+    FLineBkgColor: TColor;
+    FLineWidth: integer;
+    FVerticalPos: single;
+    FDeltaPos: single;
+    FSettingVerticalPos: boolean;
+    FSensitivity: integer;
+    FMinAngle: integer;
+    FMaxAngle: integer;
+    FFontShadowColor: TColor;
+    FFontShadowOffsetX: integer;
+    FFontShadowOffsetY: integer;
+    FFontShadowRadius: integer;
+    FDrawText: boolean;
+    FDrawTicks: boolean;
+    FBkgColor: TColor;
+    FItems: TStrings;
+    FMinTicksAngle: integer;
+    FMaxTicksAngle: integer;
+    FPointerSize: integer;
+    FStyle: TZStyle;
+    FDrawTextPhong: boolean;
+    FAltitude: integer;
+    //global intensity of the light
+    FLightSourceIntensity: single;
+    //minimum distance always added (positive value)
+    FLightSourceDistanceTerm: single;
+    //how much actual distance is taken into account (usually 0 or 1)
+    FLightSourceDistanceFactor: single;
+    //how much the location of the lightened pixel is taken into account (usually 0 or 1)
+    FLightDestFactor: single;
+    //color of the light reflection
+    FLightColor: TColor;
+    //how much light is reflected (0..1)
+    FSpecularFactor: single;
+    //how concentrated reflected light is (positive value)
+    FSpecularIndex: single;
+    //ambiant lighting whereever the point is (0..1)
+    FAmbientFactor: single;
+    //diffusion, i.e. how much pixels are lightened by light source (0..1)
+    FDiffusionFactor: single;
+    //how much hidden surface are darkened (0..1)
+    FNegativeDiffusionFactor: single;
+    //when diffusion saturates, use light color to show it
+    FDiffuseSaturation: boolean;
+    FLightPositionX: integer;
+    FLightPositionY: integer;
+    FLightPositionZ: integer;
+    procedure SetLineBkgColor(AValue: TColor);
+    procedure SetLineColor(AValue: TColor);
+    procedure SetTicksCount(AValue: integer);
+    procedure SetValue(AValue: integer);
+    procedure SetLineWidth(AValue: integer);
+    procedure UpdateVerticalPos(X, Y: integer);
+    procedure SetSensitivity(AValue: integer);
+    procedure SetMinAngle(AValue: integer);
+    procedure SetMaxAngle(AValue: integer);
+    procedure SetDrawText(AValue: boolean);
+    procedure SetDrawTicks(AValue: boolean);
+    procedure SetBkgColor(AValue: TColor);
+    procedure SetFFontShadowColor(AValue: TColor);
+    procedure SetFFontShadowOffsetX(AValue: integer);
+    procedure SetFFontShadowOffsetY(AValue: integer);
+    procedure SetFFontShadowRadius(AValue: integer);
+    procedure SetItems(const Value: TStrings);
+    procedure ItemsChanged(Sender: TObject);
+    procedure SetMinTicksAngle(AValue: integer);
+    procedure SetMaxTicksAngle(AValue: integer);
+    procedure SetPointerSize(AValue: integer);
+    procedure SetStyle(AValue: TZStyle);
+    procedure SetDrawTextPhong(AValue: boolean);
+    procedure SetTheme(AValue: TBCLeaTheme);
+    procedure SetAltitude(Avalue: integer);
+  protected
+    procedure SetEnabled(Value: boolean); override;
+    procedure SetVisible(Value: boolean); override;
+    procedure Paint; override;
+    procedure Redraw;
+    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
+    procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer); override;
+    procedure MouseMove(Shift: TShiftState; X, Y: integer); override;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure UpdateTheme;
+    procedure ApplyTheme;
+    procedure SaveThemeToFile(AFileName: string);
+    procedure LoadThemeFromFile(AFileName: string);
+    procedure ApplyDefaultTheme;
+  published
+    property Align;
+    property Cursor;
+    property Enabled;
+    property Font;
+    property ParentColor;
+    property ParentFont;
+    property ParentShowHint;
+    property PopupMenu;
+    property ShowHint;
+    property TabOrder;
+    property TabStop default True;
+    property Anchors;
+    property Constraints;
+    property Visible;
+    property OnClick;
+    property OnDblClick;
+    property OnEnter;
+    property OnExit;
+    property OnMouseMove;
+    property OnMouseDown;
+    property OnMouseUp;
+    property OnMouseWheel;
+    property OnMouseWheelDown;
+    property OnMouseWheelUp;
+    property OnKeyDown;
+    property OnKeyUp;
+    property OnKeyPress;
+    property OnConTextPopup;
+    property TicksCount: integer read FTicksCount write SetTicksCount default 3;
+    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($00D3D3D3);
+    property LineWidth: integer read FLineWidth write SetLineWidth default 8;
+    property OnChangeValue: TNotifyEvent read FOnChangeValue write FOnChangeValue;
+    //Greater value is less sensitive
+    property Sensitivity: integer read FSensitivity write SetSensitivity default 10;
+    property MinAngle: integer read FMinAngle write SetMinAngle default 20;
+    property MaxAngle: integer read FMaxAngle write SetMaxAngle default 340;
+    property FontShadowColor: TColor read FFontShadowColor write SetFFontShadowColor default clBlack;
+    property FontShadowOffsetX: integer read FFontShadowOffsetX write SetFFontShadowOffsetX default 2;
+    property FontShadowOffsetY: integer read FFontShadowOffsetY write SetFFontShadowOffsetY default 2;
+    property FontShadowRadius: integer read FFontSHadowRadius write SetFFontShadowRadius default 4;
+    property DrawText: boolean read FDrawText write SetDrawText default True;
+    property DrawTicks: boolean read FDrawTicks write SetDrawTicks default False;
+    property BackgroundColor: TColor read FBkgColor write SetBkgColor default clBtnFace;
+    property Items: TStrings read FItems write SetItems;
+    property MinTicksAngle: integer read FMinTicksAngle write SetMinTicksAngle default 20;
+    property MaxTicksAngle: integer read FMaxTicksAngle write SetMaxTicksAngle default 340;
+    property PointerSize: integer read FPointerSize write SetPointerSize default 3;
+    property Style: TZStyle read FStyle write SetStyle default zsRaised;
+    property DrawTextPhong: boolean read FDrawTextPhong write SetDrawTextPhong default False;
+    property Theme: TBCLeaTheme read FTheme write SetTheme;
+    property Altitude: integer read FAltitude write SetAltitude default 2;
+  end;
+
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+  RegisterComponents('BGRA Controls', [TBCLeaSelector]);
+end;
+
+{ TBCLeaSelector }
+
+procedure TBCLeaSelector.SetMaxAngle(AValue: integer);
+begin
+  if FMaxAngle = AValue then
+    exit;
+  FMaxAngle := AValue;
+  if FMaxAngle > 350 then
+    FMaxAngle := 350;
+  if FMinAngle > FMaxAngle then
+    FMaxAngle := FMinAngle;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetMinAngle(AValue: integer);
+begin
+  if FMinAngle = AValue then
+    exit;
+  FMinAngle := AValue;
+  if FMinAngle < 10 then
+    FMinAngle := 10;
+  if FMinAngle > FMaxAngle then
+    FMinAngle := FMaxAngle;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetMaxTicksAngle(AValue: integer);
+begin
+  if FMaxTicksAngle = AValue then
+    exit;
+  FMaxTicksAngle := AValue;
+  if FMaxTicksAngle > 350 then
+    FMaxTicksAngle := 350;
+  if FMinTicksAngle > FMaxTicksAngle then
+    FMaxTicksAngle := FMinTicksAngle;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetMinTicksAngle(AValue: integer);
+begin
+  if FMinTicksAngle = AValue then
+    exit;
+  FMinTicksAngle := AValue;
+  if FMinTicksAngle < 10 then
+    FMinTicksAngle := 10;
+  if FMinTicksAngle > FMaxTicksAngle then
+    FMinTicksAngle := FMaxTicksAngle;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetSensitivity(AValue: integer);
+begin
+  if FSensitivity = AValue then
+    exit;
+  if AValue <> 0 then
+    FSensitivity := AValue
+  else
+    FSensitivity := 10;
+end;
+
+procedure TBCLeaSelector.SetLineBkgColor(AValue: TColor);
+begin
+  if FLineBkgColor = AValue then
+    Exit;
+  FLineBkgColor := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetLineColor(AValue: TColor);
+begin
+  if FLineColor = AValue then
+    Exit;
+  FLineColor := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetTicksCount(AValue: integer);
+begin
+  if FTicksCount = AValue then
+    exit;
+  if FTicksCount < 2 then
+    exit;
+  FTicksCount := AValue;
+  if FItems.Count < FTicksCount then
+  begin
+    while FItems.Count <= FTicksCount do
+      FItems.Add('Item ' + IntToStr(FItems.Count + 1));
+  end;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetValue(AValue: integer);
+begin
+  if FValue = AValue then
+    exit;
+  FValue := AValue;
+  if FValue < 1 then
+    FValue := 1;
+  if FValue > FTicksCount then
+    FValue := FTicksCount;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetPointerSize(AValue: integer);
+begin
+  if FPointerSize = AValue then
+    exit;
+  FPointerSize := AValue;
+  if FPointerSize < 1 then
+    FPointerSize := 1;
+  if FPointerSize > 10 then
+    FPointerSize := 10;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetLineWidth(AValue: integer);
+begin
+  if FLineWidth = AValue then exit;
+  FLineWidth := AValue;
+  if Visible then Redraw;
+end;
+
+procedure TBCLeaSelector.SetEnabled(Value: boolean);
+begin
+  inherited SetEnabled(Value);
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetVisible(Value: boolean);
+begin
+  inherited SetVisible(Value);
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.Paint;
+begin
+  inherited Paint;
+  Redraw;
+end;
+
+procedure TBCLeaSelector.Redraw;
+const
+  pi15 = pi * 1.5;
+var
+  TextBmp: TBGRABitmap;
+  TextStr: string;
+  EffectiveSize: integer;
+  EffectiveLineWidth: single;
+  //a, da,
+  r: single;
+  RMinAngle, RMaxAngle, RMinTicksAngle, RMaxTicksAngle, RAngle: single;
+  Blur: TBGRABitmap;
+  Mask, Mask2: TBGRABitmap;
+  Phong: TPhongShading;
+  ScaledPhongSize: int64;
+
+  procedure DoDrawArc(a, b: single; c: TColor);
+  begin
+    FBitmap.Canvas2D.strokeStyle(c);
+    FBitmap.Canvas2D.beginPath;
+    FBitmap.Canvas2D.arc(0, 0, r, a, b, False);
+    FBitmap.Canvas2D.stroke;
+  end;
+
+  procedure DoDrawTicks(a, b: single; c: TColor);
+  begin
+    FBitmap.Canvas2D.strokeStyle(c);
+    FBitmap.Canvas2D.lineWidth := 5;
+    FBitmap.Canvas2D.beginPath;
+    FBitmap.Canvas2D.lineTo(0 - a, 0 - b);
+    FBitmap.Canvas2D.lineTo(5 - a, -2 - b);
+    FBitmap.Canvas2D.lineTo(5 - a, 2 - b);
+    FBitmap.Canvas2D.lineTo(0 - a, 0 - b);
+    FBitmap.Canvas2D.stroke;
+  end;
+
+begin
+  FBitmap.SetSize(Width, Height);
+  FBitmap.Fill(FBkgColor);
+
+  if Width < Height then
+    EffectiveSize := Width
+  else
+    EffectiveSize := Height;
+
+  if EffectiveSize < 2 then exit;
+
+
+  FBitmap.Canvas2D.resetTransform;
+  FBitmap.Canvas2D.translate(FBitmap.Width / 2, FBitmap.Height / 2);
+  FBitmap.Canvas2D.rotate(pi15);
+
+  if FLineWidth = 0 then
+    EffectiveLineWidth := EffectiveSize / 12
+  else
+    EffectiveLineWidth := FLineWidth;
+  r := (EffectiveSize - EffectiveLineWidth) / 2;
+
+  FBitmap.Canvas2D.lineWidth := EffectiveLineWidth;
+
+  RMinAngle := (180 + FMinAngle) * pi / 180;
+  RMaxAngle := ((180 + FMaxAngle) * pi / 180) - RMinAngle;
+
+  RMinTicksAngle := (180 + FMinTicksAngle) * pi / 180;
+  RMaxTicksAngle := ((180 + FMaxTicksAngle) * pi / 180) - RMinTicksAngle;
+
+  FBitmap.Canvas2D.lineCapLCL := pecRound;
+  // background line
+  if FLineBkgColor <> clNone then
+    DoDrawArc(RMinAngle, (RMaxAngle + RMinAngle), FLineBkgColor);
+
+  RAngle := (RMaxTicksAngle / (FTicksCount + FOffset)) * ((FValue + FOffset) - ((FTicksCount + FOffset) / 2));
+
+  if Enabled then
+  begin
+    if FValue >= 0 then
+      DoDrawArc(RAngle - FPointerSize / 100, RAngle + FPointerSize / 100, FLineColor);
+  end
+  else
+    DoDrawArc(RAngle - FPointerSize / 100, RAngle + FPointerSize / 100, clGray);
+
+  if FDrawText and FDrawTextPhong then
+  begin
+    if FItems.Count >= FValue then
+      TextStr := FItems[FValue]
+    else
+      TextStr := 'NaN';
+    TextBmp := TextShadow(EffectiveSize, EffectiveSize, TextStr, Font.Height,
+      Font.Color, FontShadowColor, FontShadowOFfsetX,
+      FontShadowOffsetY, FontShadowRadius, Font.Style, Font.Name) as TBGRABitmap;
+    FBitmap.PutImage(0, 0, TextBmp, dmDrawWithTransparency);
+    TextBmp.Free;
+  end;
+
+  if FDrawTicks then
+    DoDrawTicks(-(FBitmap.Width / 2 - 5), 0, clBlack);
+
+  if (FStyle = zsRaised) or (FStyle = zsLowered) then
+  begin
+    ScaledPhongSize := round(EffectiveLineWidth / 2);
+    Mask := FBitmap.FilterGrayscale as TBGRABitmap;
+    if FStyle = zsRaised then
+      Mask.Negative;
+    Blur := Mask.FilterBlurRadial(ScaledPhongSize, ScaledPhongSize, rbFast) as TBGRABitmap;
+    Blur.FillMask(0, 0, Mask, BGRAPixelTransparent, dmSet);
+    Mask.Free;
+
+    Phong := TPhongShading.Create;
+    if Assigned(FTheme) then
+    begin
+      Phong.AmbientFactor := FAmbientFactor;
+      Phong.SpecularIndex := FSpecularIndex;
+      Phong.LightDestFactor := FLightDestFactor;
+      Phong.LightPosition := Point(FLightPositionX, FLightPositionY);
+      Phong.LightPositionZ := FLightPositionZ;
+      Phong.LightSourceIntensity := FLightSourceIntensity;
+      Phong.LightSourceDistanceTerm := FLightSourceDistanceTerm;
+      Phong.LightSourceDistanceFactor := FLightSourceDistanceFactor;
+      Phong.NegativeDiffusionFactor := FNegativeDiffusionFactor;
+      Phong.SpecularFactor := FSpecularFactor;
+      Phong.DiffusionFactor := FDiffusionFactor;
+      Phong.DiffuseSaturation := FDiffuseSaturation;
+      Phong.LightColor := FLightColor;
+    end;
+    Phong.Draw(FBitmap, Blur, FAltitude, 0, 0, FBitmap);
+    Phong.Free;
+    Blur.Free;
+
+    Mask := TBGRABitmap.Create(EffectiveSize, EffectiveSize, BGRABlack);
+    Mask.FillEllipseAntialias(EffectiveSize div 2, EffectiveSize div 2, EffectiveSize div 2, EffectiveSize div 2, BGRAWhite);
+    Mask2 := TBGRABitmap.Create(EffectiveSize, EffectiveSize, ColorToBGRA(ColorToRGB(FBkgColor)));
+    Mask2.PutImage(0, 0, FBitmap, dmSet);
+    Mask2.ApplyMask(Mask);
+    Mask.Free;
+    FBitmap.Fill(FBkgColor);
+    FBitmap.PutImage(0, 0, Mask2, dmDrawWithTransparency);
+    Mask2.Free;
+  end;
+
+  if FDrawText and not FDrawTextPhong then
+  begin
+    if FItems.Count >= FValue then
+      TextStr := FItems[FValue]
+    else
+      TextStr := 'NaN';
+    TextBmp := TextShadow(EffectiveSize, EffectiveSize, TextStr, Font.Height,
+      Font.Color, FontShadowColor, FontShadowOFfsetX,
+      FontShadowOffsetY, FontShadowRadius, Font.Style, Font.Name) as TBGRABitmap;
+    FBitmap.PutImage(0, 0, TextBmp, dmDrawWithTransparency);
+    TextBmp.Free;
+  end;
+
+  FBitmap.Draw(Canvas, 0, 0, True);
+end;
+
+constructor TBCLeaSelector.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+
+  with GetControlClassDefaultSize do
+    SetInitialBounds(0, 0, 100, 100);
+  FTicksCount := 2;
+  FOffset := 0;
+  FMinAngle := 20;
+  FMaxAngle := 340;
+  FMinTicksAngle := 150;
+  FMaxTicksAngle := 210;
+  FValue := 0;
+  FDeltaPos := 0;
+  FSensitivity := 10;
+  FDrawText := True;
+  FDrawTicks := False;
+  FBitmap := TBGRABitmap.Create(Width, Height, FBkgColor);
+  FItems := TStringList.Create;
+  FItems.Add('Item 1');
+  FItems.Add('Item 2');
+  FItems.Add('Item 3');
+  TStringList(FItems).OnChange := @ItemsChanged;
+  Font.Color := clBlack;
+  Font.Height := 20;
+  ApplyDefaultTheme;
+end;
+
+destructor TBCLeaSelector.Destroy;
+begin
+  FreeAndNil(FBitmap);
+  TStringList(FItems).OnChange := nil;
+  FreeAndNil(FItems);
+  inherited Destroy;
+end;
+
+procedure TBCLeaSelector.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseDown(Button, Shift, X, Y);
+  if Button = mbLeft then
+  begin
+    FDeltaPos := ((ClientHeight / FSensitivity) - (Y / FSensitivity)) * (FTicksCount / ClientHeight);
+    FSettingVerticalPos := True;
+  end;
+end;
+
+procedure TBCLeaSelector.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseUp(Button, Shift, X, Y);
+  if Button = mbLeft then
+    FSettingVerticalPos := False;
+end;
+
+procedure TBCLeaSelector.MouseMove(Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseMove(Shift, X, Y);
+  if FSettingVerticalPos then
+    UpdateVerticalPos(X, Y);
+end;
+
+procedure TBCLeaSelector.UpdateVerticalPos(X, Y: integer);
+var
+  FPreviousPos: single;
+  FCurrPos: single;
+begin
+  FPreviousPos := FVerticalPos;
+  FCurrPos := ((ClientHeight / FSensitivity) - (Y / FSensitivity)) * (FTicksCount / ClientHeight);
+
+  FVerticalPos := FVerticalPos - FDeltaPos + FCurrPos;
+  if FVerticalPos < 0 then FVerticalPos := 0;
+  if FVerticalPos > FTicksCount then FVerticalPos := FTicksCount;
+
+  FValue := round(FVerticalPos);
+  if FValue < 0 then
+    FValue := 0;
+  if FValue > FTicksCount then
+    FValue := FTicksCount;
+
+  Redraw;
+  if (FPreviousPos <> FVerticalPos) and Assigned(FOnChangeValue) then
+    FOnChangeValue(Self);
+end;
+
+procedure TBCLeaSelector.SetFFontShadowColor(AValue: TColor);
+begin
+  if FFontShadowColor = AValue then
+    Exit;
+  FFontShadowColor := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetDrawText(AValue: boolean);
+begin
+  if FDrawText = AValue then Exit;
+  FDrawText := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetFFontShadowOffsetX(AValue: integer);
+begin
+  if FFontShadowOffsetX = AValue then
+    Exit;
+  FFontShadowOffsetX := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetFFontShadowOffsetY(AValue: integer);
+begin
+  if FFontShadowOffsetY = AValue then
+    Exit;
+  FFontShadowOffsetY := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetFFontShadowRadius(AValue: integer);
+begin
+  if FFontSHadowRadius = AValue then
+    Exit;
+  FFontSHadowRadius := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetAltitude(AValue: integer);
+begin
+  if FAltitude = AValue then
+    Exit;
+  FAltitude := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetBkgColor(AValue: TColor);
+begin
+  if FBkgColor = AValue then
+    Exit;
+  FBkgColor := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetDrawTicks(AValue: boolean);
+begin
+  if FDrawTicks = AValue then
+    Exit;
+  FDrawTicks := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetStyle(AValue: TZStyle);
+begin
+  if FStyle = AValue then
+    Exit;
+  FStyle := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetDrawTextPhong(AValue: boolean);
+begin
+  if FDrawTextPhong = AValue then
+    Exit;
+  FDrawTextPhong := AValue;
+  Invalidate;
+end;
+
+procedure TBCLeaSelector.SetItems(const Value: TStrings);
+var
+  i: integer;
+begin
+  FItems.Clear;
+  for i := 0 to FTicksCount do
+  begin
+    if i < Value.Count then
+      FItems.Add(Value[i])
+    else
+      FItems.Add(' ');
+  end;
+  ItemsChanged(self);
+end;
+
+procedure TBCLeaSelector.ItemsChanged(Sender: TObject);
+begin
+  Invalidate;
+  if Assigned(FOnChangeValue) then FOnChangeValue(self);
+end;
+
+procedure TBCLeaSelector.SetTheme(AValue: TBCLeaTheme);
+begin
+  if FTheme = AValue then
+    Exit;
+  if Assigned(FTheme) then
+    FTheme := nil;
+  FTheme := AValue;
+  ApplyTheme;
+end;
+
+procedure TBCLeaSelector.UpdateTheme;
+begin
+  if Assigned(FTheme) then
+  begin
+    FTheme.SEL_LineWidth := FLineWidth;
+    FTheme.SEL_LineColor := FLineColor;
+    FTheme.SEL_LineBkgColor := FLineBkgColor;
+    FTheme.SEL_BkgColor := FBkgColor;
+    FTheme.SEL_FontShadowColor := FFontShadowColor;
+    FTheme.SEL_FontShadowOffsetX := FFontShadowOffsetX;
+    FTheme.SEL_FontShadowOffsetY := FFontShadowOffsetY;
+    FTheme.SEL_FontShadowRadius := FFontShadowRadius;
+    FTheme.SEL_PointerSize := FPointerSize;
+    FTheme.SEL_Style := FStyle;
+    FTheme.SEL_DrawTextPhong := FDrawTextPhong;
+    FTheme.SEL_Altitude := FAltitude;
+  end;
+end;
+
+procedure TBCLeaSelector.ApplyTheme;
+begin
+  if Assigned(FTheme) then
+  begin
+    FLineWidth := FTheme.SEL_LineWidth;
+    FLineColor := FTheme.SEL_LineColor;
+    FLineBkgColor := FTheme.SEL_LineBkgColor;
+    FBkgColor := FTheme.SEL_BkgColor;
+    FFontShadowColor := FTheme.SEL_FontShadowColor;
+    FFontShadowOffsetX := FTheme.SEL_FontShadowOffsetX;
+    FFontShadowOffsetY := FTheme.SEL_FontShadowOffsetY;
+    FFontShadowRadius := FTheme.SEL_FontShadowRadius;
+    FPointerSize := FTheme.SEL_PointerSize;
+    FStyle := FTheme.SEL_Style;
+    FDrawTextPhong := FTheme.SEL_DrawTextPhong;
+    FAltitude := FTheme.SEL_Altitude;
+
+    FLightSourceIntensity := FTheme.COM_LightSourceIntensity;
+    FLightSourceDistanceTerm := FTheme.COM_LightSourceDistanceTerm;
+    FLightSourceDistanceFactor := FTheme.COM_LightSourceDistanceFactor;
+    FLightDestFactor := FTheme.COM_LightDestFactor;
+    FLightColor := FTheme.COM_LightColor;
+    FSpecularFactor := FTheme.COM_SpecularFactor;
+    FSpecularIndex := FTheme.COM_SpecularIndex;
+    FAmbientFactor := FTheme.COM_AmbientFactor;
+    FDiffusionFactor := FTheme.COM_DiffusionFactor;
+    FNegativeDiffusionFactor := FTheme.COM_NegativeDiffusionFactor;
+    FDiffuseSaturation := FTheme.COM_DiffuseSaturation;
+    FLightPositionX := FTheme.COM_LightPositionX;
+    FLightPositionY := FTheme.COM_LightPositionY;
+    FLightPositionZ := FTheme.COM_LightPositionZ;
+    Invalidate;
+  end
+  else
+  begin
+    ApplyDefaultTheme;
+  end;
+end;
+
+procedure TBCLeaSelector.SaveThemeToFile(AFileName: string);
+begin
+  if Assigned(FTheme) then
+    FTheme.SaveThemeToFile(AFileName);
+end;
+
+procedure TBCLeaSelector.LoadThemeFromFile(AFileName: string);
+begin
+  if Assigned(FTheme) then
+    FTheme.LoadThemeFromFile(AFileName);
+end;
+
+procedure TBCLeaSelector.ApplyDefaultTheme;
+begin
+  FLineWidth := 8;
+  FLineColor := TColor($009E5A00);
+  FLineBkgColor := TColor($00D3D3D3);
+  FBkgColor := clBtnFace;
+  FFontShadowColor := clBlack;
+  FFontShadowOffsetX := 2;
+  FFontShadowOffsetY := 2;
+  FFontShadowRadius := 4;
+  FPointerSize := 3;
+  FStyle := zsRaised;
+  FDrawTextPhong := False;
+  FAltitude := 2;
+
+  FAmbientFactor := 0.3;
+  FSpecularIndex := 10;
+  FSpecularFactor := 0.6;
+  FLightDestFactor := 1;
+  FLightPositionX := -100;
+  FLightPositionY := -100;
+  FLightPositionZ := 100;
+  FLightSourceIntensity := 500;
+  FLightSourceDistanceTerm := 150;
+  FLightSourceDistanceFactor := 1;
+  FNegativeDiffusionFactor := 0.1;
+  FLightColor := clWhite;
+  FDiffuseSaturation := False;
+  FDiffusionFactor := 0.9;
+end;
+
+end.

+ 2191 - 0
bcleatheme.pas

@@ -0,0 +1,2191 @@
+{
+ *****************************************************************************
+  See the file COPYING.modifiedLGPL.txt, included in this distribution,
+  for details about the license.
+ *****************************************************************************
+
+ Author: Boban Spasic
+ Credits to: alpine from Lazarus forum
+}
+
+unit BCLeaTheme;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
+  laz2_dom, laz2_xmlwrite, laz2_xmlread, StrUtils, LCLIntf,
+  BGRABitmapTypes, BGRABitmap, BGRAGradients, BCLeaTypes;
+
+type
+  TBCLeaThemeCommon = class(TPersistent)
+  public
+    //Common
+    FLightSourceIntensity: single;
+    FLightSourceDistanceTerm: single;
+    FLightSourceDistanceFactor: single;
+    FLightDestFactor: single;
+    FLightColor: TColor;
+    FSpecularFactor: single;
+    FSpecularIndex: single;
+    FAmbientFactor: single;
+    FDiffusionFactor: single;
+    FNegativeDiffusionFactor: single;
+    FDiffuseSaturation: boolean;
+    FLightPositionX: integer;
+    FLightPositionY: integer;
+    FLightPositionZ: integer;
+  end;
+
+  TBCLeaThemeLCD = class(TPersistent)
+  public
+    //BLCDDisplay
+    FFrameColor: TColor;
+    FBoardColor: TColor;
+    FDotColorOn: TColor;
+    FFrameStyle: TZStyle;
+    FFrameHeight: integer;
+    FFrameAltitude: integer;
+    FFrameSize: integer;
+    FDotShape: TDotShape;
+    FDotSize: integer;
+    FDotsSpace: integer;
+    FDotBlend: boolean;
+    FDotBlendOperation: TBlendOperation;
+    FDotBlur: boolean;
+    FDotBlurRadius: single;
+    FBoardShadow: TBoardShadow;
+  end;
+
+  TBCLeaThemeLED = class(TPersistent)
+  public
+    //BCLeaLED
+    FColorOn: TColor;
+    FColorOff: TColor;
+    FBkgColor: TColor;
+    FStyle: TZStyle;
+    FSize: integer;
+    FAltitude: integer;
+  end;
+
+  TBCLeaThemeQLED = class(TPersistent)
+  public
+    //BCLeaQLED
+    FColorOn: TColor;
+    FColorOff: TColor;
+    FBkgColor: TColor;
+    FStyle: TZStyle;
+    FSize: integer;
+    FAltitude: integer;
+    FRounding: integer;
+  end;
+
+  TBCLeaThemeSelector = class(TPersistent)
+  public
+    //BSelector
+    FLineColor: TColor;
+    FLineBkgColor: TColor;
+    FLineWidth: integer;
+    FFontShadowColor: TColor;
+    FFontShadowOffsetX: integer;
+    FFontShadowOffsetY: integer;
+    FFontShadowRadius: integer;
+    FBkgColor: TColor;
+    FPointerSize: integer;
+    FStyle: TZStyle;
+    FDrawTextPhong: boolean;
+    FAltitude: integer;
+  end;
+
+  TBCLeaThemeRingSlider = class(TPersistent)
+  public
+    //BRingSlider
+    FLineColor: TColor;
+    FLineBkgColor: TColor;
+    FLineWidth: integer;
+    FFontShadowColor: TColor;
+    FFontShadowOffsetX: integer;
+    FFontShadowOffsetY: integer;
+    FFontShadowRadius: integer;
+    FBkgColor: TColor;
+    FPointerSize: integer;
+    FPointerColor: TColor;
+    FStyle: TZStyle;
+    FDrawTextPhong: boolean;
+    FAltitude: integer;
+  end;
+
+  TBCLeaTheme = class(TComponent)
+  private
+    FThemeSetCommon: TBCLeaThemeCommon;
+    FThemeSetLCD: TBCLeaThemeLCD;
+    FThemeSetLED: TBCLeaThemeLED;
+    FThemeSetSelector: TBCLeaThemeSelector;
+    FThemeSetRingSlider: TBCLeaThemeRingSlider;
+    FThemeSetQLED: TBCLeaThemeQLED;
+    FOnChange: TNotifyEvent;
+    procedure DoChange;
+    //Common
+    procedure SetLightSourceIntensity(const AValue: single);
+    procedure SetLightSourceDistanceTerm(const AValue: single);
+    procedure SetLightSourceDistanceFactor(const AValue: single);
+    procedure SetLightDestFactor(const AValue: single);
+    procedure SetLightColor(const AValue: TColor);
+    procedure SetSpecularFactor(const AValue: single);
+    procedure SetSpecularIndex(const AValue: single);
+    procedure SetAmbientFactor(const AValue: single);
+    procedure SetDiffusionFactor(const AValue: single);
+    procedure SetNegativeDiffusionFactor(const AValue: single);
+    procedure SetDiffuseSaturation(const AValue: boolean);
+    procedure SetLightPositionX(const AValue: integer);
+    procedure SetLightPositionY(const AValue: integer);
+    procedure SetLightPositionZ(const AValue: integer);
+    function GetLightSourceIntensity: single;
+    function GetLightSourceDistanceTerm: single;
+    function GetLightSourceDistanceFactor: single;
+    function GetLightDestFactor: single;
+    function GetLightColor: TColor;
+    function GetSpecularFactor: single;
+    function GetSpecularIndex: single;
+    function GetAmbientFactor: single;
+    function GetDiffusionFactor: single;
+    function GetNegativeDiffusionFactor: single;
+    function GetDiffuseSaturation: boolean;
+    function GetLightPositionX: integer;
+    function GetLightPositionY: integer;
+    function GetLightPositionZ: integer;
+    //BLCDDisplay
+    procedure SetBLCDFrameColor(const AValue: TColor);
+    procedure SetBLCDBoardColor(const AValue: TColor);
+    procedure SetBLCDDotColorOn(const AValue: TColor);
+    procedure SetBLCDFrameAltitude(const AValue: integer);
+    procedure SetBLCDFrameHeight(const AValue: integer);
+    procedure SetBLCDFrameSize(const AValue: integer);
+    procedure SetBLCDFrameStyle(const AValue: TZStyle);
+    procedure SetBLCDDotShape(const AValue: TDotShape);
+    procedure SetBLCDDotSize(const AValue: integer);
+    procedure SetBLCDDotsSpace(const AValue: integer);
+    procedure SetBLCDDotBlend(const AValue: boolean);
+    procedure SetBLCDDotBlendOperation(const AValue: TBlendOperation);
+    procedure SetBLCDDotBlur(const AValue: boolean);
+    procedure SetBLCDDotBlurRadius(const AValue: single);
+    procedure SetBLCDBoardShadow(const AValue: TBoardShadow);
+    function GetBLCDFrameColor: TColor;
+    function GetBLCDBoardColor: TColor;
+    function GetBLCDDotColorOn: TColor;
+    function GetBLCDFrameAltitude: integer;
+    function GetBLCDFrameHeight: integer;
+    function GetBLCDFrameSize: integer;
+    function GetBLCDFrameStyle: TZStyle;
+    function GetBLCDDotShape: TDotShape;
+    function GetBLCDDotSize: integer;
+    function GetBLCDDotsSpace: integer;
+    function GetBLCDDotBlend: boolean;
+    function GetBLCDDotBlendOperation: TBlendOperation;
+    function GetBLCDDotBlur: boolean;
+    function GetBLCDDotBlurRadius: single;
+    function GetBLCDBoardShadow: TBoardShadow;
+    //BCLeaLED
+    procedure SetBCLeaLEDColorOn(AValue: TColor);
+    procedure SetBCLeaLEDColorOff(AValue: TColor);
+    procedure SetBCLeaLEDBkgColor(AValue: TColor);
+    procedure SetBCLeaLEDStyle(AValue: TZStyle);
+    procedure SetBCLeaLEDSize(AValue: integer);
+    procedure SetBCLeaLEDAltitude(AValue: integer);
+    function GetBCLeaLEDColorOn: TColor;
+    function GetBCLeaLEDColorOff: TColor;
+    function GetBCLeaLEDBkgColor: TColor;
+    function GetBCLeaLEDStyle: TZStyle;
+    function GetBCLeaLEDSize: integer;
+    function GetBCLeaLEDAltitude: integer;
+    //BCLeaQLED
+    procedure SetBCLeaQLEDColorOn(AValue: TColor);
+    procedure SetBCLeaQLEDColorOff(AValue: TColor);
+    procedure SetBCLeaQLEDBkgColor(AValue: TColor);
+    procedure SetBCLeaQLEDStyle(AValue: TZStyle);
+    procedure SetBCLeaQLEDSize(AValue: integer);
+    procedure SetBCLeaQLEDAltitude(AValue: integer);
+    procedure SetBCLeaQLEDRounding(AValue: integer);
+    function GetBCLeaQLEDColorOn: TColor;
+    function GetBCLeaQLEDColorOff: TColor;
+    function GetBCLeaQLEDBkgColor: TColor;
+    function GetBCLeaQLEDStyle: TZStyle;
+    function GetBCLeaQLEDSize: integer;
+    function GetBCLeaQLEDAltitude: integer;
+    function GetBCLeaQLEDRounding: integer;
+    //BSelector
+    procedure SetBSELLineColor(AValue: TColor);
+    procedure SetBSELLineBkgColor(AValue: TColor);
+    procedure SetBSELLineWidth(AValue: integer);
+    procedure SetBSELFontShadowColor(AValue: TColor);
+    procedure SetBSELFontShadowOffsetX(AValue: integer);
+    procedure SetBSELFontShadowOffsetY(AValue: integer);
+    procedure SetBSELFontShadowRadius(AValue: integer);
+    procedure SetBSELBkgColor(AValue: TColor);
+    procedure SetBSELPointerSize(AValue: integer);
+    procedure SetBSELStyle(AValue: TZStyle);
+    procedure SetBSELDrawTextPhong(AValue: boolean);
+    procedure SetBSELAltitude(AValue: integer);
+    function GetBSELLineColor: TColor;
+    function GetBSELLineBkgColor: TColor;
+    function GetBSELLineWidth: integer;
+    function GetBSELFontShadowColor: TColor;
+    function GetBSELFontShadowOffsetX: integer;
+    function GetBSELFontShadowOffsetY: integer;
+    function GetBSELFontShadowRadius: integer;
+    function GetBSELBkgColor: TColor;
+    function GetBSELPointerSize: integer;
+    function GetBSELStyle: TZStyle;
+    function GetBSELDrawTextPhong: boolean;
+    function GetBSELAltitude: integer;
+    //BRingSlider
+    procedure SetBRSLineColor(AValue: TColor);
+    procedure SetBRSLineBkgColor(AValue: TColor);
+    procedure SetBRSLineWidth(AValue: integer);
+    procedure SetBRSFontShadowColor(AValue: TColor);
+    procedure SetBRSFontShadowOffsetX(AValue: integer);
+    procedure SetBRSFontShadowOffsetY(AValue: integer);
+    procedure SetBRSFontShadowRadius(AValue: integer);
+    procedure SetBRSBkgColor(AValue: TColor);
+    procedure SetBRSPointerSize(AValue: integer);
+    procedure SetBRSPointerColor(AValue: TColor);
+    procedure SetBRSStyle(AValue: TZStyle);
+    procedure SetBRSDrawTextPhong(AValue: boolean);
+    procedure SetBRSAltitude(AValue: integer);
+    function GetBRSLineColor: TColor;
+    function GetBRSLineBkgColor: TColor;
+    function GetBRSLineWidth: integer;
+    function GetBRSFontShadowColor: TColor;
+    function GetBRSFontShadowOffsetX: integer;
+    function GetBRSFontShadowOffsetY: integer;
+    function GetBRSFontShadowRadius: integer;
+    function GetBRSBkgColor: TColor;
+    function GetBRSPointerSize: integer;
+    function GetBRSPointerColor: TColor;
+    function GetBRSStyle: TZStyle;
+    function GetBRSDrawTextPhong: boolean;
+    function GetBRSAltitude: integer;
+  protected
+
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    //load default theme
+    procedure Initialize;
+    //do not use direct, please use the procedures of the parent component
+    procedure SaveThemeToFile(AFileName: string);
+    //do not use direct, please use the procedures of the parent component
+    procedure LoadThemeFromFile(AFileName: string);
+  published
+    property OnChange: TNotifyEvent read FOnChange write FOnChange;
+    //BLCDDisplay
+    property LCD_FrameColor: TColor read GetBLCDFrameColor write SetBLCDFrameColor default clBtnFace;
+    property LCD_BoardColor: TColor read GetBLCDBoardColor write SetBLCDBoardColor default clBlack;
+    property LCD_DotColorOn: TColor read GetBLCDDotColorOn write SetBLCDDotColorOn default clSkyBlue;
+    property LCD_FrameAltitude: integer read GetBLCDFrameAltitude write SetBLCDFrameAltitude default 2;
+    property LCD_FrameHeight: integer read GetBLCDFrameHeight write SetBLCDFrameHeight default 8;
+    property LCD_FrameSize: integer read GetBLCDFrameSize write SetBLCDFrameSize default 8;
+    property LCD_FrameStyle: TZStyle read GetBLCDFrameStyle write SetBLCDFrameStyle default zsRaised;
+    property LCD_DotShape: TDotShape read GetBLCDDotShape write SetBLCDDotShape default stSquare;
+    property LCD_DotSize: integer read GetBLCDDotSize write SetBLCDDotSize default 4;
+    property LCD_DotsSpace: integer read GetBLCDDotsSpace write SetBLCDDotsSpace default 1;
+    property LCD_DotBlend: boolean read GetBLCDDotBlend write SetBLCDDotBlend default False;
+    property LCD_DotBlendOperation: TBlendOperation read GetBLCDDotBlendOperation write SetBLCDDotBlendOperation default boGlow;
+    property LCD_DotBlur: boolean read GetBLCDDotBlur write SetBLCDDotBlur default False;
+    property LCD_DotBlurRadius: single read GetBLCDDotBlurRadius write SetBLCDDotBlurRadius default 0.8;
+    property LCD_BoardShadow: TBoardShadow read GetBLCDBoardShadow write SetBLCDBoardShadow default bsFrame;
+    property COM_LightSourceIntensity: single read GetLightSourceIntensity write SetLightSourceIntensity default 500;
+    property COM_LightSourceDistanceTerm: single read GetLightSourceDistanceTerm write SetLightSourceDistanceTerm default 150;
+    property COM_LightSourceDistanceFactor: single read GetLightSourceDistanceFactor write SetLightSourceDistanceFactor default 1.0;
+    property COM_LightDestFactor: single read GetLightDestFactor write SetLightDestFactor default 1.0;
+    property COM_LightColor: TColor read GetLightColor write SetLightColor default clWhite;
+    property COM_SpecularFactor: single read GetSpecularFactor write SetSpecularFactor default 0.6;
+    property COM_SpecularIndex: single read GetSpecularIndex write SetSpecularIndex default 10;
+    property COM_AmbientFactor: single read GetAmbientFactor write SetAmbientFactor default 0.3;
+    property COM_DiffusionFactor: single read GetDiffusionFactor write SetDiffusionFactor default 0.9;
+    property COM_NegativeDiffusionFactor: single read GetNegativeDiffusionFactor write SetNegativeDiffusionFactor default 0.1;
+    property COM_DiffuseSaturation: boolean read GetDiffuseSaturation write SetDiffuseSaturation default False;
+    property COM_LightPositionX: integer read GetLightPositionX write SetLightPositionX default -100;
+    property COM_LightPositionY: integer read GetLightPositionY write SetLightPositionY default -100;
+    property COM_LightPositionZ: integer read GetLightPositionZ write SetLightPositionZ default 100;
+    property LED_ColorOn: TColor read GetBCLeaLEDColorOn write SetBCLeaLEDColorOn default TColor($00FF9C15);
+    property LED_ColorOff: TColor read GetBCLeaLEDColorOff write SetBCLeaLEDColorOff default TColor($009E5A00);
+    property LED_BkgColor: TColor read GetBCLeaLEDBkgColor write SetBCLeaLEDBkgColor default clBtnFace;
+    property LED_Style: TZStyle read GetBCLeaLEDStyle write SetBCLeaLEDStyle default zsRaised;
+    property LED_Size: integer read GetBCLeaLEDSize write SetBCLeaLEDSize default 15;
+    property LED_Altitude: integer read GetBCLeaLEDAltitude write SetBCLeaLEDAltitude default 2;
+    property QLED_ColorOn: TColor read GetBCLeaQLEDColorOn write SetBCLeaQLEDColorOn default TColor($00FF9C15);
+    property QLED_ColorOff: TColor read GetBCLeaQLEDColorOff write SetBCLeaQLEDColorOff default TColor($009E5A00);
+    property QLED_BkgColor: TColor read GetBCLeaQLEDBkgColor write SetBCLeaQLEDBkgColor default clBtnFace;
+    property QLED_Style: TZStyle read GetBCLeaQLEDStyle write SetBCLeaQLEDStyle default zsRaised;
+    property QLED_Size: integer read GetBCLeaQLEDSize write SetBCLeaQLEDSize default 20;
+    property QLED_Altitude: integer read GetBCLeaQLEDAltitude write SetBCLeaQLEDAltitude default 2;
+    property QLED_Rounding: integer read GetBCLeaQLEDRounding write SetBCLeaQLEDRounding default 3;
+    property SEL_LineColor: TColor read GetBSELLineColor write SetBSELLineColor default TColor($009E5A00);
+    property SEL_LineBkgColor: TColor read GetBSELLineBkgColor write SetBSELLineBkgColor default TColor($00D3D3D3);
+    property SEL_LineWidth: integer read GetBSELLineWidth write SetBSELLineWidth default 0;
+    property SEL_FontShadowColor: TColor read GetBSELFontShadowColor write SetBSELFontShadowColor default clBlack;
+    property SEL_FontShadowOffsetX: integer read GetBSELFontShadowOffsetX write SetBSELFontShadowOffsetX default 2;
+    property SEL_FontShadowOffsetY: integer read GetBSELFontShadowOffsetY write SetBSELFontShadowOffsetY default 2;
+    property SEL_FontShadowRadius: integer read GetBSELFontShadowRadius write SetBSELFontShadowRadius default 4;
+    property SEL_BkgColor: TColor read GetBSELBkgColor write SetBSELBkgColor default clBtnFace;
+    property SEL_PointerSize: integer read GetBSELPointerSize write SetBSELPointerSize default 2;
+    property SEL_Style: TZStyle read GetBSELStyle write SetBSELStyle default zsRaised;
+    property SEL_DrawTextPhong: boolean read GetBSELDrawTextPhong write SetBSELDrawTextPhong default False;
+    property SEL_Altitude: integer read GetBSELAltitude write SetBSELAltitude default 2;
+    property RS_LineColor: TColor read GetBRSLineColor write SetBRSLineColor default TColor($009E5A00);
+    property RS_LineBkgColor: TColor read GetBRSLineBkgColor write SetBRSLineBkgColor default TColor($00D3D3D3);
+    property RS_LineWidth: integer read GetBRSLineWidth write SetBRSLineWidth default 0;
+    property RS_FontShadowColor: TColor read GetBRSFontShadowColor write SetBRSFontShadowColor default clBlack;
+    property RS_FontShadowOffsetX: integer read GetBRSFontShadowOffsetX write SetBRSFontShadowOffsetX default 2;
+    property RS_FontShadowOffsetY: integer read GetBRSFontShadowOffsetY write SetBRSFontShadowOffsetY default 2;
+    property RS_FontShadowRadius: integer read GetBRSFontShadowRadius write SetBRSFontShadowRadius default 4;
+    property RS_BkgColor: TColor read GetBRSBkgColor write SetBRSBkgColor default clBtnFace;
+    property RS_PointerSize: integer read GetBRSPointerSize write SetBRSPointerSize default 2;
+    property RS_PointerColor: TColor read GetBRSPointerColor write SetBRSPointerColor default TColor($00FF9C15);
+    property RS_Style: TZStyle read GetBRSStyle write SetBRSStyle default zsRaised;
+    property RS_DrawTextPhong: boolean read GetBRSDrawTextPhong write SetBRSDrawTextPhong default False;
+    property RS_Altitude: integer read GetBRSAltitude write SetBRSAltitude default 2;
+  end;
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+  RegisterComponents('BGRA Controls', [TBCLeaTheme]);
+end;
+
+constructor TBCLeaTheme.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+  FThemeSetCommon := TBCLeaThemeCommon.Create;
+  FThemeSetLCD := TBCLeaThemeLCD.Create;
+  FThemeSetLED := TBCLeaThemeLED.Create;
+  FThemeSetSelector := TBCLeaThemeSelector.Create;
+  FThemeSetRingSlider := TBCLeaThemeRingSlider.Create;
+  FThemeSetQLED := TBCLeaThemeQLED.Create;
+  Initialize;
+end;
+
+destructor TBCLeaTheme.Destroy;
+begin
+  FreeAndNil(FThemeSetCommon);
+  FreeAndNil(FThemeSetLCD);
+  FreeAndNil(FThemeSetLED);
+  FreeAndNil(FThemeSetSelector);
+  FreeAndNil(FThemeSetRingSlider);
+  FreeAndNil(FThemeSetQLED);
+  inherited Destroy;
+end;
+
+procedure TBCLeaTheme.DoChange;
+begin
+  if Assigned(FOnChange) then FOnChange(self);
+end;
+
+function TBCLeaTheme.GetLightSourceIntensity: single;
+begin
+  Result := FThemeSetCommon.FLightSourceIntensity;
+end;
+
+function TBCLeaTheme.GetLightSourceDistanceTerm: single;
+begin
+  Result := FThemeSetCommon.FLightSourceDistanceTerm;
+end;
+
+function TBCLeaTheme.GetLightSourceDistanceFactor: single;
+begin
+  Result := FThemeSetCommon.FLightSourceDistanceFactor;
+end;
+
+function TBCLeaTheme.GetLightDestFactor: single;
+begin
+  Result := FThemeSetCommon.FLightDestFactor;
+end;
+
+function TBCLeaTheme.GetLightColor: TColor;
+begin
+  Result := FThemeSetCommon.FLightColor;
+end;
+
+function TBCLeaTheme.GetSpecularFactor: single;
+begin
+  Result := FThemeSetCommon.FSpecularFactor;
+end;
+
+function TBCLeaTheme.GetSpecularIndex: single;
+begin
+  Result := FThemeSetCommon.FSpecularIndex;
+end;
+
+function TBCLeaTheme.GetAmbientFactor: single;
+begin
+  Result := FThemeSetCommon.FAmbientFactor;
+end;
+
+function TBCLeaTheme.GetDiffusionFactor: single;
+begin
+  Result := FThemeSetCommon.FDiffusionFactor;
+end;
+
+function TBCLeaTheme.GetNegativeDiffusionFactor: single;
+begin
+  Result := FThemeSetCommon.FNegativeDiffusionFactor;
+end;
+
+function TBCLeaTheme.GetDiffuseSaturation: boolean;
+begin
+  Result := FThemeSetCommon.FDiffuseSaturation;
+end;
+
+function TBCLeaTheme.GetLightPositionX: integer;
+begin
+  Result := FThemeSetCommon.FLightPositionX;
+end;
+
+function TBCLeaTheme.GetLightPositionY: integer;
+begin
+  Result := FThemeSetCommon.FLightPositionY;
+end;
+
+function TBCLeaTheme.GetLightPositionZ: integer;
+begin
+  Result := FThemeSetCommon.FLightPositionZ;
+end;
+
+function TBCLeaTheme.GetBLCDFrameColor: TColor;
+begin
+  Result := FThemeSetLCD.FFrameColor;
+end;
+
+function TBCLeaTheme.GetBLCDBoardColor: TColor;
+begin
+  Result := FThemeSetLCD.FBoardColor;
+end;
+
+function TBCLeaTheme.GetBLCDDotColorOn: TColor;
+begin
+  Result := FThemeSetLCD.FDotColorOn;
+end;
+
+function TBCLeaTheme.GetBLCDFrameAltitude: integer;
+begin
+  Result := FThemeSetLCD.FFrameAltitude;
+end;
+
+function TBCLeaTheme.GetBLCDFrameHeight: integer;
+begin
+  Result := FThemeSetLCD.FFrameHeight;
+end;
+
+function TBCLeaTheme.GetBLCDFrameSize: integer;
+begin
+  Result := FThemeSetLCD.FFrameSize;
+end;
+
+function TBCLeaTheme.GetBLCDFrameStyle: TZStyle;
+begin
+  Result := FThemeSetLCD.FFrameStyle;
+end;
+
+function TBCLeaTheme.GetBLCDDotShape: TDotShape;
+begin
+  Result := FThemeSetLCD.FDotShape;
+end;
+
+function TBCLeaTheme.GetBLCDDotSize: integer;
+begin
+  Result := FThemeSetLCD.FDotSize;
+end;
+
+function TBCLeaTheme.GetBLCDDotsSpace: integer;
+begin
+  Result := FThemeSetLCD.FDotsSpace;
+end;
+
+function TBCLeaTheme.GetBLCDDotBlend: boolean;
+begin
+  Result := FThemeSetLCD.FDotBlend;
+end;
+
+function TBCLeaTheme.GetBLCDDotBlendOperation: TBlendOperation;
+begin
+  Result := FThemeSetLCD.FDotBlendOperation;
+end;
+
+function TBCLeaTheme.GetBLCDDotBlur: boolean;
+begin
+  Result := FThemeSetLCD.FDotBlur;
+end;
+
+function TBCLeaTheme.GetBLCDDotBlurRadius: single;
+begin
+  Result := FThemeSetLCD.FDotBlurRadius;
+end;
+
+function TBCLeaTheme.GetBLCDBoardShadow: TBoardShadow;
+begin
+  Result := FThemeSetLCD.FBoardShadow;
+end;
+
+function TBCLeaTheme.GetBCLeaLEDColorOn: TColor;
+begin
+  Result := FThemeSetLED.FColorOn;
+end;
+
+function TBCLeaTheme.GetBCLeaLEDColorOff: TColor;
+begin
+  Result := FThemeSetLED.FColorOff;
+end;
+
+function TBCLeaTheme.GetBCLeaLEDBkgColor: TColor;
+begin
+  Result := FThemeSetLED.FBkgColor;
+end;
+
+function TBCLeaTheme.GetBCLeaLEDStyle: TZStyle;
+begin
+  Result := FThemeSetLED.FStyle;
+end;
+
+function TBCLeaTheme.GetBCLeaLEDSize: integer;
+begin
+  Result := FThemeSetLED.FSize;
+end;
+
+function TBCLeaTheme.GetBCLeaLEDAltitude: integer;
+begin
+  Result := FThemeSetLED.FAltitude;
+end;
+
+function TBCLeaTheme.GetBCLeaQLEDColorOn: TColor;
+begin
+  Result := FThemeSetQLED.FColorOn;
+end;
+
+function TBCLeaTheme.GetBCLeaQLEDColorOff: TColor;
+begin
+  Result := FThemeSetQLED.FColorOff;
+end;
+
+function TBCLeaTheme.GetBCLeaQLEDBkgColor: TColor;
+begin
+  Result := FThemeSetQLED.FBkgColor;
+end;
+
+function TBCLeaTheme.GetBCLeaQLEDStyle: TZStyle;
+begin
+  Result := FThemeSetQLED.FStyle;
+end;
+
+function TBCLeaTheme.GetBCLeaQLEDSize: integer;
+begin
+  Result := FThemeSetQLED.FSize;
+end;
+
+function TBCLeaTheme.GetBCLeaQLEDAltitude: integer;
+begin
+  Result := FThemeSetQLED.FAltitude;
+end;
+
+function TBCLeaTheme.GetBCLeaQLEDRounding: integer;
+begin
+  Result := FThemeSetQLED.FRounding;
+end;
+
+function TBCLeaTheme.GetBSELLineColor: TColor;
+begin
+  Result := FThemeSetSelector.FLineColor;
+end;
+
+function TBCLeaTheme.GetBSELLineBkgColor: TColor;
+begin
+  Result := FThemeSetSelector.FLineBkgColor;
+end;
+
+function TBCLeaTheme.GetBSELLineWidth: integer;
+begin
+  Result := FThemeSetSelector.FLineWidth;
+end;
+
+function TBCLeaTheme.GetBSELFontShadowColor: TColor;
+begin
+  Result := FThemeSetSelector.FFontShadowColor;
+end;
+
+function TBCLeaTheme.GetBSELFontShadowOffsetX: integer;
+begin
+  Result := FThemeSetSelector.FFontShadowOffsetX;
+end;
+
+function TBCLeaTheme.GetBSELFontShadowOffsetY: integer;
+begin
+  Result := FThemeSetSelector.FFontShadowOffsetY;
+end;
+
+function TBCLeaTheme.GetBSELFontShadowRadius: integer;
+begin
+  Result := FThemeSetSelector.FFontShadowRadius;
+end;
+
+function TBCLeaTheme.GetBSELBkgColor: TColor;
+begin
+  Result := FThemeSetSelector.FBkgColor;
+end;
+
+function TBCLeaTheme.GetBSELPointerSize: integer;
+begin
+  Result := FThemeSetSelector.FPointerSize;
+end;
+
+function TBCLeaTheme.GetBSELStyle: TZStyle;
+begin
+  Result := FThemeSetSelector.FStyle;
+end;
+
+function TBCLeaTheme.GetBSELDrawTextPhong: boolean;
+begin
+  Result := FThemeSetSelector.FDrawTextPhong;
+end;
+
+function TBCLeaTheme.GetBSELAltitude: integer;
+begin
+  Result := FThemeSetSelector.FAltitude;
+end;
+
+function TBCLeaTheme.GetBRSLineColor: TColor;
+begin
+  Result := FThemeSetRingSlider.FLineColor;
+end;
+
+function TBCLeaTheme.GetBRSLineBkgColor: TColor;
+begin
+  Result := FThemeSetRingSlider.FLineBkgColor;
+end;
+
+function TBCLeaTheme.GetBRSLineWidth: integer;
+begin
+  Result := FThemeSetRingSlider.FLineWidth;
+end;
+
+function TBCLeaTheme.GetBRSFontShadowColor: TColor;
+begin
+  Result := FThemeSetRingSlider.FFontShadowColor;
+end;
+
+function TBCLeaTheme.GetBRSFontShadowOffsetX: integer;
+begin
+  Result := FThemeSetRingSlider.FFontShadowOffsetX;
+end;
+
+function TBCLeaTheme.GetBRSFontShadowOffsetY: integer;
+begin
+  Result := FThemeSetRingSlider.FFontShadowOffsetY;
+end;
+
+function TBCLeaTheme.GetBRSFontShadowRadius: integer;
+begin
+  Result := FThemeSetRingSlider.FFontShadowRadius;
+end;
+
+function TBCLeaTheme.GetBRSBkgColor: TColor;
+begin
+  Result := FThemeSetRingSlider.FBkgColor;
+end;
+
+function TBCLeaTheme.GetBRSPointerSize: integer;
+begin
+  Result := FThemeSetRingSlider.FPointerSize;
+end;
+
+function TBCLeaTheme.GetBRSPointerColor: TColor;
+begin
+  Result := FThemeSetRingSlider.FPointerColor;
+end;
+
+function TBCLeaTheme.GetBRSStyle: TZStyle;
+begin
+  Result := FThemeSetRingSlider.FStyle;
+end;
+
+function TBCLeaTheme.GetBRSDrawTextPhong: boolean;
+begin
+  Result := FThemeSetRingSlider.FDrawTextPhong;
+end;
+
+function TBCLeaTheme.GetBRSAltitude: integer;
+begin
+  Result := FThemeSetRingSlider.FAltitude;
+end;
+//============================================================================
+procedure TBCLeaTheme.SetLightSourceIntensity(const AValue: single);
+begin
+  if AValue = FThemeSetCommon.FLightSourceIntensity then
+    Exit;
+  FThemeSetCommon.FLightSourceIntensity := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetLightSourceDistanceTerm(const AValue: single);
+begin
+  if AValue = FThemeSetCommon.FLightSourceDistanceTerm then
+    Exit;
+  FThemeSetCommon.FLightSourceDistanceTerm := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetLightSourceDistanceFactor(const AValue: single);
+begin
+  if AValue = FThemeSetCommon.FLightSourceDistanceFactor then
+    Exit;
+  FThemeSetCommon.FLightSourceDistanceFactor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetLightDestFactor(const AValue: single);
+begin
+  if AValue = FThemeSetCommon.FLightDestFactor then
+    Exit;
+  FThemeSetCommon.FLightDestFactor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetLightColor(const AValue: TColor);
+begin
+  if AValue = FThemeSetCommon.FLightColor then
+    Exit;
+  FThemeSetCommon.FLightColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetSpecularFactor(const AValue: single);
+begin
+  if AValue = FThemeSetCommon.FSpecularFactor then
+    Exit;
+  FThemeSetCommon.FSpecularFactor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetSpecularIndex(const AValue: single);
+begin
+  if AValue = FThemeSetCommon.FSpecularIndex then
+    Exit;
+  FThemeSetCommon.FSpecularIndex := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetAmbientFactor(const AValue: single);
+begin
+  if AValue = FThemeSetCommon.FAmbientFactor then
+    Exit;
+  FThemeSetCommon.FAmbientFactor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetDiffusionFactor(const AValue: single);
+begin
+  if AValue = FThemeSetCommon.FDiffusionFactor then
+    Exit;
+  FThemeSetCommon.FDiffusionFactor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetNegativeDiffusionFactor(const AValue: single);
+begin
+  if AValue = FThemeSetCommon.FNegativeDiffusionFactor then
+    Exit;
+  FThemeSetCommon.FNegativeDiffusionFactor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetDiffuseSaturation(const AValue: boolean);
+begin
+  if AValue = FThemeSetCommon.FDiffuseSaturation then
+    Exit;
+  FThemeSetCommon.FDiffuseSaturation := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetLightPositionX(const AValue: integer);
+begin
+  if AValue = FThemeSetCommon.FLightPositionX then
+    Exit;
+  FThemeSetCommon.FLightPositionX := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetLightPositionY(const AValue: integer);
+begin
+  if AValue = FThemeSetCommon.FLightPositionY then
+    Exit;
+  FThemeSetCommon.FLightPositionY := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetLightPositionZ(const AValue: integer);
+begin
+  if AValue = FThemeSetCommon.FLightPositionZ then
+    Exit;
+  FThemeSetCommon.FLightPositionZ := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDFrameColor(const AValue: TColor);
+begin
+  if AValue = FThemeSetLCD.FFrameColor then
+    Exit;
+  FThemeSetLCD.FFrameColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDBoardColor(const AValue: TColor);
+begin
+  if AValue = FThemeSetLCD.FBoardColor then
+    Exit;
+  FThemeSetLCD.FBoardColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDDotColorOn(const AValue: TColor);
+begin
+  if AValue = FThemeSetLCD.FDotColorOn then
+    Exit;
+  FThemeSetLCD.FDotColorOn := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDFrameAltitude(const AValue: integer);
+begin
+  if AValue = FThemeSetLCD.FFrameAltitude then
+    Exit;
+  FThemeSetLCD.FFrameAltitude := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDFrameHeight(const AValue: integer);
+begin
+  if AValue = FThemeSetLCD.FFrameHeight then
+    Exit;
+  FThemeSetLCD.FFrameHeight := AValue;
+  if FThemeSetLCD.FFrameSize < FThemeSetLCD.FFrameHeight then FThemeSetLCD.FFrameSize := FThemeSetLCD.FFrameHeight;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDFrameSize(const AValue: integer);
+begin
+  if AValue = FThemeSetLCD.FFrameSize then
+    Exit;
+  FThemeSetLCD.FFrameSize := AValue;
+  if FThemeSetLCD.FFrameSize < FThemeSetLCD.FFrameHeight then FThemeSetLCD.FFrameHeight := FThemeSetLCD.FFrameSize;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDFrameStyle(const AValue: TZStyle);
+begin
+  if AValue = FThemeSetLCD.FFrameStyle then
+    Exit;
+  FThemeSetLCD.FFrameStyle := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDDotShape(const AValue: TDotShape);
+begin
+  if AValue = FThemeSetLCD.FDotShape then
+    Exit;
+  FThemeSetLCD.FDotShape := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDDotSize(const AValue: integer);
+begin
+  if AValue = FThemeSetLCD.FDotSize then
+    Exit;
+  FThemeSetLCD.FDotSize := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDDotsSpace(const AValue: integer);
+begin
+  if AValue = FThemeSetLCD.FDotsSpace then
+    Exit;
+  FThemeSetLCD.FDotsSpace := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDDotBlend(const AValue: boolean);
+begin
+  if AValue = FThemeSetLCD.FDotBlend then
+    exit;
+  FThemeSetLCD.FDotBlend := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDDotBlendOperation(const AValue: TBlendOperation);
+begin
+  if AValue = FThemeSetLCD.FDotBlendOperation then
+    exit;
+  FThemeSetLCD.FDotBlendOperation := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDDotBlur(const AValue: boolean);
+begin
+  if AValue = FThemeSetLCD.FDotBlur then
+    exit;
+  FThemeSetLCD.FDotBlur := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDDotBlurRadius(const AValue: single);
+begin
+  if AValue = FThemeSetLCD.FDotBlurRadius then
+    exit;
+  FThemeSetLCD.FDotBlurRadius := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBLCDBoardShadow(const AValue: TBoardShadow);
+begin
+  if AValue = FThemeSetLCD.FBoardShadow then
+    exit;
+  FThemeSetLCD.FBoardShadow := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaLEDColorOn(AValue: TColor);
+begin
+  if AValue = FThemeSetLED.FColorOn then
+    exit;
+  FThemeSetLED.FColorOn := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaLEDColorOff(AValue: TColor);
+begin
+  if AValue = FThemeSetLED.FColorOff then
+    exit;
+  FThemeSetLED.FColorOff := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaLEDBkgColor(AValue: TColor);
+begin
+  if AValue = FThemeSetLED.FColorOn then
+    exit;
+  FThemeSetLED.FBkgColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaLEDStyle(AValue: TZStyle);
+begin
+  if AValue = FThemeSetLED.FStyle then
+    exit;
+  FThemeSetLED.FStyle := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaLEDSize(AValue: integer);
+begin
+  if AValue = FThemeSetLED.FSize then
+    exit;
+  FThemeSetLED.FSize := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaLEDAltitude(AValue: integer);
+begin
+  if AValue = FThemeSetLED.FAltitude then
+    exit;
+  FThemeSetLED.FAltitude := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaQLEDColorOn(AValue: TColor);
+begin
+  if AValue = FThemeSetQLED.FColorOn then
+    exit;
+  FThemeSetQLED.FColorOn := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaQLEDColorOff(AValue: TColor);
+begin
+  if AValue = FThemeSetQLED.FColorOff then
+    exit;
+  FThemeSetQLED.FColorOff := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaQLEDBkgColor(AValue: TColor);
+begin
+  if AValue = FThemeSetQLED.FColorOn then
+    exit;
+  FThemeSetQLED.FBkgColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaQLEDStyle(AValue: TZStyle);
+begin
+  if AValue = FThemeSetQLED.FStyle then
+    exit;
+  FThemeSetQLED.FStyle := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaQLEDSize(AValue: integer);
+begin
+  if AValue = FThemeSetQLED.FSize then
+    exit;
+  FThemeSetQLED.FSize := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaQLEDAltitude(AValue: integer);
+begin
+  if AValue = FThemeSetQLED.FAltitude then
+    exit;
+  FThemeSetQLED.FAltitude := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBCLeaQLEDRounding(AValue: integer);
+begin
+  if AValue = FThemeSetQLED.FRounding then
+    exit;
+  FThemeSetQLED.FRounding := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBSELLineColor(AValue: TColor);
+begin
+  if AValue = FThemeSetSelector.FLineColor then
+    exit;
+  FThemeSetSelector.FLineColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBSELLineBkgColor(AValue: TColor);
+begin
+  if AValue = FThemeSetSelector.FLineBkgColor then
+    exit;
+  FThemeSetSelector.FLineBkgColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBSELLineWidth(AValue: integer);
+begin
+  if AValue = FThemeSetSelector.FLineWidth then
+    exit;
+  FThemeSetSelector.FLineWidth := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBSELFontShadowColor(AValue: TColor);
+begin
+  if AValue = FThemeSetSelector.FFontShadowColor then
+    exit;
+  FThemeSetSelector.FFontShadowColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBSELFontShadowOffsetX(AValue: integer);
+begin
+  if AValue = FThemeSetSelector.FFontShadowOffsetX then
+    exit;
+  FThemeSetSelector.FFontShadowOffsetX := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBSELFontShadowOffsetY(AValue: integer);
+begin
+  if AValue = FThemeSetSelector.FFontShadowOffsetY then
+    exit;
+  FThemeSetSelector.FFontShadowOffsetY := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBSELFontShadowRadius(AValue: integer);
+begin
+  if AValue = FThemeSetSelector.FFontShadowRadius then
+    exit;
+  FThemeSetSelector.FFontShadowRadius := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBSELBkgColor(AValue: TColor);
+begin
+  if AValue = FThemeSetSelector.FBkgColor then
+    exit;
+  FThemeSetSelector.FBkgColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBSELPointerSize(AValue: integer);
+begin
+  if AValue = FThemeSetSelector.FPointerSize then
+    exit;
+  FThemeSetSelector.FPointerSize := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBSELStyle(AValue: TZStyle);
+begin
+  if AValue = FThemeSetSelector.FStyle then
+    exit;
+  FThemeSetSelector.FStyle := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBSELDrawTextPhong(AValue: boolean);
+begin
+  if AValue = FThemeSetSelector.FDrawTextPhong then
+    exit;
+  FThemeSetSelector.FDrawTextPhong := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBSELAltitude(AValue: integer);
+begin
+  if AValue = FThemeSetSelector.FAltitude then
+    exit;
+  FThemeSetSelector.FAltitude := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSLineColor(AValue: TColor);
+begin
+  if AValue = FThemeSetRingSlider.FLineColor then
+    exit;
+  FThemeSetRingSlider.FLineColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSLineBkgColor(AValue: TColor);
+begin
+  if AValue = FThemeSetRingSlider.FLineBkgColor then
+    exit;
+  FThemeSetRingSlider.FLineBkgColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSLineWidth(AValue: integer);
+begin
+  if AValue = FThemeSetRingSlider.FLineWidth then
+    exit;
+  FThemeSetRingSlider.FLineWidth := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSFontShadowColor(AValue: TColor);
+begin
+  if AValue = FThemeSetRingSlider.FFontShadowColor then
+    exit;
+  FThemeSetRingSlider.FFontShadowColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSFontShadowOffsetX(AValue: integer);
+begin
+  if AValue = FThemeSetRingSlider.FFontShadowOffsetX then
+    exit;
+  FThemeSetRingSlider.FFontShadowOffsetX := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSFontShadowOffsetY(AValue: integer);
+begin
+  if AValue = FThemeSetRingSlider.FFontShadowOffsetY then
+    exit;
+  FThemeSetRingSlider.FFontShadowOffsetY := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSFontShadowRadius(AValue: integer);
+begin
+  if AValue = FThemeSetRingSlider.FFontShadowRadius then
+    exit;
+  FThemeSetRingSlider.FFontShadowRadius := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSBkgColor(AValue: TColor);
+begin
+  if AValue = FThemeSetRingSlider.FBkgColor then
+    exit;
+  FThemeSetRingSlider.FBkgColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSPointerSize(AValue: integer);
+begin
+  if AValue = FThemeSetRingSlider.FPointerSize then
+    exit;
+  FThemeSetRingSlider.FPointerSize := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSPointerColor(AValue: TColor);
+begin
+  if AValue = FThemeSetRingSlider.FPointerColor then
+    exit;
+  FThemeSetRingSlider.FPointerColor := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSStyle(AValue: TZStyle);
+begin
+  if AValue = FThemeSetRingSlider.FStyle then
+    exit;
+  FThemeSetRingSlider.FStyle := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSDrawTextPhong(AValue: boolean);
+begin
+  if AValue = FThemeSetRingSlider.FDrawTextPhong then
+    exit;
+  FThemeSetRingSlider.FDrawTextPhong := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SetBRSAltitude(AValue: integer);
+begin
+  if AValue = FThemeSetRingSlider.FAltitude then
+    exit;
+  FThemeSetRingSlider.FAltitude := AValue;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.Initialize;
+begin
+  FThemeSetCommon.FAmbientFactor := 0.3;
+  FThemeSetCommon.FSpecularIndex := 10;
+  FThemeSetCommon.FSpecularFactor := 0.6;
+  FThemeSetCommon.FLightDestFactor := 1;
+  FThemeSetCommon.FLightPositionX := -100;
+  FThemeSetCommon.FLightPositionY := -100;
+  FThemeSetCommon.FLightPositionZ := 100;
+  FThemeSetCommon.FLightSourceIntensity := 500;
+  FThemeSetCommon.FLightSourceDistanceTerm := 150;
+  FThemeSetCommon.FLightSourceDistanceFactor := 1;
+  FThemeSetCommon.FNegativeDiffusionFactor := 0.1;
+  FThemeSetCommon.FLightColor := clWhite;
+  FThemeSetCommon.FDiffuseSaturation := False;
+  FThemeSetCommon.FDiffusionFactor := 0.9;
+  FThemeSetLCD.FDotSize := 4;
+  FThemeSetLCD.FDotsSpace := 1;
+  FThemeSetLCD.FDotShape := stRound;
+  FThemeSetLCD.FDotBlend := False;
+  FThemeSetLCD.FDotBlendOperation := boGlow;
+  FThemeSetLCD.FDotBlur := False;
+  FThemeSetLCD.FDotBlurRadius := 0.8;
+  FThemeSetLCD.FFrameSize := 8;
+  FThemeSetLCD.FFrameHeight := 8;
+  FThemeSetLCD.FFrameAltitude := 2;
+  FThemeSetLCD.FFrameStyle := zsRaised;
+  FThemeSetLCD.FBoardShadow := bsFrame;
+  FThemeSetLCD.FFrameColor := clBtnFace;
+  FThemeSetLCD.FBoardColor := clBlack;
+  FThemeSetLCD.FDotColorOn := clSkyBlue;
+  FThemeSetLED.FColorOn := TColor($00FF9C15);
+  FThemeSetLED.FColorOff := TColor($009E5A00);
+  FThemeSetLED.FBkgColor := clBtnFace;
+  FThemeSetLED.FStyle := zsRaised;
+  FThemeSetLED.FSize := 15;
+  FThemeSetLED.FAltitude := 2;
+  FThemeSetSelector.FLineWidth := 8;
+  FThemeSetSelector.FLineColor := TColor($009E5A00);
+  FThemeSetSelector.FLineBkgColor := TColor($00D3D3D3);
+  FThemeSetSelector.FBkgColor := clBtnFace;
+  FThemeSetSelector.FFontShadowColor := clBlack;
+  FThemeSetSelector.FFontShadowOffsetX := 2;
+  FThemeSetSelector.FFontShadowOffsetY := 2;
+  FThemeSetSelector.FFontShadowRadius := 4;
+  FThemeSetSelector.FPointerSize := 3;
+  FThemeSetSelector.FStyle := zsRaised;
+  FThemeSetSelector.FDrawTextPhong := False;
+  FThemeSetSelector.FAltitude := 2;
+  FThemeSetRingSlider.FLineWidth := 8;
+  FThemeSetRingSlider.FLineColor := TColor($009E5A00);
+  FThemeSetRingSlider.FLineBkgColor := TColor($00D3D3D3);
+  FThemeSetRingSlider.FBkgColor := clBtnFace;
+  FThemeSetRingSlider.FFontShadowColor := clBlack;
+  FThemeSetRingSlider.FFontShadowOffsetX := 2;
+  FThemeSetRingSlider.FFontShadowOffsetY := 2;
+  FThemeSetRingSlider.FFontShadowRadius := 4;
+  FThemeSetRingSlider.FPointerSize := 3;
+  FThemeSetRingSlider.FPointerColor := TColor($00FF9C15);
+  FThemeSetRingSlider.FStyle := zsRaised;
+  FThemeSetRingSlider.FDrawTextPhong := False;
+  FThemeSetRingSlider.FAltitude := 2;
+  FThemeSetQLED.FColorOn := TColor($00FF9C15);
+  FThemeSetQLED.FColorOff := TColor($009E5A00);
+  FThemeSetQLED.FBkgColor := clBtnFace;
+  FThemeSetQLED.FStyle := zsRaised;
+  FThemeSetQLED.FSize := 20;
+  FThemeSetQLED.FAltitude := 2;
+  FThemeSetQLED.FRounding := 3;
+end;
+
+procedure TBCLeaTheme.LoadThemeFromFile(AFileName: string);
+var
+  doc: TXMLDocument = nil;
+  rootNode, componentNode, parentNode, node: TDOMNode;
+  nodeName: string;
+  version: string;
+begin
+  try
+    ReadXMLFile(doc, AFileName);
+    rootNode := doc.DocumentElement;
+    if rootNode.NodeName = 'BCLea_Theme' then
+    begin
+      parentNode := rootNode.FirstChild;
+      while Assigned(parentNode) do
+      begin
+        nodeName := parentNode.NodeName;
+        if nodeName = 'Version' then
+        begin
+          node := parentNode.FirstChild;
+          while Assigned(node) do
+          begin
+            nodeName := node.NodeName;
+            if nodeName = 'Version' then
+              Version := node.TextContent;
+            node := node.NextSibling;
+          end;
+        end;
+        parentNode := parentNode.NextSibling;
+      end;
+      if version = '1.0' then
+      begin
+        componentNode := rootNode.FirstChild;
+        while Assigned(componentNode) do
+        begin
+          nodeName := componentNode.NodeName;
+          if nodeName = 'BCLeaLCD' then
+          begin
+            parentNode := componentNode.FirstChild;
+            while Assigned(parentNode) do
+            begin
+              nodeName := parentNode.NodeName;
+              if nodeName = 'Frame' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'Height' then
+                    FThemeSetLCD.FFrameHeight := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'Size' then
+                    FThemeSetLCD.FFrameSize := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'Altitude' then
+                    FThemeSetLCD.FFrameAltitude := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'Style' then
+                    FThemeSetLCD.FFrameStyle := TZStyle(StrToInt(node.TextContent))
+                  else
+                  if nodeName = 'BoardShadow' then
+                    FThemeSetLCD.FBoardShadow := TBoardShadow(StrToInt(node.TextContent));
+                  node := node.NextSibling;
+                end;
+              end
+              else
+              if nodeName = 'Dot' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'Shape' then
+                    FThemeSetLCD.FDotShape := TDotShape(StrToInt(node.TextContent))
+                  else
+                  if nodeName = 'Size' then
+                    FThemeSetLCD.FDotSize := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'Space' then
+                    FThemeSetLCD.FDotsSpace := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'Blured' then
+                    FThemeSetLCD.FDotBlur := StrToBool(node.TextContent)
+                  else
+                  if nodeName = 'BlurRadius' then
+                    FThemeSetLCD.FDotBlurRadius := StrToFloat(node.TextContent)
+                  else
+                  if nodeName = 'Blended' then
+                    FThemeSetLCD.FDotBlend := StrToBool(node.TextContent)
+                  else
+                  if nodeName = 'BlendOperation' then
+                    FThemeSetLCD.FDotBlendOperation := TBlendOperation(StrToInt(node.TextContent));
+                  node := node.NextSibling;
+                end;
+              end
+              else
+              if nodeName = 'Colors' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'Board' then
+                    FThemeSetLCD.FBoardColor := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'Frame' then
+                    FThemeSetLCD.FFrameColor := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'DotOn' then
+                    FThemeSetLCD.FDotColorOn := TColor(Hex2Dec(node.TextContent));
+                  node := node.NextSibling;
+                end;
+              end;
+              parentNode := parentNode.NextSibling;
+            end;
+          end
+          else
+          if nodeName = 'COMMON' then
+          begin
+            parentNode := componentNode.FirstChild;
+            while Assigned(parentNode) do
+            begin
+              nodeName := parentNode.NodeName;
+              if nodeName = 'Light' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'SourceIntensity' then
+                    FThemeSetCommon.FLightSourceIntensity := StrToFloat(node.TextContent)
+                  else
+                  if nodeName = 'SourceDistanceTerm' then
+                    FThemeSetCommon.FLightSourceDistanceTerm := StrToFloat(node.TextContent)
+                  else
+                  if nodeName = 'SourceDistanceFactor' then
+                    FThemeSetCommon.FLightSourceDistanceFactor := StrToFloat(node.TextContent)
+                  else
+                  if nodeName = 'DestFactor' then
+                    FThemeSetCommon.FLightDestFactor := StrToFloat(node.TextContent)
+                  else
+                  if nodeName = 'Color' then
+                    FThemeSetCommon.FLightColor := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'SpecularFacor' then
+                    FThemeSetCommon.FSpecularFactor := StrToFloat(node.TextContent)
+                  else
+                  if nodeName = 'SpecularIndex' then
+                    FThemeSetCommon.FSpecularIndex := StrToFloat(node.TextContent)
+                  else
+                  if nodeName = 'AmbientFactor' then
+                    FThemeSetCommon.FAmbientFactor := StrToFloat(node.TextContent)
+                  else
+                  if nodeName = 'DiffusionFactor' then
+                    FThemeSetCommon.FDiffusionFactor := StrToFloat(node.TextContent)
+                  else
+                  if nodeName = 'NegativeDiffusionFactor' then
+                    FThemeSetCommon.FNegativeDiffusionFactor := StrToFloat(node.TextContent)
+                  else
+                  if nodeName = 'DiffuseSaturation' then
+                    FThemeSetCommon.FDiffuseSaturation := StrToBool(node.TextContent)
+                  else
+                  if nodeName = 'PositionX' then
+                    FThemeSetCommon.FLightPositionX := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'PositionY' then
+                    FThemeSetCommon.FLightPositionY := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'PositionZ' then
+                    FThemeSetCommon.FLightPositionZ := StrToInt(node.TextContent);
+                  node := node.NextSibling;
+                end;
+              end;
+              parentNode := parentNode.NextSibling;
+            end;
+          end
+          else
+          if nodeName = 'BCLeaLED' then
+          begin
+            parentNode := componentNode.FirstChild;
+            while Assigned(parentNode) do
+            begin
+              nodeName := parentNode.NodeName;
+              if nodeName = 'Geometry' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'Style' then
+                    FThemeSetLED.FStyle := TZStyle(StrToInt(node.TextContent))
+                  else
+                  if nodeName = 'Size' then
+                    FThemeSetLED.FSize := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'Altitude' then
+                    FThemeSetLED.FAltitude := StrToInt(node.TextContent);
+                  node := node.NextSibling;
+                end;
+              end
+              else
+              if nodeName = 'Colors' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'ColorOn' then
+                    FThemeSetLED.FColorOn := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'ColorOff' then
+                    FThemeSetLED.FColorOff := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'BkgColor' then
+                    FThemeSetLED.FBkgColor := TColor(Hex2Dec(node.TextContent));
+                  node := node.NextSibling;
+                end;
+              end;
+              parentNode := parentNode.NextSibling;
+            end;
+          end
+          else
+          if nodeName = 'BCLeaQLED' then
+          begin
+            parentNode := componentNode.FirstChild;
+            while Assigned(parentNode) do
+            begin
+              nodeName := parentNode.NodeName;
+              if nodeName = 'Geometry' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'Style' then
+                    FThemeSetQLED.FStyle := TZStyle(StrToInt(node.TextContent))
+                  else
+                  if nodeName = 'Size' then
+                    FThemeSetQLED.FSize := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'Altitude' then
+                    FThemeSetQLED.FAltitude := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'Rounding' then
+                    FThemeSetQLED.FRounding := StrToInt(node.TextContent);
+                  node := node.NextSibling;
+                end;
+              end
+              else
+              if nodeName = 'Colors' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'ColorOn' then
+                    FThemeSetQLED.FColorOn := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'ColorOff' then
+                    FThemeSetQLED.FColorOff := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'BkgColor' then
+                    FThemeSetQLED.FBkgColor := TColor(Hex2Dec(node.TextContent));
+                  node := node.NextSibling;
+                end;
+              end;
+              parentNode := parentNode.NextSibling;
+            end;
+          end
+          else
+          if nodeName = 'BCLeaSelector' then
+          begin
+            parentNode := componentNode.FirstChild;
+            while Assigned(parentNode) do
+            begin
+              nodeName := parentNode.NodeName;
+              if nodeName = 'Geometry' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'Style' then
+                    FThemeSetSelector.FStyle := TZStyle(StrToInt(node.TextContent))
+                  else
+                  if nodeName = 'LineWidth' then
+                    FThemeSetSelector.FLineWidth := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'Altitude' then
+                    FThemeSetSelector.FAltitude := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'PointerSize' then
+                    FThemeSetSelector.FPointerSize := StrToInt(node.TextContent);
+                  node := node.NextSibling;
+                end;
+              end
+              else
+              if nodeName = 'Colors' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'Line' then
+                    FThemeSetSelector.FLineColor := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'LineBkg' then
+                    FThemeSetSelector.FLineBkgColor := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'BkgColor' then
+                    FThemeSetSelector.FBkgColor := TColor(Hex2Dec(node.TextContent));
+                  node := node.NextSibling;
+                end;
+              end
+              else
+              if nodeName = 'Text' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'ShadowColor' then
+                    FThemeSetSelector.FFontShadowColor := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'ShadowOffsetX' then
+                    FThemeSetSelector.FFontShadowOffsetX := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'ShadowOffsetY' then
+                    FThemeSetSelector.FFontShadowOffsetY := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'ShadowRadius' then
+                    FThemeSetSelector.FFontShadowRadius := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'Draw3D' then
+                    FThemeSetSelector.FDrawTextPhong := StrToBool(node.TextContent);
+                  node := node.NextSibling;
+                end;
+              end;
+              parentNode := parentNode.NextSibling;
+            end;
+          end
+          else
+          if nodeName = 'BCLeaRingSlider' then
+          begin
+            parentNode := componentNode.FirstChild;
+            while Assigned(parentNode) do
+            begin
+              nodeName := parentNode.NodeName;
+              if nodeName = 'Geometry' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'Style' then
+                    FThemeSetRingSlider.FStyle := TZStyle(StrToInt(node.TextContent))
+                  else
+                  if nodeName = 'LineWidth' then
+                    FThemeSetRingSlider.FLineWidth := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'Altitude' then
+                    FThemeSetRingSlider.FAltitude := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'PointerSize' then
+                    FThemeSetRingSlider.FPointerSize := StrToInt(node.TextContent);
+                  node := node.NextSibling;
+                end;
+              end
+              else
+              if nodeName = 'Colors' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'Line' then
+                    FThemeSetRingSlider.FLineColor := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'LineBkg' then
+                    FThemeSetRingSlider.FLineBkgColor := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'BkgColor' then
+                    FThemeSetRingSlider.FBkgColor := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'PointerColor' then
+                    FThemeSetRingSlider.FPointerColor := TColor(Hex2Dec(node.TextContent));
+                  node := node.NextSibling;
+                end;
+              end
+              else
+              if nodeName = 'Text' then
+              begin
+                node := parentNode.FirstChild;
+                while Assigned(node) do
+                begin
+                  nodeName := node.NodeName;
+                  if nodeName = 'ShadowColor' then
+                    FThemeSetRingSlider.FFontShadowColor := TColor(Hex2Dec(node.TextContent))
+                  else
+                  if nodeName = 'ShadowOffsetX' then
+                    FThemeSetRingSlider.FFontShadowOffsetX := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'ShadowOffsetY' then
+                    FThemeSetRingSlider.FFontShadowOffsetY := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'ShadowRadius' then
+                    FThemeSetRingSlider.FFontShadowRadius := StrToInt(node.TextContent)
+                  else
+                  if nodeName = 'Draw3D' then
+                    FThemeSetRingSlider.FDrawTextPhong := StrToBool(node.TextContent);
+                  node := node.NextSibling;
+                end;
+              end;
+              parentNode := parentNode.NextSibling;
+            end;
+          end;
+          { here comes the next component
+          if nodeName = 'BLCD' then  }
+          componentNode := componentNode.NextSibling;
+        end;
+      end
+      else
+        raise Exception.Create('Not version 1.0 file');
+    end
+    else
+      raise Exception.Create('Not a BCLea theme file');
+  finally
+    doc.Free;
+  end;
+  DoChange;
+end;
+
+procedure TBCLeaTheme.SaveThemeToFile(AFileName: string);
+var
+  doc: TXMLDocument;
+  rootNode, componentNode, parentNode, node, textNode: TDOMNode;
+begin
+  doc := TXMLDocument.Create;
+  try
+    rootNode := doc.CreateElement('BCLea_Theme');
+    doc.AppendChild(rootNode);
+
+    rootNode := doc.DocumentElement;
+
+    componentNode := doc.CreateElement('Version');
+    rootNode.AppendChild(componentNode);
+
+    node := doc.CreateElement('Version');
+    componentNode.AppendChild(node);
+    textNode := doc.CreateTextNode('1.0');
+    node.AppendChild(textNode);
+
+    //COMMON
+    componentNode := doc.CreateElement('COMMON');
+    rootNode.AppendChild(componentNode);
+
+    parentNode := doc.CreateElement('Light');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('SourceIntensity');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetCommon.FLightSourceIntensity));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('SourceDistanceTerm');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetCommon.FLightSourceDistanceTerm));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('SourceDistanceFactor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetCommon.FLightSourceDistanceFactor));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('DestFactor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetCommon.FLightDestFactor));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Color');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(FThemeSetCommon.FLightColor));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('SpecularFactor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetCommon.FSpecularFactor));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('SpecularIndex');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetCommon.FSpecularIndex));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('AmbientFactor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetCommon.FAmbientFactor));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('DiffusionFactor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetCommon.FDiffusionFactor));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('NegativeDiffusionFactor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetCommon.FNegativeDiffusionFactor));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('DiffuseSaturation');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(BoolToStr(FThemeSetCommon.FDiffuseSaturation));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('PositionX');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetCommon.FLightPositionX));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('PositionY');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetCommon.FLightPositionY));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('PositionZ');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetCommon.FLightPositionZ));
+    node.AppendChild(textNode);
+
+    //BCLeaLCD
+    componentNode := doc.CreateElement('BCLeaLCD');
+    rootNode.AppendChild(componentNode);
+
+    parentNode := doc.CreateElement('Frame');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('Height');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetLCD.FFrameHeight));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Size');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetLCD.FFrameSize));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Altitude');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetLCD.FFrameAltitude));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Style');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(integer(FThemeSetLCD.FFrameStyle)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('BoardShadow');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(integer(FThemeSetLCD.FBoardShadow)));
+    node.AppendChild(textNode);
+
+    parentNode := doc.CreateElement('Dot');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('Shape');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(integer(FThemeSetLCD.FDotShape)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Size');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetLCD.FDotSize));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Space');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetLCD.FDotsSpace));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Blured');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(BoolToStr(FThemeSetLCD.FDotBlur));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('BlurRadius');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(FloatToStr(FThemeSetLCD.FDotBlurRadius));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Blended');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(BoolToStr(FThemeSetLCD.FDotBlend));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('BlendOperation');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(integer(FThemeSetLCD.FDotBlendOperation)));
+    node.AppendChild(textNode);
+
+    parentNode := doc.CreateElement('Colors');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('Board');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetLCD.FBoardColor)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Frame');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetLCD.FFrameColor)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('DotOn');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetLCD.FDotColorOn)));
+    node.AppendChild(textNode);
+
+    //BCLeaLED
+    componentNode := doc.CreateElement('BCLeaLED');
+    rootNode.AppendChild(componentNode);
+
+    parentNode := doc.CreateElement('Geometry');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('Style');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(integer(FThemeSetLED.FStyle)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Size');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetLED.FSize));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Altitude');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetLED.FAltitude));
+    node.AppendChild(textNode);
+
+    parentNode := doc.CreateElement('Colors');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('ColorOn');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetLED.FColorOn)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('ColorOff');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetLED.FColorOff)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('BkgColor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetLED.FBkgColor)));
+    node.AppendChild(textNode);
+
+    //BCLeaQLED
+    componentNode := doc.CreateElement('BCLeaQLED');
+    rootNode.AppendChild(componentNode);
+
+    parentNode := doc.CreateElement('Geometry');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('Style');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(integer(FThemeSetQLED.FStyle)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Size');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetQLED.FSize));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Altitude');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetQLED.FAltitude));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Rounding');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetQLED.FRounding));
+    node.AppendChild(textNode);
+
+    parentNode := doc.CreateElement('Colors');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('ColorOn');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetQLED.FColorOn)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('ColorOff');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetQLED.FColorOff)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('BkgColor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetQLED.FBkgColor)));
+    node.AppendChild(textNode);
+
+    //BCLeaSelector
+    componentNode := doc.CreateElement('BCLeaSelector');
+    rootNode.AppendChild(componentNode);
+
+    parentNode := doc.CreateElement('Geometry');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('Style');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(integer(FThemeSetSelector.FStyle)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('LineWidth');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetSelector.FLineWidth));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Altitude');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetSelector.FAltitude));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('PointerSize');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetSelector.FPointerSize));
+    node.AppendChild(textNode);
+
+    parentNode := doc.CreateElement('Colors');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('Line');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetSelector.FLineColor)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('LineBkg');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetSelector.FLineBkgColor)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('BkgColor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetSelector.FBkgColor)));
+    node.AppendChild(textNode);
+
+    parentNode := doc.CreateElement('Text');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('ShadowColor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetSelector.FFontShadowColor)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('ShadowOffsetX');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetSelector.FFontShadowOffsetX));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('ShadowOffsetY');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetSelector.FFontShadowOffsetY));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('ShadowRadius');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetSelector.FFontShadowRadius));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Draw3D');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(BoolToStr(FThemeSetSelector.FDrawTextPhong));
+    node.AppendChild(textNode);
+
+    //BCLeaRingSlider
+    componentNode := doc.CreateElement('BCLeaRingSlider');
+    rootNode.AppendChild(componentNode);
+
+    parentNode := doc.CreateElement('Geometry');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('Style');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(integer(FThemeSetRingSlider.FStyle)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('LineWidth');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetRingSlider.FLineWidth));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Altitude');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetRingSlider.FAltitude));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('PointerSize');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetRingSlider.FPointerSize));
+    node.AppendChild(textNode);
+
+    parentNode := doc.CreateElement('Colors');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('Line');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetRingSlider.FLineColor)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('LineBkg');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetRingSlider.FLineBkgColor)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('BkgColor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetRingSlider.FBkgColor)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('PointerColor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetRingSlider.FPointerColor)));
+    node.AppendChild(textNode);
+
+    parentNode := doc.CreateElement('Text');
+    componentNode.AppendChild(parentNode);
+
+    node := doc.CreateElement('ShadowColor');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToHex(integer(FThemeSetRingSlider.FFontShadowColor)));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('ShadowOffsetX');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetRingSlider.FFontShadowOffsetX));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('ShadowOffsetY');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetRingSlider.FFontShadowOffsetY));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('ShadowRadius');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(IntToStr(FThemeSetRingSlider.FFontShadowRadius));
+    node.AppendChild(textNode);
+
+    node := doc.CreateElement('Draw3D');
+    parentNode.AppendChild(node);
+    textNode := doc.CreateTextNode(BoolToStr(FThemeSetRingSlider.FDrawTextPhong));
+    node.AppendChild(textNode);
+    WriteXMLFile(doc, AFileName);
+  finally
+    doc.Free;
+  end;
+end;
+
+end.

+ 26 - 0
bcleatypes.pas

@@ -0,0 +1,26 @@
+{
+ *****************************************************************************
+  See the file COPYING.modifiedLGPL.txt, included in this distribution,
+  for details about the license.
+ *****************************************************************************
+
+ Author: Boban Spasic
+}
+
+unit BCLeaTypes;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils;
+
+type
+  TZStyle = (zsFlat, zsLowered, zsRaised);
+  TDotShape = (stSquare, stRound);
+  TBoardShadow = (bsNone, bsOwn, bsFrame);
+
+implementation
+
+end.

+ 36 - 1
bgracontrols.lpk

@@ -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" Release="1" Build="4"/>
-    <Files Count="70">
+    <Files Count="77">
       <Item1>
         <Filename Value="atshapelinebgra.pas"/>
         <HasRegisterProc Value="True"/>
@@ -376,6 +376,41 @@
         <Filename Value="bgrasvgimagelistform/bgrasvgimagelistform.pas"/>
         <UnitName Value="bgrasvgimagelistform"/>
       </Item70>
+      <Item71>
+        <Filename Value="bclealcddisplay.pas"/>
+        <HasRegisterProc Value="True"/>
+        <UnitName Value="BCLeaLCDDisplay"/>
+      </Item71>
+      <Item72>
+        <Filename Value="bclealed.pas"/>
+        <HasRegisterProc Value="True"/>
+        <UnitName Value="BCLeaLED"/>
+      </Item72>
+      <Item73>
+        <Filename Value="bcleaqled.pas"/>
+        <HasRegisterProc Value="True"/>
+        <UnitName Value="BCLeaQLED"/>
+      </Item73>
+      <Item74>
+        <Filename Value="bclearingslider.pas"/>
+        <HasRegisterProc Value="True"/>
+        <UnitName Value="BCLeaRingSlider"/>
+      </Item74>
+      <Item75>
+        <Filename Value="bcleaselector.pas"/>
+        <HasRegisterProc Value="True"/>
+        <UnitName Value="BCLeaSelector"/>
+      </Item75>
+      <Item76>
+        <Filename Value="bcleatheme.pas"/>
+        <HasRegisterProc Value="True"/>
+        <UnitName Value="BCLeaTheme"/>
+      </Item76>
+      <Item77>
+        <Filename Value="bclealcddisplay_editorregister.pas"/>
+        <HasRegisterProc Value="True"/>
+        <UnitName Value="BCLeaLCDDisplay_EditorRegister"/>
+      </Item77>
     </Files>
     <CompatibilityMode Value="True"/>
     <LazDoc Paths="fpdoc"/>

+ 10 - 1
bgracontrols.pas

@@ -23,7 +23,8 @@ uses
   BGRAThemeCheckBox, BGRAThemeRadioButton, BGRAVirtualScreen, 
   ColorSpeedButton, DTAnalogClock, DTAnalogCommon, DTAnalogGauge, 
   dtthemedclock, dtthemedgauge, MaterialColors, bgrasvgimagelistform, 
-  LazarusPackageIntf;
+  BCLeaLCDDisplay, BCLeaLED, BCLeaQLED, BCLeaRingSlider, BCLeaSelector, 
+  BCLeaTheme, BCLeaLCDDisplay_EditorRegister, LazarusPackageIntf;
 
 implementation
 
@@ -81,6 +82,14 @@ begin
   RegisterUnit('DTAnalogGauge', @DTAnalogGauge.Register);
   RegisterUnit('dtthemedclock', @dtthemedclock.Register);
   RegisterUnit('dtthemedgauge', @dtthemedgauge.Register);
+  RegisterUnit('BCLeaLCDDisplay', @BCLeaLCDDisplay.Register);
+  RegisterUnit('BCLeaLED', @BCLeaLED.Register);
+  RegisterUnit('BCLeaQLED', @BCLeaQLED.Register);
+  RegisterUnit('BCLeaRingSlider', @BCLeaRingSlider.Register);
+  RegisterUnit('BCLeaSelector', @BCLeaSelector.Register);
+  RegisterUnit('BCLeaTheme', @BCLeaTheme.Register);
+  RegisterUnit('BCLeaLCDDisplay_EditorRegister', 
+    @BCLeaLCDDisplay_EditorRegister.Register);
 end;
 
 initialization

BIN
images/TBCLeaLCDDisplay.png


BIN
images/TBCLeaLCDDisplay_150.png


BIN
images/TBCLeaLCDDisplay_200.png


BIN
images/TBCLeaLED.png


BIN
images/TBCLeaLED_150.png


BIN
images/TBCLeaLED_200.png


BIN
images/TBCLeaQLED.png


BIN
images/TBCLeaQLED_150.png


BIN
images/TBCLeaQLED_200.png


BIN
images/TBCLeaRingSlider.png


BIN
images/TBCLeaRingSlider_150.png


BIN
images/TBCLeaRingSlider_200.png


BIN
images/TBCLeaSelector.png


BIN
images/TBCLeaSelector_150.png


BIN
images/TBCLeaSelector_200.png


BIN
images/TBCLeaTheme.png


BIN
images/TBCLeaTheme_150.png


BIN
images/TBCLeaTheme_200.png


BIN
images/bgracontrols_images.res


+ 19 - 1
images/bgracontrols_images_list.txt

@@ -108,4 +108,22 @@ tbcfluentprogressring_150.png
 tbcfluentprogressring_200.png
 tbcfluentslider.png
 tbcfluentslider_150.png
-tbcfluentslider_200.png
+tbcfluentslider_200.png
+TBCLeaLCDDisplay.png
+TBCLeaLCDDisplay_150.png
+TBCLeaLCDDisplay_200.png
+TBCLeaLED.png
+TBCLeaLED_150.png
+TBCLeaLED_200.png
+TBCLeaQLED.png
+TBCLeaQLED_150.png
+TBCLeaQLED_200.png
+TBCLeaRingSlider.png
+TBCLeaRingSlider_150.png
+TBCLeaRingSlider_200.png
+TBCLeaSelector.png
+TBCLeaSelector_150.png
+TBCLeaSelector_200.png
+TBCLeaTheme.png
+TBCLeaTheme_150.png
+TBCLeaTheme_200.png

+ 113 - 0
styles/lea_alien.bclea

@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BCLea_Theme>
+  <Version>
+    <Version>1.0</Version>
+  </Version>
+  <COMMON>
+    <Light>
+      <SourceIntensity>300</SourceIntensity>
+      <SourceDistanceTerm>150</SourceDistanceTerm>
+      <SourceDistanceFactor>1</SourceDistanceFactor>
+      <DestFactor>1</DestFactor>
+      <Color>00A3D29B</Color>
+      <SpecularFactor>0,6000000238</SpecularFactor>
+      <SpecularIndex>10</SpecularIndex>
+      <AmbientFactor>0,1000000015</AmbientFactor>
+      <DiffusionFactor>0,8999999762</DiffusionFactor>
+      <NegativeDiffusionFactor>0,200000003</NegativeDiffusionFactor>
+      <DiffuseSaturation>0</DiffuseSaturation>
+      <PositionX>-4</PositionX>
+      <PositionY>-14</PositionY>
+      <PositionZ>100</PositionZ>
+    </Light>
+  </COMMON>
+  <BCLeaLCD>
+    <Frame>
+      <Height>8</Height>
+      <Size>8</Size>
+      <Altitude>100</Altitude>
+      <Style>2</Style>
+      <BoardShadow>2</BoardShadow>
+    </Frame>
+    <Dot>
+      <Shape>1</Shape>
+      <Size>4</Size>
+      <Space>1</Space>
+      <Blured>0</Blured>
+      <BlurRadius>0,8000000119</BlurRadius>
+      <Blended>0</Blended>
+      <BlendOperation>11</BlendOperation>
+    </Dot>
+    <Colors>
+      <Board>00000000</Board>
+      <Frame>8000000F</Frame>
+      <DotOn>0000C8FF</DotOn>
+    </Colors>
+  </BCLeaLCD>
+  <BCLeaLED>
+    <Geometry>
+      <Style>2</Style>
+      <Size>15</Size>
+      <Altitude>100</Altitude>
+    </Geometry>
+    <Colors>
+      <ColorOn>00A5C7A5</ColorOn>
+      <ColorOff>00A5C8A5</ColorOff>
+      <BkgColor>8000000F</BkgColor>
+    </Colors>
+  </BCLeaLED>
+  <BCLeaQLED>
+    <Geometry>
+      <Style>2</Style>
+      <Size>20</Size>
+      <Altitude>100</Altitude>
+      <Rounding>10</Rounding>
+    </Geometry>
+    <Colors>
+      <ColorOn>00A5C7A5</ColorOn>
+      <ColorOff>00A5C8A5</ColorOff>
+      <BkgColor>00F0F0F0</BkgColor>
+    </Colors>
+  </BCLeaQLED>
+  <BCLeaSelector>
+    <Geometry>
+      <Style>2</Style>
+      <LineWidth>8</LineWidth>
+      <Altitude>100</Altitude>
+      <PointerSize>3</PointerSize>
+    </Geometry>
+    <Colors>
+      <Line>0000C8FF</Line>
+      <LineBkg>00AFCDAF</LineBkg>
+      <BkgColor>8000000F</BkgColor>
+    </Colors>
+    <Text>
+      <ShadowColor>00000000</ShadowColor>
+      <ShadowOffsetX>2</ShadowOffsetX>
+      <ShadowOffsetY>2</ShadowOffsetY>
+      <ShadowRadius>4</ShadowRadius>
+      <Draw3D>0</Draw3D>
+    </Text>
+  </BCLeaSelector>
+  <BCLeaRingSlider>
+    <Geometry>
+      <Style>2</Style>
+      <LineWidth>8</LineWidth>
+      <Altitude>100</Altitude>
+      <PointerSize>3</PointerSize>
+    </Geometry>
+    <Colors>
+      <Line>0000C8FF</Line>
+      <LineBkg>00AFCDAF</LineBkg>
+      <BkgColor>8000000F</BkgColor>
+      <PointerColor>0046C846</PointerColor>
+    </Colors>
+    <Text>
+      <ShadowColor>00000000</ShadowColor>
+      <ShadowOffsetX>2</ShadowOffsetX>
+      <ShadowOffsetY>2</ShadowOffsetY>
+      <ShadowRadius>4</ShadowRadius>
+      <Draw3D>0</Draw3D>
+    </Text>
+  </BCLeaRingSlider>
+</BCLea_Theme>

+ 113 - 0
styles/lea_default.bclea

@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BCLea_Theme>
+  <Version>
+    <Version>1.0</Version>
+  </Version>
+  <COMMON>
+    <Light>
+      <SourceIntensity>500</SourceIntensity>
+      <SourceDistanceTerm>150</SourceDistanceTerm>
+      <SourceDistanceFactor>1</SourceDistanceFactor>
+      <DestFactor>1</DestFactor>
+      <Color>00FFFFFF</Color>
+      <SpecularFactor>0,6000000238</SpecularFactor>
+      <SpecularIndex>10</SpecularIndex>
+      <AmbientFactor>0,3000000119</AmbientFactor>
+      <DiffusionFactor>0,8999999762</DiffusionFactor>
+      <NegativeDiffusionFactor>0,1000000015</NegativeDiffusionFactor>
+      <DiffuseSaturation>0</DiffuseSaturation>
+      <PositionX>-100</PositionX>
+      <PositionY>-100</PositionY>
+      <PositionZ>100</PositionZ>
+    </Light>
+  </COMMON>
+  <BCLeaLCD>
+    <Frame>
+      <Height>8</Height>
+      <Size>8</Size>
+      <Altitude>2</Altitude>
+      <Style>2</Style>
+      <BoardShadow>2</BoardShadow>
+    </Frame>
+    <Dot>
+      <Shape>1</Shape>
+      <Size>4</Size>
+      <Space>1</Space>
+      <Blured>0</Blured>
+      <BlurRadius>0,8000000119</BlurRadius>
+      <Blended>0</Blended>
+      <BlendOperation>11</BlendOperation>
+    </Dot>
+    <Colors>
+      <Board>00000000</Board>
+      <Frame>8000000F</Frame>
+      <DotOn>00F0CAA6</DotOn>
+    </Colors>
+  </BCLeaLCD>
+  <BCLeaLED>
+    <Geometry>
+      <Style>2</Style>
+      <Size>15</Size>
+      <Altitude>2</Altitude>
+    </Geometry>
+    <Colors>
+      <ColorOn>00FF9C15</ColorOn>
+      <ColorOff>009E5A00</ColorOff>
+      <BkgColor>8000000F</BkgColor>
+    </Colors>
+  </BCLeaLED>
+  <BCLeaQLED>
+    <Geometry>
+      <Style>2</Style>
+      <Size>20</Size>
+      <Altitude>2</Altitude>
+      <Rounding>3</Rounding>
+    </Geometry>
+    <Colors>
+      <ColorOn>00FF9C15</ColorOn>
+      <ColorOff>009E5A00</ColorOff>
+      <BkgColor>8000000F</BkgColor>
+    </Colors>
+  </BCLeaQLED>
+  <BCLeaSelector>
+    <Geometry>
+      <Style>2</Style>
+      <LineWidth>8</LineWidth>
+      <Altitude>2</Altitude>
+      <PointerSize>3</PointerSize>
+    </Geometry>
+    <Colors>
+      <Line>009E5A00</Line>
+      <LineBkg>00D3D3D3</LineBkg>
+      <BkgColor>8000000F</BkgColor>
+    </Colors>
+    <Text>
+      <ShadowColor>00000000</ShadowColor>
+      <ShadowOffsetX>2</ShadowOffsetX>
+      <ShadowOffsetY>2</ShadowOffsetY>
+      <ShadowRadius>4</ShadowRadius>
+      <Draw3D>0</Draw3D>
+    </Text>
+  </BCLeaSelector>
+  <BCLeaRingSlider>
+    <Geometry>
+      <Style>2</Style>
+      <LineWidth>8</LineWidth>
+      <Altitude>2</Altitude>
+      <PointerSize>3</PointerSize>
+    </Geometry>
+    <Colors>
+      <Line>009E5A00</Line>
+      <LineBkg>00D3D3D3</LineBkg>
+      <BkgColor>8000000F</BkgColor>
+      <PointerColor>00FF9C15</PointerColor>
+    </Colors>
+    <Text>
+      <ShadowColor>00000000</ShadowColor>
+      <ShadowOffsetX>2</ShadowOffsetX>
+      <ShadowOffsetY>2</ShadowOffsetY>
+      <ShadowRadius>4</ShadowRadius>
+      <Draw3D>0</Draw3D>
+    </Text>
+  </BCLeaRingSlider>
+</BCLea_Theme>

+ 113 - 0
styles/lea_plastic_morph.bclea

@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BCLea_Theme>
+  <Version>
+    <Version>1.0</Version>
+  </Version>
+  <COMMON>
+    <Light>
+      <SourceIntensity>100</SourceIntensity>
+      <SourceDistanceTerm>150</SourceDistanceTerm>
+      <SourceDistanceFactor>1</SourceDistanceFactor>
+      <DestFactor>1</DestFactor>
+      <Color>00FFFFFF</Color>
+      <SpecularFactor>0,6000000238</SpecularFactor>
+      <SpecularIndex>10</SpecularIndex>
+      <AmbientFactor>0,8000000119</AmbientFactor>
+      <DiffusionFactor>0,8000000119</DiffusionFactor>
+      <NegativeDiffusionFactor>0,200000003</NegativeDiffusionFactor>
+      <DiffuseSaturation>0</DiffuseSaturation>
+      <PositionX>226</PositionX>
+      <PositionY>100</PositionY>
+      <PositionZ>300</PositionZ>
+    </Light>
+  </COMMON>
+  <BCLeaLCD>
+    <Frame>
+      <Height>10</Height>
+      <Size>10</Size>
+      <Altitude>15</Altitude>
+      <Style>2</Style>
+      <BoardShadow>1</BoardShadow>
+    </Frame>
+    <Dot>
+      <Shape>1</Shape>
+      <Size>4</Size>
+      <Space>1</Space>
+      <Blured>-1</Blured>
+      <BlurRadius>0,1000000015</BlurRadius>
+      <Blended>-1</Blended>
+      <BlendOperation>11</BlendOperation>
+    </Dot>
+    <Colors>
+      <Board>00FFFFFF</Board>
+      <Frame>00E1E1E1</Frame>
+      <DotOn>00F00000</DotOn>
+    </Colors>
+  </BCLeaLCD>
+  <BCLeaLED>
+    <Geometry>
+      <Style>2</Style>
+      <Size>15</Size>
+      <Altitude>15</Altitude>
+    </Geometry>
+    <Colors>
+      <ColorOn>00FF9C15</ColorOn>
+      <ColorOff>009E5A00</ColorOff>
+      <BkgColor>00FFFFFF</BkgColor>
+    </Colors>
+  </BCLeaLED>
+  <BCLeaQLED>
+    <Geometry>
+      <Style>2</Style>
+      <Size>20</Size>
+      <Altitude>15</Altitude>
+      <Rounding>3</Rounding>
+    </Geometry>
+    <Colors>
+      <ColorOn>00FF9C15</ColorOn>
+      <ColorOff>009E5A00</ColorOff>
+      <BkgColor>00FFFFFF</BkgColor>
+    </Colors>
+  </BCLeaQLED>
+  <BCLeaSelector>
+    <Geometry>
+      <Style>2</Style>
+      <LineWidth>9</LineWidth>
+      <Altitude>15</Altitude>
+      <PointerSize>3</PointerSize>
+    </Geometry>
+    <Colors>
+      <Line>00FF0000</Line>
+      <LineBkg>00E1E1E1</LineBkg>
+      <BkgColor>00FFFFFF</BkgColor>
+    </Colors>
+    <Text>
+      <ShadowColor>00000000</ShadowColor>
+      <ShadowOffsetX>2</ShadowOffsetX>
+      <ShadowOffsetY>2</ShadowOffsetY>
+      <ShadowRadius>4</ShadowRadius>
+      <Draw3D>0</Draw3D>
+    </Text>
+  </BCLeaSelector>
+  <BCLeaRingSlider>
+    <Geometry>
+      <Style>2</Style>
+      <LineWidth>9</LineWidth>
+      <Altitude>15</Altitude>
+      <PointerSize>3</PointerSize>
+    </Geometry>
+    <Colors>
+      <Line>00FF0000</Line>
+      <LineBkg>00E1E1E1</LineBkg>
+      <BkgColor>00FFFFFF</BkgColor>
+      <PointerColor>00FF9C15</PointerColor>
+    </Colors>
+    <Text>
+      <ShadowColor>00000000</ShadowColor>
+      <ShadowOffsetX>2</ShadowOffsetX>
+      <ShadowOffsetY>2</ShadowOffsetY>
+      <ShadowRadius>4</ShadowRadius>
+      <Draw3D>0</Draw3D>
+    </Text>
+  </BCLeaRingSlider>
+</BCLea_Theme>

BIN
test/test_bclea/ThemeBuillder.ico


+ 161 - 0
test/test_bclea/ThemeBuillder.lpi

@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="12"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <UseDesignTimePackages Value="True"/>
+        <CompatibilityMode Value="True"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <Title Value="ThemeBuillder"/>
+      <Scaled Value="True"/>
+      <ResourceType Value="res"/>
+      <UseXPManifest Value="True"/>
+      <XPManifest>
+        <DpiAware Value="True"/>
+      </XPManifest>
+      <Icon Value="0"/>
+    </General>
+    <LazDoc Paths="..\docs"/>
+    <BuildModes Count="3">
+      <Item1 Name="Default" Default="True"/>
+      <Item2 Name="Debug">
+        <CompilerOptions>
+          <Version Value="11"/>
+          <PathDelim Value="\"/>
+          <Target>
+            <Filename Value="ThemeBuillder"/>
+          </Target>
+          <SearchPaths>
+            <IncludeFiles Value="$(ProjOutDir)"/>
+            <OtherUnitFiles Value=".."/>
+            <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+          </SearchPaths>
+          <Parsing>
+            <SyntaxOptions>
+              <IncludeAssertionCode Value="True"/>
+            </SyntaxOptions>
+          </Parsing>
+          <CodeGeneration>
+            <Checks>
+              <IOChecks Value="True"/>
+              <RangeChecks Value="True"/>
+              <OverflowChecks Value="True"/>
+              <StackChecks Value="True"/>
+            </Checks>
+            <VerifyObjMethodCallValidity Value="True"/>
+          </CodeGeneration>
+          <Linking>
+            <Debugging>
+              <DebugInfoType Value="dsDwarf3"/>
+              <UseHeaptrc Value="True"/>
+              <TrashVariables Value="True"/>
+              <UseExternalDbgSyms Value="True"/>
+            </Debugging>
+            <Options>
+              <Win32>
+                <GraphicApplication Value="True"/>
+              </Win32>
+            </Options>
+          </Linking>
+        </CompilerOptions>
+      </Item2>
+      <Item3 Name="Release">
+        <CompilerOptions>
+          <Version Value="11"/>
+          <PathDelim Value="\"/>
+          <Target>
+            <Filename Value="ThemeBuillder"/>
+          </Target>
+          <SearchPaths>
+            <IncludeFiles Value="$(ProjOutDir)"/>
+            <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+          </SearchPaths>
+          <CodeGeneration>
+            <SmartLinkUnit Value="True"/>
+            <Optimizations>
+              <OptimizationLevel Value="3"/>
+            </Optimizations>
+          </CodeGeneration>
+          <Linking>
+            <Debugging>
+              <GenerateDebugInfo Value="False"/>
+              <DebugInfoType Value="dsDwarf2Set"/>
+            </Debugging>
+            <LinkSmart Value="True"/>
+            <Options>
+              <Win32>
+                <GraphicApplication Value="True"/>
+              </Win32>
+            </Options>
+          </Linking>
+        </CompilerOptions>
+      </Item3>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <UseFileFilters Value="True"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+    </RunParams>
+    <RequiredPackages Count="2">
+      <Item1>
+        <PackageName Value="bgracontrols"/>
+      </Item1>
+      <Item2>
+        <PackageName Value="LCL"/>
+      </Item2>
+    </RequiredPackages>
+    <Units Count="2">
+      <Unit0>
+        <Filename Value="ThemeBuillder.lpr"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+      <Unit1>
+        <Filename Value="untThemeBuilder.pas"/>
+        <IsPartOfProject Value="True"/>
+        <ComponentName Value="frmMain"/>
+        <HasResources Value="True"/>
+        <ResourceBaseClass Value="Form"/>
+      </Unit1>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="ThemeBuillder"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value=".."/>
+      <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/>
+    </SearchPaths>
+    <Linking>
+      <Debugging>
+        <DebugInfoType Value="dsDwarf2Set"/>
+      </Debugging>
+      <Options>
+        <Win32>
+          <GraphicApplication Value="True"/>
+        </Win32>
+      </Options>
+    </Linking>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="3">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 24 - 0
test/test_bclea/ThemeBuillder.lpr

@@ -0,0 +1,24 @@
+program ThemeBuillder;
+
+{$mode objfpc}{$H+}
+
+uses
+  {$IFDEF UNIX}
+  cthreads,
+  {$ENDIF}
+  {$IFDEF HASAMIGA}
+  athreads,
+  {$ENDIF}
+  Interfaces, // this includes the LCL widgetset
+  Forms, untThemeBuilder;
+
+{$R *.res}
+
+begin
+  RequireDerivedFormResource:=True;
+  Application.Scaled:=True;
+  Application.Initialize;
+  Application.CreateForm(TfrmMain, frmMain);
+  Application.Run;
+end.
+

+ 113 - 0
test/test_bclea/themes/lea_alien.bclea

@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BCLea_Theme>
+  <Version>
+    <Version>1.0</Version>
+  </Version>
+  <COMMON>
+    <Light>
+      <SourceIntensity>300</SourceIntensity>
+      <SourceDistanceTerm>150</SourceDistanceTerm>
+      <SourceDistanceFactor>1</SourceDistanceFactor>
+      <DestFactor>1</DestFactor>
+      <Color>00A3D29B</Color>
+      <SpecularFactor>0,6000000238</SpecularFactor>
+      <SpecularIndex>10</SpecularIndex>
+      <AmbientFactor>0,1000000015</AmbientFactor>
+      <DiffusionFactor>0,8999999762</DiffusionFactor>
+      <NegativeDiffusionFactor>0,200000003</NegativeDiffusionFactor>
+      <DiffuseSaturation>0</DiffuseSaturation>
+      <PositionX>-4</PositionX>
+      <PositionY>-14</PositionY>
+      <PositionZ>100</PositionZ>
+    </Light>
+  </COMMON>
+  <BCLeaLCD>
+    <Frame>
+      <Height>8</Height>
+      <Size>8</Size>
+      <Altitude>100</Altitude>
+      <Style>2</Style>
+      <BoardShadow>2</BoardShadow>
+    </Frame>
+    <Dot>
+      <Shape>1</Shape>
+      <Size>4</Size>
+      <Space>1</Space>
+      <Blured>0</Blured>
+      <BlurRadius>0,8000000119</BlurRadius>
+      <Blended>0</Blended>
+      <BlendOperation>11</BlendOperation>
+    </Dot>
+    <Colors>
+      <Board>00000000</Board>
+      <Frame>8000000F</Frame>
+      <DotOn>0000C8FF</DotOn>
+    </Colors>
+  </BCLeaLCD>
+  <BCLeaLED>
+    <Geometry>
+      <Style>2</Style>
+      <Size>15</Size>
+      <Altitude>100</Altitude>
+    </Geometry>
+    <Colors>
+      <ColorOn>00A5C7A5</ColorOn>
+      <ColorOff>00A5C8A5</ColorOff>
+      <BkgColor>8000000F</BkgColor>
+    </Colors>
+  </BCLeaLED>
+  <BCLeaQLED>
+    <Geometry>
+      <Style>2</Style>
+      <Size>20</Size>
+      <Altitude>100</Altitude>
+      <Rounding>10</Rounding>
+    </Geometry>
+    <Colors>
+      <ColorOn>00A5C7A5</ColorOn>
+      <ColorOff>00A5C8A5</ColorOff>
+      <BkgColor>00F0F0F0</BkgColor>
+    </Colors>
+  </BCLeaQLED>
+  <BCLeaSelector>
+    <Geometry>
+      <Style>2</Style>
+      <LineWidth>8</LineWidth>
+      <Altitude>100</Altitude>
+      <PointerSize>3</PointerSize>
+    </Geometry>
+    <Colors>
+      <Line>0000C8FF</Line>
+      <LineBkg>00AFCDAF</LineBkg>
+      <BkgColor>8000000F</BkgColor>
+    </Colors>
+    <Text>
+      <ShadowColor>00000000</ShadowColor>
+      <ShadowOffsetX>2</ShadowOffsetX>
+      <ShadowOffsetY>2</ShadowOffsetY>
+      <ShadowRadius>4</ShadowRadius>
+      <Draw3D>0</Draw3D>
+    </Text>
+  </BCLeaSelector>
+  <BCLeaRingSlider>
+    <Geometry>
+      <Style>2</Style>
+      <LineWidth>8</LineWidth>
+      <Altitude>100</Altitude>
+      <PointerSize>3</PointerSize>
+    </Geometry>
+    <Colors>
+      <Line>0000C8FF</Line>
+      <LineBkg>00AFCDAF</LineBkg>
+      <BkgColor>8000000F</BkgColor>
+      <PointerColor>0046C846</PointerColor>
+    </Colors>
+    <Text>
+      <ShadowColor>00000000</ShadowColor>
+      <ShadowOffsetX>2</ShadowOffsetX>
+      <ShadowOffsetY>2</ShadowOffsetY>
+      <ShadowRadius>4</ShadowRadius>
+      <Draw3D>0</Draw3D>
+    </Text>
+  </BCLeaRingSlider>
+</BCLea_Theme>

+ 113 - 0
test/test_bclea/themes/lea_default.bclea

@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BCLea_Theme>
+  <Version>
+    <Version>1.0</Version>
+  </Version>
+  <COMMON>
+    <Light>
+      <SourceIntensity>500</SourceIntensity>
+      <SourceDistanceTerm>150</SourceDistanceTerm>
+      <SourceDistanceFactor>1</SourceDistanceFactor>
+      <DestFactor>1</DestFactor>
+      <Color>00FFFFFF</Color>
+      <SpecularFactor>0,6000000238</SpecularFactor>
+      <SpecularIndex>10</SpecularIndex>
+      <AmbientFactor>0,3000000119</AmbientFactor>
+      <DiffusionFactor>0,8999999762</DiffusionFactor>
+      <NegativeDiffusionFactor>0,1000000015</NegativeDiffusionFactor>
+      <DiffuseSaturation>0</DiffuseSaturation>
+      <PositionX>-100</PositionX>
+      <PositionY>-100</PositionY>
+      <PositionZ>100</PositionZ>
+    </Light>
+  </COMMON>
+  <BCLeaLCD>
+    <Frame>
+      <Height>8</Height>
+      <Size>8</Size>
+      <Altitude>2</Altitude>
+      <Style>2</Style>
+      <BoardShadow>2</BoardShadow>
+    </Frame>
+    <Dot>
+      <Shape>1</Shape>
+      <Size>4</Size>
+      <Space>1</Space>
+      <Blured>0</Blured>
+      <BlurRadius>0,8000000119</BlurRadius>
+      <Blended>0</Blended>
+      <BlendOperation>11</BlendOperation>
+    </Dot>
+    <Colors>
+      <Board>00000000</Board>
+      <Frame>8000000F</Frame>
+      <DotOn>00F0CAA6</DotOn>
+    </Colors>
+  </BCLeaLCD>
+  <BCLeaLED>
+    <Geometry>
+      <Style>2</Style>
+      <Size>15</Size>
+      <Altitude>2</Altitude>
+    </Geometry>
+    <Colors>
+      <ColorOn>00FF9C15</ColorOn>
+      <ColorOff>009E5A00</ColorOff>
+      <BkgColor>8000000F</BkgColor>
+    </Colors>
+  </BCLeaLED>
+  <BCLeaQLED>
+    <Geometry>
+      <Style>2</Style>
+      <Size>20</Size>
+      <Altitude>2</Altitude>
+      <Rounding>3</Rounding>
+    </Geometry>
+    <Colors>
+      <ColorOn>00FF9C15</ColorOn>
+      <ColorOff>009E5A00</ColorOff>
+      <BkgColor>8000000F</BkgColor>
+    </Colors>
+  </BCLeaQLED>
+  <BCLeaSelector>
+    <Geometry>
+      <Style>2</Style>
+      <LineWidth>8</LineWidth>
+      <Altitude>2</Altitude>
+      <PointerSize>3</PointerSize>
+    </Geometry>
+    <Colors>
+      <Line>009E5A00</Line>
+      <LineBkg>00D3D3D3</LineBkg>
+      <BkgColor>8000000F</BkgColor>
+    </Colors>
+    <Text>
+      <ShadowColor>00000000</ShadowColor>
+      <ShadowOffsetX>2</ShadowOffsetX>
+      <ShadowOffsetY>2</ShadowOffsetY>
+      <ShadowRadius>4</ShadowRadius>
+      <Draw3D>0</Draw3D>
+    </Text>
+  </BCLeaSelector>
+  <BCLeaRingSlider>
+    <Geometry>
+      <Style>2</Style>
+      <LineWidth>8</LineWidth>
+      <Altitude>2</Altitude>
+      <PointerSize>3</PointerSize>
+    </Geometry>
+    <Colors>
+      <Line>009E5A00</Line>
+      <LineBkg>00D3D3D3</LineBkg>
+      <BkgColor>8000000F</BkgColor>
+      <PointerColor>00FF9C15</PointerColor>
+    </Colors>
+    <Text>
+      <ShadowColor>00000000</ShadowColor>
+      <ShadowOffsetX>2</ShadowOffsetX>
+      <ShadowOffsetY>2</ShadowOffsetY>
+      <ShadowRadius>4</ShadowRadius>
+      <Draw3D>0</Draw3D>
+    </Text>
+  </BCLeaRingSlider>
+</BCLea_Theme>

+ 113 - 0
test/test_bclea/themes/lea_plastic_morph.bclea

@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BCLea_Theme>
+  <Version>
+    <Version>1.0</Version>
+  </Version>
+  <COMMON>
+    <Light>
+      <SourceIntensity>100</SourceIntensity>
+      <SourceDistanceTerm>150</SourceDistanceTerm>
+      <SourceDistanceFactor>1</SourceDistanceFactor>
+      <DestFactor>1</DestFactor>
+      <Color>00FFFFFF</Color>
+      <SpecularFactor>0,6000000238</SpecularFactor>
+      <SpecularIndex>10</SpecularIndex>
+      <AmbientFactor>0,8000000119</AmbientFactor>
+      <DiffusionFactor>0,8000000119</DiffusionFactor>
+      <NegativeDiffusionFactor>0,200000003</NegativeDiffusionFactor>
+      <DiffuseSaturation>0</DiffuseSaturation>
+      <PositionX>226</PositionX>
+      <PositionY>100</PositionY>
+      <PositionZ>300</PositionZ>
+    </Light>
+  </COMMON>
+  <BCLeaLCD>
+    <Frame>
+      <Height>10</Height>
+      <Size>10</Size>
+      <Altitude>15</Altitude>
+      <Style>2</Style>
+      <BoardShadow>1</BoardShadow>
+    </Frame>
+    <Dot>
+      <Shape>1</Shape>
+      <Size>4</Size>
+      <Space>1</Space>
+      <Blured>-1</Blured>
+      <BlurRadius>0,1000000015</BlurRadius>
+      <Blended>-1</Blended>
+      <BlendOperation>11</BlendOperation>
+    </Dot>
+    <Colors>
+      <Board>00FFFFFF</Board>
+      <Frame>00E1E1E1</Frame>
+      <DotOn>00F00000</DotOn>
+    </Colors>
+  </BCLeaLCD>
+  <BCLeaLED>
+    <Geometry>
+      <Style>2</Style>
+      <Size>15</Size>
+      <Altitude>15</Altitude>
+    </Geometry>
+    <Colors>
+      <ColorOn>00FF9C15</ColorOn>
+      <ColorOff>009E5A00</ColorOff>
+      <BkgColor>00FFFFFF</BkgColor>
+    </Colors>
+  </BCLeaLED>
+  <BCLeaQLED>
+    <Geometry>
+      <Style>2</Style>
+      <Size>20</Size>
+      <Altitude>15</Altitude>
+      <Rounding>3</Rounding>
+    </Geometry>
+    <Colors>
+      <ColorOn>00FF9C15</ColorOn>
+      <ColorOff>009E5A00</ColorOff>
+      <BkgColor>00FFFFFF</BkgColor>
+    </Colors>
+  </BCLeaQLED>
+  <BCLeaSelector>
+    <Geometry>
+      <Style>2</Style>
+      <LineWidth>9</LineWidth>
+      <Altitude>15</Altitude>
+      <PointerSize>3</PointerSize>
+    </Geometry>
+    <Colors>
+      <Line>00FF0000</Line>
+      <LineBkg>00E1E1E1</LineBkg>
+      <BkgColor>00FFFFFF</BkgColor>
+    </Colors>
+    <Text>
+      <ShadowColor>00000000</ShadowColor>
+      <ShadowOffsetX>2</ShadowOffsetX>
+      <ShadowOffsetY>2</ShadowOffsetY>
+      <ShadowRadius>4</ShadowRadius>
+      <Draw3D>0</Draw3D>
+    </Text>
+  </BCLeaSelector>
+  <BCLeaRingSlider>
+    <Geometry>
+      <Style>2</Style>
+      <LineWidth>9</LineWidth>
+      <Altitude>15</Altitude>
+      <PointerSize>3</PointerSize>
+    </Geometry>
+    <Colors>
+      <Line>00FF0000</Line>
+      <LineBkg>00E1E1E1</LineBkg>
+      <BkgColor>00FFFFFF</BkgColor>
+      <PointerColor>00FF9C15</PointerColor>
+    </Colors>
+    <Text>
+      <ShadowColor>00000000</ShadowColor>
+      <ShadowOffsetX>2</ShadowOffsetX>
+      <ShadowOffsetY>2</ShadowOffsetY>
+      <ShadowRadius>4</ShadowRadius>
+      <Draw3D>0</Draw3D>
+    </Text>
+  </BCLeaRingSlider>
+</BCLea_Theme>

+ 1904 - 0
test/test_bclea/untThemeBuilder.lfm

@@ -0,0 +1,1904 @@
+object frmMain: TfrmMain
+  Left = 503
+  Height = 735
+  Top = 151
+  Width = 1063
+  AutoSize = True
+  Caption = 'Theme Builder'
+  ClientHeight = 735
+  ClientWidth = 1063
+  Menu = MainMenu
+  OnCreate = FormCreate
+  OnShow = FormShow
+  LCLVersion = '3.4.0.0'
+  object pnlProperties: TPanel
+    Left = 0
+    Height = 371
+    Top = 364
+    Width = 1063
+    Align = alBottom
+    BevelOuter = bvNone
+    ClientHeight = 371
+    ClientWidth = 1063
+    TabOrder = 0
+    object GroupBox1: TGroupBox
+      Left = 8
+      Height = 352
+      Top = 8
+      Width = 320
+      Caption = 'Theme Common - Lights'
+      ClientHeight = 332
+      ClientWidth = 316
+      TabOrder = 0
+      object lblL_1: TLabel
+        AnchorSideTop.Side = asrCenter
+        Left = 0
+        Height = 15
+        Top = 12
+        Width = 49
+        Caption = 'Ambient:'
+        ParentColor = False
+        Transparent = False
+      end
+      object lblL_2: TLabel
+        AnchorSideTop.Side = asrCenter
+        Left = 0
+        Height = 15
+        Top = 38
+        Width = 80
+        Caption = 'Specular Index:'
+        ParentColor = False
+        Transparent = False
+      end
+      object lblL_3: TLabel
+        AnchorSideTop.Side = asrCenter
+        Left = 0
+        Height = 15
+        Top = 64
+        Width = 84
+        Caption = 'Specular Factor:'
+        ParentColor = False
+        Transparent = False
+      end
+      object lblL_4: TLabel
+        AnchorSideTop.Side = asrCenter
+        Left = 0
+        Height = 15
+        Top = 90
+        Width = 56
+        Caption = 'Dst Factor:'
+        ParentColor = False
+        Transparent = False
+      end
+      object lblL_5: TLabel
+        AnchorSideTop.Side = asrCenter
+        Left = 0
+        Height = 15
+        Top = 116
+        Width = 67
+        Caption = 'Src Intensity:'
+        ParentColor = False
+        Transparent = False
+      end
+      object lblL_6: TLabel
+        AnchorSideTop.Side = asrCenter
+        Left = 0
+        Height = 15
+        Top = 142
+        Width = 71
+        Caption = 'Src Dist Term:'
+        ParentColor = False
+        Transparent = False
+      end
+      object lblL_7: TLabel
+        AnchorSideTop.Side = asrCenter
+        Left = 0
+        Height = 15
+        Top = 168
+        Width = 78
+        Caption = 'Src Dist Factor:'
+        ParentColor = False
+        Transparent = False
+      end
+      object lblL_8: TLabel
+        AnchorSideTop.Side = asrCenter
+        Left = 0
+        Height = 15
+        Top = 194
+        Width = 70
+        Caption = 'Diffus Factor:'
+        ParentColor = False
+        Transparent = False
+      end
+      object lblL_9: TLabel
+        AnchorSideTop.Side = asrCenter
+        Left = 0
+        Height = 15
+        Top = 220
+        Width = 95
+        Caption = 'Neg Diffus Factor:'
+        ParentColor = False
+        Transparent = False
+      end
+      object seL_Ambient: TFloatSpinEdit
+        Left = 100
+        Height = 23
+        Top = 8
+        Width = 56
+        Increment = 0.1
+        OnChange = seL_AmbientChange
+        TabOrder = 0
+      end
+      object seL_SpecIndex: TFloatSpinEdit
+        AnchorSideTop.Control = seL_Ambient
+        AnchorSideTop.Side = asrBottom
+        Left = 100
+        Height = 23
+        Top = 34
+        Width = 56
+        BorderSpacing.Top = 3
+        Increment = 0.1
+        OnChange = seL_SpecIndexChange
+        TabOrder = 1
+      end
+      object seL_SpecFact: TFloatSpinEdit
+        AnchorSideTop.Control = seL_SpecIndex
+        AnchorSideTop.Side = asrBottom
+        Left = 100
+        Height = 23
+        Top = 60
+        Width = 56
+        BorderSpacing.Top = 3
+        Increment = 0.1
+        OnChange = seL_SpecFactChange
+        TabOrder = 2
+      end
+      object seL_DistFact: TFloatSpinEdit
+        AnchorSideTop.Control = seL_SpecFact
+        AnchorSideTop.Side = asrBottom
+        Left = 100
+        Height = 23
+        Top = 86
+        Width = 56
+        BorderSpacing.Top = 3
+        Increment = 0.1
+        OnChange = seL_DistFactChange
+        TabOrder = 3
+      end
+      object seL_SrcIntens: TFloatSpinEdit
+        AnchorSideTop.Control = seL_DistFact
+        AnchorSideTop.Side = asrBottom
+        Left = 100
+        Height = 23
+        Top = 112
+        Width = 56
+        BorderSpacing.Top = 3
+        Increment = 0.1
+        OnChange = seL_SrcIntensChange
+        TabOrder = 4
+      end
+      object seL_SrcDistTerm: TFloatSpinEdit
+        AnchorSideTop.Control = seL_SrcIntens
+        AnchorSideTop.Side = asrBottom
+        Left = 100
+        Height = 23
+        Top = 138
+        Width = 56
+        BorderSpacing.Top = 3
+        Increment = 0.1
+        OnChange = seL_SrcDistTermChange
+        TabOrder = 5
+      end
+      object seL_SrcDistFact: TFloatSpinEdit
+        AnchorSideTop.Control = seL_SrcDistTerm
+        AnchorSideTop.Side = asrBottom
+        Left = 100
+        Height = 23
+        Top = 164
+        Width = 56
+        BorderSpacing.Top = 3
+        Increment = 0.1
+        OnChange = seL_SrcDistFactChange
+        TabOrder = 6
+      end
+      object seL_DiffFact: TFloatSpinEdit
+        AnchorSideTop.Control = seL_SrcDistFact
+        AnchorSideTop.Side = asrBottom
+        Left = 100
+        Height = 23
+        Top = 190
+        Width = 56
+        BorderSpacing.Top = 3
+        Increment = 0.1
+        OnChange = seL_DiffFactChange
+        TabOrder = 7
+      end
+      object seL_NegDiffFact: TFloatSpinEdit
+        AnchorSideTop.Control = seL_DiffFact
+        AnchorSideTop.Side = asrBottom
+        Left = 100
+        Height = 23
+        Top = 216
+        Width = 56
+        BorderSpacing.Top = 3
+        Increment = 0.1
+        OnChange = seL_NegDiffFactChange
+        TabOrder = 8
+      end
+      object lblL_10: TLabel
+        AnchorSideTop.Side = asrCenter
+        Left = 184
+        Height = 15
+        Top = 12
+        Width = 32
+        Caption = 'Pos X:'
+        ParentColor = False
+        Transparent = False
+      end
+      object lblL_11: TLabel
+        AnchorSideTop.Side = asrCenter
+        Left = 184
+        Height = 15
+        Top = 38
+        Width = 32
+        Caption = 'Pos Y:'
+        ParentColor = False
+        Transparent = False
+      end
+      object lblL_12: TLabel
+        AnchorSideTop.Side = asrCenter
+        Left = 184
+        Height = 15
+        Top = 63
+        Width = 32
+        Caption = 'Pos Z:'
+        ParentColor = False
+        Transparent = False
+      end
+      object cbtLightColor: TColorButton
+        Left = 184
+        Height = 25
+        Top = 86
+        Width = 122
+        BorderWidth = 2
+        ButtonColorAutoSize = False
+        ButtonColorSize = 16
+        ButtonColor = clBlack
+        Caption = 'Light Color'
+        Margin = 8
+        OnColorChanged = cbtLightColorColorChanged
+      end
+      object cbL_DiffSat: TCheckBox
+        Left = 184
+        Height = 19
+        Top = 118
+        Width = 94
+        Caption = 'Diff Saturation'
+        TabOrder = 9
+        OnChange = cbL_DiffSatChange
+      end
+      object seL_PosX: TSpinEdit
+        Left = 256
+        Height = 23
+        Top = 9
+        Width = 50
+        OnChange = seL_PosXChange
+        TabOrder = 10
+      end
+      object seL_PosY: TSpinEdit
+        Left = 256
+        Height = 23
+        Top = 35
+        Width = 50
+        OnChange = seL_PosYChange
+        TabOrder = 11
+      end
+      object seL_PosZ: TSpinEdit
+        Left = 256
+        Height = 23
+        Top = 60
+        Width = 50
+        OnChange = seL_PosZChange
+        TabOrder = 12
+      end
+    end
+    object PageControl1: TPageControl
+      Left = 328
+      Height = 352
+      Top = 8
+      Width = 656
+      ActivePage = tsQLED
+      TabIndex = 4
+      TabOrder = 1
+      object tsLCD: TTabSheet
+        Caption = 'BCLeaLCDDisplay'
+        ClientHeight = 324
+        ClientWidth = 648
+        object GroupBox3: TGroupBox
+          Left = 0
+          Height = 320
+          Top = 0
+          Width = 137
+          Caption = 'Theme BCLeaLCDDisplay'
+          ClientHeight = 300
+          ClientWidth = 133
+          TabOrder = 0
+          object rgLCDBoardShadow: TRadioGroup
+            Left = 8
+            Height = 81
+            Top = 9
+            Width = 108
+            AutoFill = True
+            Caption = 'Board Shadow'
+            ChildSizing.LeftRightSpacing = 6
+            ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
+            ChildSizing.EnlargeVertical = crsHomogenousChildResize
+            ChildSizing.ShrinkHorizontal = crsScaleChilds
+            ChildSizing.ShrinkVertical = crsScaleChilds
+            ChildSizing.Layout = cclLeftToRightThenTopToBottom
+            ChildSizing.ControlsPerLine = 1
+            ClientHeight = 61
+            ClientWidth = 104
+            Items.Strings = (
+              'bsNone'
+              'bsOwn'
+              'bsFrame'
+            )
+            OnClick = rgLCDBoardShadowClick
+            TabOrder = 0
+          end
+          object cbLCDBlured: TCheckBox
+            Left = 8
+            Height = 19
+            Top = 104
+            Width = 52
+            Caption = 'Blured'
+            TabOrder = 1
+            OnChange = cbLCDBluredChange
+          end
+          object lblLCDDotsBlended: TLabel
+            Left = 8
+            Height = 15
+            Top = 130
+            Width = 59
+            Caption = 'Blur radius:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seLCDDotBlured: TFloatSpinEdit
+            Left = 74
+            Height = 23
+            Top = 127
+            Width = 56
+            Increment = 0.1
+            OnChange = seLCDDotBluredChange
+            TabOrder = 2
+          end
+          object cbLCDBlended: TCheckBox
+            Left = 8
+            Height = 19
+            Top = 160
+            Width = 61
+            Caption = 'Blended'
+            TabOrder = 3
+            OnChange = cbLCDBlendedChange
+          end
+          object cbLCDBlendOperations: TComboBox
+            Left = 8
+            Height = 23
+            Top = 184
+            Width = 122
+            ItemHeight = 15
+            TabOrder = 4
+            Text = 'cbLCDBlendOperations'
+            OnChange = cbLCDBlendOperationsChange
+          end
+        end
+        object GroupBox2: TGroupBox
+          Left = 136
+          Height = 320
+          Top = 0
+          Width = 322
+          Caption = 'Component and also in Theme'
+          ClientHeight = 300
+          ClientWidth = 318
+          TabOrder = 1
+          object lblLCDColorScheme: TLabel
+            Left = 8
+            Height = 15
+            Top = 9
+            Width = 76
+            Caption = 'Color scheme:'
+            ParentColor = False
+            Transparent = False
+          end
+          object lblLCDCustomColors: TLabel
+            Left = 8
+            Height = 15
+            Top = 56
+            Width = 119
+            Caption = 'Custom color scheme:'
+            ParentColor = False
+            Transparent = False
+          end
+          object cbtLCDFrameColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 73
+            Width = 123
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Frame color'
+            Margin = 8
+            OnColorChanged = cbtLCDFrameColorColorChanged
+          end
+          object cbtLCDBoardColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 102
+            Width = 123
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Board color'
+            Margin = 8
+            OnColorChanged = cbtLCDBoardColorColorChanged
+          end
+          object cbtLCDDotOnColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 130
+            Width = 123
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Dot color ON'
+            Margin = 8
+            OnColorChanged = cbtLCDDotOnColorColorChanged
+          end
+          object rgLCDDotShape: TRadioGroup
+            Left = 8
+            Height = 65
+            Top = 167
+            Width = 128
+            AutoFill = True
+            Caption = 'Dot shape'
+            ChildSizing.LeftRightSpacing = 6
+            ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
+            ChildSizing.EnlargeVertical = crsHomogenousChildResize
+            ChildSizing.ShrinkHorizontal = crsScaleChilds
+            ChildSizing.ShrinkVertical = crsScaleChilds
+            ChildSizing.Layout = cclLeftToRightThenTopToBottom
+            ChildSizing.ControlsPerLine = 1
+            ClientHeight = 45
+            ClientWidth = 124
+            Items.Strings = (
+              'stSquare'
+              'stRound'
+            )
+            OnClick = rgLCDDotShapeClick
+            TabOrder = 0
+          end
+          object lblLCDDotSize: TLabel
+            Left = 8
+            Height = 15
+            Top = 248
+            Width = 44
+            Caption = 'Dot size:'
+            ParentColor = False
+            Transparent = False
+          end
+          object lblLCDDotSpace: TLabel
+            Left = 8
+            Height = 15
+            Top = 276
+            Width = 60
+            Caption = 'Dots space:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seLCDDotSize: TSpinEdit
+            Left = 78
+            Height = 23
+            Top = 246
+            Width = 58
+            OnChange = seLCDDotSizeChange
+            TabOrder = 1
+          end
+          object seLCDDotsSpace: TSpinEdit
+            Left = 78
+            Height = 23
+            Top = 272
+            Width = 58
+            OnChange = seLCDDotsSpaceChange
+            TabOrder = 2
+          end
+          object rgLCDFrameStyle: TRadioGroup
+            Left = 168
+            Height = 81
+            Top = 9
+            Width = 146
+            AutoFill = True
+            Caption = 'Frame style'
+            ChildSizing.LeftRightSpacing = 6
+            ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
+            ChildSizing.EnlargeVertical = crsHomogenousChildResize
+            ChildSizing.ShrinkHorizontal = crsScaleChilds
+            ChildSizing.ShrinkVertical = crsScaleChilds
+            ChildSizing.Layout = cclLeftToRightThenTopToBottom
+            ChildSizing.ControlsPerLine = 1
+            ClientHeight = 61
+            ClientWidth = 142
+            Items.Strings = (
+              'zsFlat'
+              'zsLowered'
+              'zsRaised'
+            )
+            OnClick = rgLCDFrameStyleClick
+            TabOrder = 3
+          end
+          object lblLCDFrameHeight: TLabel
+            Left = 168
+            Height = 15
+            Top = 116
+            Width = 73
+            Caption = 'Frame height:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seLCDFrameHeight: TSpinEdit
+            Left = 256
+            Height = 23
+            Top = 112
+            Width = 58
+            OnChange = seLCDFrameHeightChange
+            TabOrder = 4
+          end
+          object lblLCDFrameSize: TLabel
+            Left = 168
+            Height = 15
+            Top = 141
+            Width = 58
+            Caption = 'Frame size:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seLCDFrameSize: TSpinEdit
+            Left = 256
+            Height = 23
+            Top = 138
+            Width = 58
+            OnChange = seLCDFrameSizeChange
+            TabOrder = 6
+          end
+          object lblLCDFrameAltitude: TLabel
+            Left = 168
+            Height = 15
+            Top = 167
+            Width = 79
+            Caption = 'Frame altitude:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seLCDFrameAltitude: TSpinEdit
+            Left = 256
+            Height = 23
+            Top = 164
+            Width = 58
+            OnChange = seLCDFrameAltitudeChange
+            TabOrder = 5
+          end
+        end
+        object GroupBox4: TGroupBox
+          Left = 456
+          Height = 320
+          Top = 0
+          Width = 185
+          Caption = 'Component only'
+          ClientHeight = 300
+          ClientWidth = 181
+          TabOrder = 2
+          object lblLCDLinesText: TLabel
+            Left = 8
+            Height = 15
+            Top = 8
+            Width = 50
+            Caption = 'Lines text'
+            ParentColor = False
+          end
+          object mmLCDText: TMemo
+            AnchorSideTop.Control = lblLCDLinesText
+            AnchorSideTop.Side = asrBottom
+            Left = 8
+            Height = 48
+            Top = 25
+            Width = 168
+            BorderSpacing.Top = 2
+            BorderSpacing.Right = 8
+            TabOrder = 0
+            OnChange = mmLCDTextChange
+          end
+          object lblLCDDisplayLineCount: TLabel
+            Left = 8
+            Height = 15
+            Top = 85
+            Width = 98
+            Caption = 'Display row count:'
+            ParentColor = False
+            Transparent = False
+          end
+          object lblLCDDisplayCharCount: TLabel
+            Left = 8
+            Height = 15
+            Top = 116
+            Width = 94
+            Caption = 'Display col count:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seLCDDisplayLineCount: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 82
+            Width = 58
+            OnChange = seLCDDisplayLineCountChange
+            TabOrder = 1
+          end
+          object seLCDDisplayCharCount: TSpinEdit
+            Left = 118
+            Height = 23
+            Hint = 'Set 0 for AutoSize'
+            Top = 112
+            Width = 58
+            OnChange = seLCDDisplayCharCountChange
+            ParentShowHint = False
+            ShowHint = True
+            TabOrder = 2
+          end
+          object cbLCDAutoSize: TCheckBox
+            Left = 8
+            Height = 19
+            Top = 144
+            Width = 64
+            Caption = 'AutoSize'
+            TabOrder = 3
+            OnChange = cbLCDAutoSizeChange
+          end
+          object lblLCDWidth: TLabel
+            Left = 8
+            Height = 15
+            Top = 179
+            Width = 35
+            Caption = 'Width:'
+            ParentColor = False
+            Transparent = False
+          end
+          object lblLCDHeight: TLabel
+            Left = 8
+            Height = 15
+            Top = 207
+            Width = 39
+            Caption = 'Heigth:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seLCDWidth: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 176
+            Width = 58
+            OnChange = seLCDWidthChange
+            TabOrder = 4
+          end
+          object seLCDHeigth: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 204
+            Width = 58
+            OnChange = seLCDHeigthChange
+            TabOrder = 5
+          end
+        end
+      end
+      object tsLED: TTabSheet
+        Caption = 'BCLeaLED'
+        ClientHeight = 324
+        ClientWidth = 648
+        object GroupBox5: TGroupBox
+          Left = 0
+          Height = 320
+          Top = 0
+          Width = 224
+          Caption = 'Component and also in Theme BCLeaLED'
+          ClientHeight = 300
+          ClientWidth = 220
+          TabOrder = 0
+          object cbtLEDColorOn: TColorButton
+            Left = 8
+            Height = 25
+            Top = 8
+            Width = 123
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Dot Color On'
+            Margin = 8
+            OnColorChanged = cbtLEDColorOnColorChanged
+          end
+          object cbtLEDColorOff: TColorButton
+            Left = 8
+            Height = 25
+            Top = 37
+            Width = 123
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Dot Color Off'
+            Margin = 8
+            OnColorChanged = cbtLEDColorOffColorChanged
+          end
+          object cbtLEDBkgColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 65
+            Width = 123
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Bkg Color'
+            Margin = 8
+            OnColorChanged = cbtLEDBkgColorColorChanged
+          end
+          object lblLEDSize: TLabel
+            Left = 8
+            Height = 15
+            Top = 100
+            Width = 23
+            Caption = 'Size:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seLEDSize: TSpinEdit
+            Left = 72
+            Height = 23
+            Top = 96
+            Width = 58
+            OnChange = seLEDSizeChange
+            TabOrder = 0
+          end
+          object rgLEDZStyle: TRadioGroup
+            Left = 8
+            Height = 81
+            Top = 144
+            Width = 146
+            AutoFill = True
+            Caption = 'Z-style'
+            ChildSizing.LeftRightSpacing = 6
+            ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
+            ChildSizing.EnlargeVertical = crsHomogenousChildResize
+            ChildSizing.ShrinkHorizontal = crsScaleChilds
+            ChildSizing.ShrinkVertical = crsScaleChilds
+            ChildSizing.Layout = cclLeftToRightThenTopToBottom
+            ChildSizing.ControlsPerLine = 1
+            ClientHeight = 61
+            ClientWidth = 142
+            Items.Strings = (
+              'zsFlat'
+              'zsLowered'
+              'zsRaised'
+            )
+            OnClick = rgLEDZStyleClick
+            TabOrder = 1
+          end
+          object lblLEDAltitude: TLabel
+            Left = 8
+            Height = 15
+            Top = 244
+            Width = 45
+            Caption = 'Altitude:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seLEDAltitude: TSpinEdit
+            Left = 73
+            Height = 23
+            Top = 240
+            Width = 58
+            OnChange = seLEDAltitudeChange
+            TabOrder = 2
+          end
+        end
+        object GroupBox6: TGroupBox
+          Left = 224
+          Height = 320
+          Top = 0
+          Width = 185
+          Caption = 'Component only'
+          ClientHeight = 300
+          ClientWidth = 181
+          TabOrder = 1
+          object cbLEDClickable: TCheckBox
+            Left = 8
+            Height = 19
+            Top = 8
+            Width = 66
+            Caption = 'Clickable'
+            TabOrder = 0
+            OnChange = cbLEDClickableChange
+          end
+          object lblLEDWidth: TLabel
+            Left = 8
+            Height = 15
+            Top = 43
+            Width = 35
+            Caption = 'Width:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seLEDWidth: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 40
+            Width = 58
+            OnChange = seLEDWidthChange
+            TabOrder = 1
+          end
+          object lblLEDHeight: TLabel
+            Left = 8
+            Height = 15
+            Top = 71
+            Width = 39
+            Caption = 'Heigth:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seLEDHeigth: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 68
+            Width = 58
+            OnChange = seLEDHeigthChange
+            TabOrder = 2
+          end
+          object cbLEDValue: TCheckBox
+            Left = 8
+            Height = 19
+            Top = 104
+            Width = 47
+            Caption = 'Value'
+            TabOrder = 3
+            OnChange = cbLEDValueChange
+          end
+        end
+      end
+      object tsSelector: TTabSheet
+        Caption = 'BCLeaSelector'
+        ClientHeight = 324
+        ClientWidth = 648
+        object GroupBox7: TGroupBox
+          Left = 320
+          Height = 320
+          Top = 0
+          Width = 185
+          Caption = 'Component only'
+          ClientHeight = 300
+          ClientWidth = 181
+          TabOrder = 0
+          object cbBSELDrawText: TCheckBox
+            Left = 8
+            Height = 19
+            Top = 8
+            Width = 68
+            Caption = 'Draw text'
+            TabOrder = 0
+            OnChange = cbBSELDrawTextChange
+          end
+          object lblBSELWidth: TLabel
+            Left = 8
+            Height = 15
+            Top = 243
+            Width = 35
+            Caption = 'Width:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seBSELWidth: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 240
+            Width = 58
+            OnChange = seBSELWidthChange
+            TabOrder = 1
+          end
+          object lblBSELHeight: TLabel
+            Left = 8
+            Height = 15
+            Top = 271
+            Width = 39
+            Caption = 'Heigth:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seBSELHeigth: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 268
+            Width = 58
+            OnChange = seBSELHeigthChange
+            TabOrder = 2
+          end
+          object cbBSELDrawTicks: TCheckBox
+            Left = 8
+            Height = 19
+            Top = 32
+            Width = 72
+            Caption = 'Draw ticks'
+            TabOrder = 3
+            OnChange = cbBSELDrawTicksChange
+          end
+          object cbtBSELFontColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 100
+            Width = 130
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Font Color'
+            Margin = 8
+            OnColorChanged = cbtBSELFontColorColorChanged
+          end
+          object seBSELFontHeigth: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 134
+            Width = 58
+            OnChange = seBSELFontHeigthChange
+            TabOrder = 4
+          end
+          object lblBSELFontHeight: TLabel
+            Left = 8
+            Height = 15
+            Top = 137
+            Width = 66
+            Caption = 'Font Heigth:'
+            ParentColor = False
+            Transparent = False
+          end
+        end
+        object GroupBox8: TGroupBox
+          Left = 0
+          Height = 320
+          Top = 0
+          Width = 320
+          Caption = 'Component and also in Theme BSelector'
+          ClientHeight = 300
+          ClientWidth = 316
+          TabOrder = 1
+          object cbtBSELLineColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 8
+            Width = 130
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Line Color'
+            Margin = 8
+            OnColorChanged = cbtBSELLineColorColorChanged
+          end
+          object cbtBSELLineBkgColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 37
+            Width = 130
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Line Bkg Color'
+            Margin = 8
+            OnColorChanged = cbtBSELLineBkgColorColorChanged
+          end
+          object cbtBSELBkgColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 65
+            Width = 130
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Bkg Color'
+            Margin = 8
+            OnColorChanged = cbtBSELBkgColorColorChanged
+          end
+          object lblBSELLineWidth: TLabel
+            Left = 8
+            Height = 15
+            Top = 100
+            Width = 58
+            Caption = 'Line width:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seBSELLineWidth: TSpinEdit
+            Left = 80
+            Height = 23
+            Top = 96
+            Width = 58
+            OnChange = seBSELLineWidthChange
+            TabOrder = 0
+          end
+          object rgBSELZStyle: TRadioGroup
+            Left = 8
+            Height = 81
+            Top = 144
+            Width = 130
+            AutoFill = True
+            Caption = 'Z-style'
+            ChildSizing.LeftRightSpacing = 6
+            ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
+            ChildSizing.EnlargeVertical = crsHomogenousChildResize
+            ChildSizing.ShrinkHorizontal = crsScaleChilds
+            ChildSizing.ShrinkVertical = crsScaleChilds
+            ChildSizing.Layout = cclLeftToRightThenTopToBottom
+            ChildSizing.ControlsPerLine = 1
+            ClientHeight = 61
+            ClientWidth = 126
+            Items.Strings = (
+              'zsFlat'
+              'zsLowered'
+              'zsRaised'
+            )
+            OnClick = rgBSELZStyleClick
+            TabOrder = 1
+          end
+          object lblBSELAltitude: TLabel
+            Left = 8
+            Height = 15
+            Top = 244
+            Width = 45
+            Caption = 'Altitude:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seBSELAltitude: TSpinEdit
+            Left = 80
+            Height = 23
+            Top = 240
+            Width = 58
+            OnChange = seBSELAltitudeChange
+            TabOrder = 2
+          end
+          object cbtBSELFontShadowColor: TColorButton
+            Left = 160
+            Height = 25
+            Top = 41
+            Width = 154
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Shadow Color'
+            Margin = 8
+            OnColorChanged = cbtBSELFontShadowColorColorChanged
+          end
+          object seBSELShadowOffsetX: TSpinEdit
+            Left = 256
+            Height = 23
+            Top = 72
+            Width = 58
+            OnChange = seBSELShadowOffsetXChange
+            TabOrder = 3
+          end
+          object lblBSELShadowOffsetX: TLabel
+            Left = 160
+            Height = 15
+            Top = 77
+            Width = 88
+            Caption = 'Shadow offset X:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seBSELShadowOffsetY: TSpinEdit
+            Left = 256
+            Height = 23
+            Top = 100
+            Width = 58
+            OnChange = seBSELShadowOffsetYChange
+            TabOrder = 4
+          end
+          object lblBSELShadowOffsetY: TLabel
+            Left = 160
+            Height = 15
+            Top = 104
+            Width = 88
+            Caption = 'Shadow offset Y:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seBSELShadowRadius: TSpinEdit
+            Left = 256
+            Height = 23
+            Top = 128
+            Width = 58
+            OnChange = seBSELShadowRadiusChange
+            TabOrder = 5
+          end
+          object lblBSELShadowRadius: TLabel
+            Left = 160
+            Height = 15
+            Top = 131
+            Width = 80
+            Caption = 'Shadow radius:'
+            ParentColor = False
+            Transparent = False
+          end
+          object lblBSELTextFont: TLabel
+            Left = 176
+            Height = 15
+            Top = 16
+            Width = 124
+            Caption = 'Additional font settings'
+            ParentColor = False
+            Transparent = False
+          end
+          object cbBSELDrawTextPhong: TCheckBox
+            Left = 160
+            Height = 19
+            Top = 156
+            Width = 100
+            Caption = 'Draw Text in 3D'
+            TabOrder = 6
+            OnChange = cbBSELDrawTextPhongChange
+          end
+          object seBSELPointerSize: TSpinEdit
+            Left = 80
+            Height = 23
+            Top = 270
+            Width = 58
+            OnChange = seBSELPointerSizeChange
+            TabOrder = 7
+          end
+          object lblBSELPointerSize: TLabel
+            Left = 8
+            Height = 15
+            Top = 272
+            Width = 63
+            Caption = 'Pointer size:'
+            ParentColor = False
+            Transparent = False
+          end
+        end
+      end
+      object tsRingSlider: TTabSheet
+        Caption = 'BCLeaRingSlider'
+        ClientHeight = 324
+        ClientWidth = 648
+        object GroupBox9: TGroupBox
+          Left = 0
+          Height = 320
+          Top = 0
+          Width = 320
+          Caption = 'Component and also in Theme BSelector'
+          ClientHeight = 300
+          ClientWidth = 316
+          TabOrder = 0
+          object cbtBRSLineColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 8
+            Width = 130
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Line Color'
+            Margin = 8
+            OnColorChanged = cbtBRSLineColorColorChanged
+          end
+          object cbtBRSLineBkgColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 37
+            Width = 130
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Line Bkg Color'
+            Margin = 8
+            OnColorChanged = cbtBRSLineBkgColorColorChanged
+          end
+          object cbtBRSBkgColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 65
+            Width = 130
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Bkg Color'
+            Margin = 8
+            OnColorChanged = cbtBRSBkgColorColorChanged
+          end
+          object lblBRSLineWidth: TLabel
+            Left = 8
+            Height = 15
+            Top = 100
+            Width = 58
+            Caption = 'Line width:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seBRSLineWidth: TSpinEdit
+            Left = 80
+            Height = 23
+            Top = 96
+            Width = 58
+            OnChange = seBRSLineWidthChange
+            TabOrder = 0
+          end
+          object rgBRSZStyle: TRadioGroup
+            Left = 8
+            Height = 81
+            Top = 144
+            Width = 130
+            AutoFill = True
+            Caption = 'Z-style'
+            ChildSizing.LeftRightSpacing = 6
+            ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
+            ChildSizing.EnlargeVertical = crsHomogenousChildResize
+            ChildSizing.ShrinkHorizontal = crsScaleChilds
+            ChildSizing.ShrinkVertical = crsScaleChilds
+            ChildSizing.Layout = cclLeftToRightThenTopToBottom
+            ChildSizing.ControlsPerLine = 1
+            ClientHeight = 61
+            ClientWidth = 126
+            Items.Strings = (
+              'zsFlat'
+              'zsLowered'
+              'zsRaised'
+            )
+            OnClick = rgBRSZStyleClick
+            TabOrder = 1
+          end
+          object lblBRSAltitude: TLabel
+            Left = 8
+            Height = 15
+            Top = 244
+            Width = 45
+            Caption = 'Altitude:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seBRSAltitude: TSpinEdit
+            Left = 80
+            Height = 23
+            Top = 240
+            Width = 58
+            OnChange = seBRSAltitudeChange
+            TabOrder = 2
+          end
+          object cbtBRSFontShadowColor: TColorButton
+            Left = 160
+            Height = 25
+            Top = 41
+            Width = 154
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Shadow Color'
+            Margin = 8
+            OnColorChanged = cbtBRSFontShadowColorColorChanged
+          end
+          object seBRSShadowOffsetX: TSpinEdit
+            Left = 256
+            Height = 23
+            Top = 72
+            Width = 58
+            OnChange = seBRSShadowOffsetXChange
+            TabOrder = 3
+          end
+          object lblBRSShadowOffsetX: TLabel
+            Left = 160
+            Height = 15
+            Top = 77
+            Width = 88
+            Caption = 'Shadow offset X:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seBRSShadowOffsetY: TSpinEdit
+            Left = 256
+            Height = 23
+            Top = 100
+            Width = 58
+            OnChange = seBRSShadowOffsetYChange
+            TabOrder = 4
+          end
+          object lblBRSShadowOffsetY: TLabel
+            Left = 160
+            Height = 15
+            Top = 104
+            Width = 88
+            Caption = 'Shadow offset Y:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seBRSShadowRadius: TSpinEdit
+            Left = 256
+            Height = 23
+            Top = 128
+            Width = 58
+            OnChange = seBRSShadowRadiusChange
+            TabOrder = 5
+          end
+          object lblBRSShadowRadius: TLabel
+            Left = 160
+            Height = 15
+            Top = 131
+            Width = 80
+            Caption = 'Shadow radius:'
+            ParentColor = False
+            Transparent = False
+          end
+          object lblBRSTextFont: TLabel
+            Left = 176
+            Height = 15
+            Top = 16
+            Width = 124
+            Caption = 'Additional font settings'
+            ParentColor = False
+            Transparent = False
+          end
+          object cbBRSDrawTextPhong: TCheckBox
+            Left = 160
+            Height = 19
+            Top = 156
+            Width = 100
+            Caption = 'Draw Text in 3D'
+            TabOrder = 6
+            OnChange = cbBRSDrawTextPhongChange
+          end
+          object seBRSPointerSize: TSpinEdit
+            Left = 80
+            Height = 23
+            Top = 270
+            Width = 58
+            OnChange = seBRSPointerSizeChange
+            TabOrder = 7
+          end
+          object lblBRSPointerSize: TLabel
+            Left = 8
+            Height = 15
+            Top = 272
+            Width = 63
+            Caption = 'Pointer size:'
+            ParentColor = False
+            Transparent = False
+          end
+          object cbtBRSPointerColor: TColorButton
+            Left = 160
+            Height = 25
+            Top = 268
+            Width = 154
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Pointer Color'
+            Margin = 8
+            OnColorChanged = cbtBRSPointerColorColorChanged
+          end
+        end
+        object GroupBox10: TGroupBox
+          Left = 320
+          Height = 320
+          Top = 0
+          Width = 185
+          Caption = 'Component only'
+          ClientHeight = 300
+          ClientWidth = 181
+          TabOrder = 1
+          object cbBRSDrawText: TCheckBox
+            Left = 8
+            Height = 19
+            Top = 8
+            Width = 68
+            Caption = 'Draw text'
+            TabOrder = 0
+            OnChange = cbBRSDrawTextChange
+          end
+          object lblBRSWidth: TLabel
+            Left = 8
+            Height = 15
+            Top = 243
+            Width = 35
+            Caption = 'Width:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seBRSWidth: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 240
+            Width = 58
+            OnChange = seBRSWidthChange
+            TabOrder = 1
+          end
+          object lblBRSHeight: TLabel
+            Left = 8
+            Height = 15
+            Top = 271
+            Width = 39
+            Caption = 'Heigth:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seBRSHeigth: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 268
+            Width = 58
+            OnChange = seBRSHeigthChange
+            TabOrder = 2
+          end
+          object cbtBRSFontColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 100
+            Width = 130
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Font Color'
+            Margin = 8
+            OnColorChanged = cbtBRSFontColorColorChanged
+          end
+          object seBRSFontHeigth: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 134
+            Width = 58
+            OnChange = seBRSFontHeigthChange
+            TabOrder = 3
+          end
+          object lblBRSFontHeight: TLabel
+            Left = 8
+            Height = 15
+            Top = 137
+            Width = 66
+            Caption = 'Font Heigth:'
+            ParentColor = False
+            Transparent = False
+          end
+          object cbBRSDrawPointer: TCheckBox
+            Left = 8
+            Height = 19
+            Top = 32
+            Width = 86
+            Caption = 'Draw pointer'
+            TabOrder = 4
+            OnChange = cbBRSDrawPointerChange
+          end
+        end
+      end
+      object tsQLED: TTabSheet
+        Caption = 'BCLeaQLED'
+        ClientHeight = 324
+        ClientWidth = 648
+        object GroupBox11: TGroupBox
+          Left = 0
+          Height = 320
+          Top = 0
+          Width = 224
+          Caption = 'Component and also in Theme BLED'
+          ClientHeight = 300
+          ClientWidth = 220
+          TabOrder = 0
+          object cbtQLEDColorOn: TColorButton
+            Left = 8
+            Height = 25
+            Top = 8
+            Width = 123
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Dot Color On'
+            Margin = 8
+            OnColorChanged = cbtQLEDColorOnColorChanged
+          end
+          object cbtQLEDColorOff: TColorButton
+            Left = 8
+            Height = 25
+            Top = 37
+            Width = 123
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Dot Color Off'
+            Margin = 8
+            OnColorChanged = cbtQLEDColorOffColorChanged
+          end
+          object cbtQLEDBkgColor: TColorButton
+            Left = 8
+            Height = 25
+            Top = 65
+            Width = 123
+            BorderWidth = 2
+            ButtonColorAutoSize = False
+            ButtonColorSize = 16
+            ButtonColor = clBlack
+            Caption = 'Bkg Color'
+            Margin = 8
+            OnColorChanged = cbtQLEDBkgColorColorChanged
+          end
+          object lblQLEDSize: TLabel
+            Left = 8
+            Height = 15
+            Top = 100
+            Width = 23
+            Caption = 'Size:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seQLEDSize: TSpinEdit
+            Left = 72
+            Height = 23
+            Top = 96
+            Width = 58
+            OnChange = seQLEDSizeChange
+            TabOrder = 0
+          end
+          object rgQLEDZStyle: TRadioGroup
+            Left = 8
+            Height = 81
+            Top = 144
+            Width = 146
+            AutoFill = True
+            Caption = 'Z-style'
+            ChildSizing.LeftRightSpacing = 6
+            ChildSizing.EnlargeHorizontal = crsHomogenousChildResize
+            ChildSizing.EnlargeVertical = crsHomogenousChildResize
+            ChildSizing.ShrinkHorizontal = crsScaleChilds
+            ChildSizing.ShrinkVertical = crsScaleChilds
+            ChildSizing.Layout = cclLeftToRightThenTopToBottom
+            ChildSizing.ControlsPerLine = 1
+            ClientHeight = 61
+            ClientWidth = 142
+            Items.Strings = (
+              'zsFlat'
+              'zsLowered'
+              'zsRaised'
+            )
+            OnClick = rgQLEDZStyleClick
+            TabOrder = 1
+          end
+          object lblQLEDAltitude: TLabel
+            Left = 8
+            Height = 15
+            Top = 244
+            Width = 45
+            Caption = 'Altitude:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seQLEDAltitude: TSpinEdit
+            Left = 73
+            Height = 23
+            Top = 240
+            Width = 58
+            OnChange = seQLEDAltitudeChange
+            TabOrder = 2
+          end
+          object seQLEDRounding: TSpinEdit
+            Left = 73
+            Height = 23
+            Top = 268
+            Width = 58
+            OnChange = seQLEDRoundingChange
+            TabOrder = 3
+          end
+          object lblQLEDRounding: TLabel
+            Left = 8
+            Height = 15
+            Top = 272
+            Width = 55
+            Caption = 'Rounding:'
+            ParentColor = False
+            Transparent = False
+          end
+        end
+        object GroupBox12: TGroupBox
+          Left = 224
+          Height = 320
+          Top = 0
+          Width = 185
+          Caption = 'Component only'
+          ClientHeight = 300
+          ClientWidth = 181
+          TabOrder = 1
+          object cbQLEDClickable: TCheckBox
+            Left = 8
+            Height = 19
+            Top = 8
+            Width = 66
+            Caption = 'Clickable'
+            TabOrder = 0
+            OnChange = cbQLEDClickableChange
+          end
+          object lblQLEDWidth: TLabel
+            Left = 8
+            Height = 15
+            Top = 43
+            Width = 35
+            Caption = 'Width:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seQLEDWidth: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 40
+            Width = 58
+            OnChange = seQLEDWidthChange
+            TabOrder = 1
+          end
+          object lblQLEDHeight: TLabel
+            Left = 8
+            Height = 15
+            Top = 71
+            Width = 39
+            Caption = 'Heigth:'
+            ParentColor = False
+            Transparent = False
+          end
+          object seQLEDHeigth: TSpinEdit
+            Left = 118
+            Height = 23
+            Top = 68
+            Width = 58
+            OnChange = seQLEDHeigthChange
+            TabOrder = 2
+          end
+          object cbQLEDValue: TCheckBox
+            Left = 8
+            Height = 19
+            Top = 104
+            Width = 47
+            Caption = 'Value'
+            TabOrder = 3
+            OnChange = cbQLEDValueChange
+          end
+        end
+      end
+    end
+  end
+  object Bevel1: TBevel
+    Left = 8
+    Height = 10
+    Top = 354
+    Width = 1047
+    Align = alBottom
+    BorderSpacing.Left = 8
+    BorderSpacing.Right = 8
+    Shape = bsBottomLine
+  end
+  object pnlComponents: TPanel
+    Left = 0
+    Height = 354
+    Top = 0
+    Width = 1063
+    Align = alClient
+    AutoSize = True
+    BevelOuter = bvNone
+    ClientHeight = 354
+    ClientWidth = 1063
+    ParentColor = False
+    TabOrder = 1
+    object LCDDisplay: TBCLeaLCDDisplay
+      AnchorSideLeft.Side = asrCenter
+      AnchorSideTop.Side = asrCenter
+      AnchorSideRight.Side = asrCenter
+      Left = 0
+      Height = 101
+      Top = 50
+      Width = 500
+      OnClick = LCDDisplayClick
+      OnMouseDown = LCDDisplayMouseDown
+      OnMouseMove = LCDDisplayMouseMove
+      OnMouseUp = LCDDisplayMouseUp
+      DisplayCharCount = 16
+      Lines.Strings = (
+        'BCLeaLCDDisplay'
+        ' '
+      )
+      DotShape = stRound
+      Theme = BTheme
+    end
+    object BLEDZoom: TBCLeaLED
+      AnchorSideLeft.Control = LCDDisplay
+      AnchorSideLeft.Side = asrBottom
+      AnchorSideTop.Control = LCDDisplay
+      AnchorSideTop.Side = asrCenter
+      Left = 500
+      Height = 100
+      Top = 50
+      Width = 100
+      TabOrder = 1
+      TabStop = False
+      Theme = BTheme
+    end
+    object BLED: TBCLeaLED
+      AnchorSideLeft.Control = BLEDZoom
+      AnchorSideLeft.Side = asrBottom
+      AnchorSideTop.Control = LCDDisplay
+      AnchorSideTop.Side = asrCenter
+      Left = 600
+      Height = 50
+      Top = 75
+      Width = 50
+      TabOrder = 2
+      TabStop = False
+      OnClick = BLEDClick
+      OnChangeValue = BLEDChangeValue
+      Theme = BTheme
+    end
+    object BSelector: TBCLeaSelector
+      AnchorSideLeft.Control = BLED
+      AnchorSideLeft.Side = asrBottom
+      AnchorSideTop.Control = LCDDisplay
+      AnchorSideTop.Side = asrCenter
+      Left = 650
+      Height = 100
+      Top = 50
+      Width = 100
+      Font.Color = clBlack
+      Font.Height = 20
+      ParentFont = False
+      TabOrder = 3
+      TabStop = False
+      OnClick = BSelectorClick
+      TicksCount = 2
+      Items.Strings = (
+        'Item 1'
+        'Item 2'
+        'Item 3'
+      )
+      MinTicksAngle = 150
+      MaxTicksAngle = 210
+      Theme = BTheme
+    end
+    object BRingSlider: TBCLeaRingSlider
+      AnchorSideLeft.Control = BSelector
+      AnchorSideLeft.Side = asrBottom
+      AnchorSideTop.Control = LCDDisplay
+      AnchorSideTop.Side = asrCenter
+      Left = 750
+      Height = 100
+      Top = 50
+      Width = 100
+      Caption = 'BRingSlider'
+      Font.Color = clBlack
+      Font.Height = 20
+      ParentFont = False
+      TabOrder = 4
+      TabStop = False
+      OnClick = BRingSliderClick
+      Value = 20
+      PointerSize = 3
+      Theme = BTheme
+    end
+    object Label1: TLabel
+      AnchorSideLeft.Control = BLEDZoom
+      AnchorSideLeft.Side = asrCenter
+      AnchorSideTop.Control = BLEDZoom
+      AnchorSideTop.Side = asrBottom
+      Left = 506
+      Height = 15
+      Top = 170
+      Width = 89
+      BorderSpacing.Top = 20
+      Caption = 'Zoomed preview'
+    end
+    object cbtPanelColor: TColorButton
+      AnchorSideLeft.Control = BLEDZoom
+      AnchorSideLeft.Side = asrCenter
+      Left = 489
+      Height = 24
+      Top = 0
+      Width = 123
+      BorderWidth = 2
+      ButtonColorAutoSize = False
+      ButtonColorSize = 16
+      ButtonColor = clBlack
+      Caption = 'Panel color'
+      Margin = 8
+      OnColorChanged = cbtPanelColorColorChanged
+    end
+    object BQLED: TBCLeaQLED
+      AnchorSideLeft.Control = BRingSlider
+      AnchorSideLeft.Side = asrBottom
+      AnchorSideTop.Control = LCDDisplay
+      AnchorSideTop.Side = asrCenter
+      Left = 850
+      Height = 50
+      Top = 75
+      Width = 50
+      TabOrder = 5
+      TabStop = False
+      OnClick = BQLEDClick
+      OnChangeValue = BQLEDChangeValue
+      Theme = BTheme
+    end
+  end
+  object MainMenu: TMainMenu
+    Left = 28
+    Top = 24
+    object miFile: TMenuItem
+      Caption = 'File'
+      object LoadChar: TMenuItem
+        Caption = 'Load char defs'
+        OnClick = btnLoadCharDefsClick
+      end
+      object SaveChar: TMenuItem
+        Caption = 'Save char defs'
+        OnClick = btnSaveCharDefsClick
+      end
+      object Separator1: TMenuItem
+        Caption = '-'
+      end
+      object LoadTheme: TMenuItem
+        Caption = 'Load theme'
+        OnClick = LoadThemeClick
+      end
+      object SaveTheme: TMenuItem
+        Caption = 'Save theme'
+        OnClick = SaveThemeClick
+      end
+      object Separator3: TMenuItem
+        Caption = '-'
+      end
+      object Quit: TMenuItem
+        Caption = 'Quit'
+        OnClick = QuitClick
+      end
+    end
+  end
+  object SaveDialog1: TSaveDialog
+    Filter = 'BCLea Theme|*.bclea'
+    Options = [ofOverwritePrompt, ofEnableSizing, ofViewDetail]
+    Left = 28
+    Top = 80
+  end
+  object OpenDialog1: TOpenDialog
+    Filter = 'BCLea Theme|*.bclea'
+    Left = 104
+    Top = 80
+  end
+  object BTheme: TBCLeaTheme
+    LCD_DotShape = stRound
+    SEL_LineWidth = 8
+    SEL_PointerSize = 3
+    RS_LineWidth = 8
+    RS_PointerSize = 3
+    Left = 104
+    Top = 24
+  end
+end

+ 1153 - 0
test/test_bclea/untThemeBuilder.pas

@@ -0,0 +1,1153 @@
+{
+ *****************************************************************************
+  See the file COPYING.modifiedLGPL.txt, included in this distribution,
+  for details about the license.
+ *****************************************************************************
+
+ Author: Boban Spasic
+}
+
+unit untThemeBuilder;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
+  Spin, Menus, ComCtrls, TypInfo, BCLeaLCDDisplay, BCLeaTheme,
+  BGRABitmapTypes, BCLeaTypes, BCLeaLED, BCLeaSelector, BCLeaRingSlider, BCLeaQLED;
+
+type
+
+  { TfrmMain }
+
+  TfrmMain = class(TForm)
+    BTheme: TBCLeaTheme;
+    Bevel1: TBevel;
+    BLEDZoom: TBCLeaLED;
+    BLED: TBCLeaLED;
+    BQLED: TBCLeaQLED;
+    BRingSlider: TBCLeaRingSlider;
+    BSelector: TBCLeaSelector;
+    cbLCDAutoSize: TCheckBox;
+    cbBRSDrawText: TCheckBox;
+    cbBRSDrawTextPhong: TCheckBox;
+    cbBRSDrawPointer: TCheckBox;
+    cbLEDClickable: TCheckBox;
+    cbBSELDrawText: TCheckBox;
+    cbQLEDClickable: TCheckBox;
+    cbLEDValue: TCheckBox;
+    cbLCDBlended: TCheckBox;
+    cbLCDBlendOperations: TComboBox;
+    cbLCDBlured: TCheckBox;
+    cbBSELDrawTicks: TCheckBox;
+    cbBSELDrawTextPhong: TCheckBox;
+    cbQLEDValue: TCheckBox;
+    cbL_DiffSat: TCheckBox;
+    cbtLCDBoardColor: TColorButton;
+    cbtBSELBkgColor: TColorButton;
+    cbtBRSBkgColor: TColorButton;
+    cbtBRSFontColor: TColorButton;
+    cbtBSELFontShadowColor: TColorButton;
+    cbtBSELFontColor: TColorButton;
+    cbtBRSFontShadowColor: TColorButton;
+    cbtBRSPointerColor: TColorButton;
+    cbtBRSLineBkgColor: TColorButton;
+    cbtBRSLineColor: TColorButton;
+    cbtQLEDBkgColor: TColorButton;
+    cbtLEDColorOff: TColorButton;
+    cbtLCDDotOnColor: TColorButton;
+    cbtLEDBkgColor: TColorButton;
+    cbtLCDFrameColor: TColorButton;
+    cbtBSELLineBkgColor: TColorButton;
+    cbtQLEDColorOff: TColorButton;
+    cbtLEDColorOn: TColorButton;
+    cbtBSELLineColor: TColorButton;
+    cbtQLEDColorOn: TColorButton;
+    cbtLightColor: TColorButton;
+    cbtPanelColor: TColorButton;
+    GroupBox1: TGroupBox;
+    GroupBox10: TGroupBox;
+    GroupBox11: TGroupBox;
+    GroupBox12: TGroupBox;
+    GroupBox2: TGroupBox;
+    GroupBox3: TGroupBox;
+    GroupBox4: TGroupBox;
+    GroupBox5: TGroupBox;
+    GroupBox6: TGroupBox;
+    GroupBox7: TGroupBox;
+    GroupBox8: TGroupBox;
+    GroupBox9: TGroupBox;
+    Label1: TLabel;
+    lblBRSAltitude: TLabel;
+    lblBSELFontHeight: TLabel;
+    lblBRSFontHeight: TLabel;
+    lblBRSHeight: TLabel;
+    lblBRSLineWidth: TLabel;
+    lblBSELPointerSize: TLabel;
+    lblBRSPointerSize: TLabel;
+    lblBSELShadowOffsetX: TLabel;
+    lblBRSShadowOffsetX: TLabel;
+    lblBSELShadowOffsetY: TLabel;
+    lblBRSShadowOffsetY: TLabel;
+    lblBSELShadowRadius: TLabel;
+    lblBRSShadowRadius: TLabel;
+    lblBSELTextFont: TLabel;
+    lblBRSTextFont: TLabel;
+    lblBRSWidth: TLabel;
+    lblLCDColorScheme: TLabel;
+    lblLCDCustomColors: TLabel;
+    lblLCDDisplayCharCount: TLabel;
+    lblLCDDisplayLineCount: TLabel;
+    lblLCDDotsBlended: TLabel;
+    lblLCDDotSize: TLabel;
+    lblLCDDotSpace: TLabel;
+    lblLCDFrameAltitude: TLabel;
+    lblLCDFrameHeight: TLabel;
+    lblBSELAltitude: TLabel;
+    lblQLEDAltitude: TLabel;
+    lblQLEDRounding: TLabel;
+    lblLEDHeight: TLabel;
+    lblBSELHeight: TLabel;
+    lblQLEDHeight: TLabel;
+    lblLEDSize: TLabel;
+    lblLCDFrameSize: TLabel;
+    lblLCDHeight: TLabel;
+    lblLEDAltitude: TLabel;
+    lblBSELLineWidth: TLabel;
+    lblBSELWidth: TLabel;
+    lblLCDLinesText: TLabel;
+    lblQLEDSize: TLabel;
+    lblQLEDWidth: TLabel;
+    lblL_1: TLabel;
+    lblL_10: TLabel;
+    lblL_11: TLabel;
+    lblL_12: TLabel;
+    lblL_2: TLabel;
+    lblL_3: TLabel;
+    lblL_4: TLabel;
+    lblL_5: TLabel;
+    lblL_6: TLabel;
+    lblL_7: TLabel;
+    lblL_8: TLabel;
+    lblL_9: TLabel;
+    lblLCDWidth: TLabel;
+    lblLEDWidth: TLabel;
+    LCDDisplay: TBCLeaLCDDisplay;
+    MainMenu: TMainMenu;
+    LoadTheme: TMenuItem;
+    mmLCDText: TMemo;
+    PageControl1: TPageControl;
+    pnlComponents: TPanel;
+    rgLCDBoardShadow: TRadioGroup;
+    rgBRSZStyle: TRadioGroup;
+    rgLCDDotShape: TRadioGroup;
+    rgLCDFrameStyle: TRadioGroup;
+    rgLEDZStyle: TRadioGroup;
+    rgBSELZStyle: TRadioGroup;
+    rgQLEDZStyle: TRadioGroup;
+    SaveTheme: TMenuItem;
+    seBRSAltitude: TSpinEdit;
+    seBSELFontHeigth: TSpinEdit;
+    seBRSFontHeigth: TSpinEdit;
+    seBRSHeigth: TSpinEdit;
+    seBRSLineWidth: TSpinEdit;
+    seBSELPointerSize: TSpinEdit;
+    seBRSPointerSize: TSpinEdit;
+    seBSELShadowOffsetX: TSpinEdit;
+    seBRSShadowOffsetX: TSpinEdit;
+    seBSELShadowOffsetY: TSpinEdit;
+    seBRSShadowOffsetY: TSpinEdit;
+    seBSELShadowRadius: TSpinEdit;
+    seBRSShadowRadius: TSpinEdit;
+    seBRSWidth: TSpinEdit;
+    seLCDDisplayCharCount: TSpinEdit;
+    seLCDDisplayLineCount: TSpinEdit;
+    seLCDDotBlured: TFloatSpinEdit;
+    seLCDDotSize: TSpinEdit;
+    seLCDDotsSpace: TSpinEdit;
+    seLCDFrameAltitude: TSpinEdit;
+    seLCDFrameHeight: TSpinEdit;
+    seBSELAltitude: TSpinEdit;
+    seQLEDAltitude: TSpinEdit;
+    seQLEDRounding: TSpinEdit;
+    seLEDHeigth: TSpinEdit;
+    seBSELHeigth: TSpinEdit;
+    seQLEDHeigth: TSpinEdit;
+    seLEDSize: TSpinEdit;
+    seLCDFrameSize: TSpinEdit;
+    seLCDHeigth: TSpinEdit;
+    seLEDAltitude: TSpinEdit;
+    seBSELLineWidth: TSpinEdit;
+    seBSELWidth: TSpinEdit;
+    seQLEDSize: TSpinEdit;
+    seQLEDWidth: TSpinEdit;
+    seL_Ambient: TFloatSpinEdit;
+    seL_DiffFact: TFloatSpinEdit;
+    seL_DistFact: TFloatSpinEdit;
+    seL_NegDiffFact: TFloatSpinEdit;
+    seL_PosX: TSpinEdit;
+    seL_PosY: TSpinEdit;
+    seL_PosZ: TSpinEdit;
+    seL_SpecFact: TFloatSpinEdit;
+    seL_SpecIndex: TFloatSpinEdit;
+    seL_SrcDistFact: TFloatSpinEdit;
+    seL_SrcDistTerm: TFloatSpinEdit;
+    seL_SrcIntens: TFloatSpinEdit;
+    Separator3: TMenuItem;
+    miFile: TMenuItem;
+    LoadChar: TMenuItem;
+    OpenDialog1: TOpenDialog;
+    SaveChar: TMenuItem;
+    SaveDialog1: TSaveDialog;
+    Quit: TMenuItem;
+    Separator1: TMenuItem;
+    pnlProperties: TPanel;
+    seLCDWidth: TSpinEdit;
+    seLEDWidth: TSpinEdit;
+    tsQLED: TTabSheet;
+    tsLCD: TTabSheet;
+    tsLED: TTabSheet;
+    tsSelector: TTabSheet;
+    tsRingSlider: TTabSheet;
+    procedure BThemeChange(Sender: TObject);
+    procedure BLEDChangeValue(Sender: TObject);
+    procedure BLEDClick(Sender: TObject);
+    procedure BQLEDChangeValue(Sender: TObject);
+    procedure BQLEDClick(Sender: TObject);
+    procedure BRingSliderClick(Sender: TObject);
+    procedure BSelectorClick(Sender: TObject);
+    procedure btnLoadCharDefsClick(Sender: TObject);
+    procedure btnSaveCharDefsClick(Sender: TObject);
+    procedure cbLCDAutoSizeChange(Sender: TObject);
+    procedure cbLCDBlendedChange(Sender: TObject);
+    procedure cbLCDBlendOperationsChange(Sender: TObject);
+    procedure cbLCDBluredChange(Sender: TObject);
+    procedure cbBRSDrawPointerChange(Sender: TObject);
+    procedure cbBRSDrawTextChange(Sender: TObject);
+    procedure cbBRSDrawTextPhongChange(Sender: TObject);
+    procedure cbBSELDrawTextChange(Sender: TObject);
+    procedure cbBSELDrawTextPhongChange(Sender: TObject);
+    procedure cbBSELDrawTicksChange(Sender: TObject);
+    procedure cbLEDClickableChange(Sender: TObject);
+    procedure cbLEDValueChange(Sender: TObject);
+    procedure cbL_DiffSatChange(Sender: TObject);
+    procedure cbQLEDClickableChange(Sender: TObject);
+    procedure cbQLEDValueChange(Sender: TObject);
+    procedure cbtBRSBkgColorColorChanged(Sender: TObject);
+    procedure cbtBRSFontColorColorChanged(Sender: TObject);
+    procedure cbtBRSFontShadowColorColorChanged(Sender: TObject);
+    procedure cbtBRSLineBkgColorColorChanged(Sender: TObject);
+    procedure cbtBRSLineColorColorChanged(Sender: TObject);
+    procedure cbtBRSPointerColorColorChanged(Sender: TObject);
+    procedure cbtBSELBkgColorColorChanged(Sender: TObject);
+    procedure cbtBSELFontColorColorChanged(Sender: TObject);
+    procedure cbtBSELFontShadowColorColorChanged(Sender: TObject);
+    procedure cbtBSELLineBkgColorColorChanged(Sender: TObject);
+    procedure cbtBSELLineColorColorChanged(Sender: TObject);
+    procedure cbtLEDBkgColorColorChanged(Sender: TObject);
+    procedure cbtLEDColorOffColorChanged(Sender: TObject);
+    procedure cbtLEDColorOnColorChanged(Sender: TObject);
+    procedure cbtPanelColorColorChanged(Sender: TObject);
+    procedure cbtLCDFrameColorColorChanged(Sender: TObject);
+    procedure cbtLCDBoardColorColorChanged(Sender: TObject);
+    procedure cbtLCDDotOnColorColorChanged(Sender: TObject);
+    procedure cbtLightColorColorChanged(Sender: TObject);
+    procedure cbtQLEDBkgColorColorChanged(Sender: TObject);
+    procedure cbtQLEDColorOffColorChanged(Sender: TObject);
+    procedure cbtQLEDColorOnColorChanged(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+    procedure FormShow(Sender: TObject);
+    procedure LCDDisplayClick(Sender: TObject);
+    procedure LCDDisplayMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+    procedure LCDDisplayMouseMove(Sender: TObject; Shift: TShiftState; X, Y: integer);
+    procedure LCDDisplayMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+    procedure LoadThemeClick(Sender: TObject);
+    procedure mmLCDTextChange(Sender: TObject);
+    procedure QuitClick(Sender: TObject);
+    procedure rgBRSZStyleClick(Sender: TObject);
+    procedure rgLCDBoardShadowClick(Sender: TObject);
+    procedure rgBSELZStyleClick(Sender: TObject);
+    procedure rgLCDFrameStyleClick(Sender: TObject);
+    procedure rgLCDDotShapeClick(Sender: TObject);
+    procedure rgLEDZStyleClick(Sender: TObject);
+    procedure rgQLEDZStyleClick(Sender: TObject);
+    procedure SaveThemeClick(Sender: TObject);
+    procedure seBRSAltitudeChange(Sender: TObject);
+    procedure seBRSFontHeigthChange(Sender: TObject);
+    procedure seBRSHeigthChange(Sender: TObject);
+    procedure seBRSLineWidthChange(Sender: TObject);
+    procedure seBRSPointerSizeChange(Sender: TObject);
+    procedure seBRSShadowOffsetXChange(Sender: TObject);
+    procedure seBRSShadowOffsetYChange(Sender: TObject);
+    procedure seBRSShadowRadiusChange(Sender: TObject);
+    procedure seBRSWidthChange(Sender: TObject);
+    procedure seBSELAltitudeChange(Sender: TObject);
+    procedure seBSELFontHeigthChange(Sender: TObject);
+    procedure seBSELHeigthChange(Sender: TObject);
+    procedure seBSELLineWidthChange(Sender: TObject);
+    procedure seBSELPointerSizeChange(Sender: TObject);
+    procedure seBSELShadowOffsetXChange(Sender: TObject);
+    procedure seBSELShadowOffsetYChange(Sender: TObject);
+    procedure seBSELShadowRadiusChange(Sender: TObject);
+    procedure seBSELWidthChange(Sender: TObject);
+    procedure seLCDDisplayCharCountChange(Sender: TObject);
+    procedure seLCDDotBluredChange(Sender: TObject);
+    procedure seLCDDotSizeChange(Sender: TObject);
+    procedure seLCDDotsSpaceChange(Sender: TObject);
+    procedure seLCDFrameAltitudeChange(Sender: TObject);
+    procedure seLCDFrameHeightChange(Sender: TObject);
+    procedure seLCDFrameSizeChange(Sender: TObject);
+    procedure seLCDHeigthChange(Sender: TObject);
+    procedure seLCDDisplayLineCountChange(Sender: TObject);
+    procedure seLEDAltitudeChange(Sender: TObject);
+    procedure seLEDHeigthChange(Sender: TObject);
+    procedure seLEDSizeChange(Sender: TObject);
+    procedure seLEDWidthChange(Sender: TObject);
+    procedure seL_AmbientChange(Sender: TObject);
+    procedure seL_DiffFactChange(Sender: TObject);
+    procedure seL_DistFactChange(Sender: TObject);
+    procedure seL_NegDiffFactChange(Sender: TObject);
+    procedure seL_PosXChange(Sender: TObject);
+    procedure seL_PosYChange(Sender: TObject);
+    procedure seL_PosZChange(Sender: TObject);
+    procedure seL_SpecFactChange(Sender: TObject);
+    procedure seL_SpecIndexChange(Sender: TObject);
+    procedure seL_SrcDistFactChange(Sender: TObject);
+    procedure seL_SrcDistTermChange(Sender: TObject);
+    procedure seL_SrcIntensChange(Sender: TObject);
+    procedure seLCDWidthChange(Sender: TObject);
+    procedure ReRead;
+    procedure ApplyTheme;
+    procedure seQLEDAltitudeChange(Sender: TObject);
+    procedure seQLEDHeigthChange(Sender: TObject);
+    procedure seQLEDRoundingChange(Sender: TObject);
+    procedure seQLEDSizeChange(Sender: TObject);
+    procedure seQLEDWidthChange(Sender: TObject);
+  private
+    FMouseDown: boolean;
+  public
+
+  end;
+
+var
+  frmMain: TfrmMain;
+
+implementation
+
+{$R *.lfm}
+
+{ TfrmMain }
+
+procedure TfrmMain.ApplyTheme;
+begin
+  LCDDisplay.ApplyTheme;
+  BLEDZoom.ApplyTheme;
+  BLED.ApplyTheme;
+  BLEDZoom.Size := 45;
+  BSelector.ApplyTheme;
+  BRingSlider.ApplyTheme;
+  BQLED.ApplyTheme;
+end;
+
+procedure TfrmMain.seQLEDAltitudeChange(Sender: TObject);
+begin
+  BQLED.Altitude := seQLEDAltitude.Value;
+  BTheme.QLED_Altitude := seQLEDAltitude.Value;
+end;
+
+procedure TfrmMain.seQLEDHeigthChange(Sender: TObject);
+begin
+  BQLED.Height := seQLEDHeigth.Value;
+end;
+
+procedure TfrmMain.seQLEDRoundingChange(Sender: TObject);
+begin
+  BQLED.Rounding := seQLEDRounding.Value;
+  BTheme.QLED_Rounding := seQLEDRounding.Value;
+end;
+
+procedure TfrmMain.seQLEDSizeChange(Sender: TObject);
+begin
+  BQLED.Size := seQLEDSize.Value;
+  BTheme.QLED_Size := seQLEDSize.Value;
+end;
+
+procedure TfrmMain.seQLEDWidthChange(Sender: TObject);
+begin
+  BQLED.Width := seQLEDWidth.Value;
+end;
+
+procedure TfrmMain.FormCreate(Sender: TObject);
+var
+  i: integer;
+  bo: TBlendOperation;
+begin
+  cbLCDBlendOperations.Items.Clear;
+  for bo := Low(TBlendOperation) to High(TBlendOperation) do
+    cbLCDBlendOperations.Items.Add(GetEnumName(typeinfo(TBlendOperation), integer(bo)));
+
+  FMouseDown := False;
+  // Fix TLabel transparency issue in Laz 2.2.2+
+  for i := 0 to ComponentCount - 1 do
+    if Components[i] is TLabel then
+      TLabel(Components[i]).Transparent := True;
+
+  PageControl1.ActivePage := tsLCD;
+end;
+
+procedure TfrmMain.FormShow(Sender: TObject);
+begin
+  if pnlComponents.Color <> clDefault then
+    cbtPanelColor.ButtonColor := pnlComponents.Color
+  else
+    cbtPanelColor.ButtonColor := clBtnFace;
+  BLEDZoom.Size := 45;
+  ReRead;
+end;
+
+procedure TfrmMain.cbtLCDFrameColorColorChanged(Sender: TObject);
+begin
+  LCDDisplay.FrameColor := cbtLCDFrameColor.ButtonColor;
+  BTheme.LCD_FrameColor := cbtLCDFrameColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtLCDBoardColorColorChanged(Sender: TObject);
+begin
+  LCDDisplay.BoardColor := cbtLCDBoardColor.ButtonColor;
+  BTheme.LCD_BoardColor := cbtLCDBoardColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtLCDDotOnColorColorChanged(Sender: TObject);
+begin
+  LCDDisplay.DotColorOn := cbtLCDDotOnColor.ButtonColor;
+  BTheme.LCD_DotColorOn := cbtLCDDotOnColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtLightColorColorChanged(Sender: TObject);
+begin
+  BTheme.COM_LightColor := cbtLightColor.ButtonColor;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.cbtQLEDBkgColorColorChanged(Sender: TObject);
+begin
+  BQLED.BackgroundColor := cbtQLEDBkgColor.ButtonColor;
+  BTheme.QLED_BkgColor := cbtQLEDBkgColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtQLEDColorOffColorChanged(Sender: TObject);
+begin
+  BQLED.ColorOff := cbtQLEDColorOff.ButtonColor;
+  BTheme.QLED_ColorOff := cbtQLEDColorOff.ButtonColor;
+end;
+
+procedure TfrmMain.cbtQLEDColorOnColorChanged(Sender: TObject);
+begin
+  BQLED.ColorOn := cbtQLEDColorOn.ButtonColor;
+  BTheme.QLED_ColorOn := cbtQLEDColorOn.ButtonColor;
+end;
+
+procedure TfrmMain.LCDDisplayClick(Sender: TObject);
+begin
+  PageControl1.ActivePage := tsLCD;
+end;
+
+procedure TfrmMain.LCDDisplayMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseDown(Button, Shift, X, Y);
+  if Button = mbLeft then
+    FMouseDown := True;
+end;
+
+procedure TfrmMain.LCDDisplayMouseMove(Sender: TObject; Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseMove(Shift, X, Y);
+  if FMouseDown then
+  begin
+    BTheme.COM_LightPositionY := Y;
+    BTheme.COM_LightPositionX := X;
+    ApplyTheme;
+  end;
+end;
+
+procedure TfrmMain.LCDDisplayMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: integer);
+begin
+  inherited MouseUp(Button, Shift, X, Y);
+  if Button = mbLeft then
+  begin
+    FMouseDown := False;
+  end;
+end;
+
+procedure TfrmMain.LoadThemeClick(Sender: TObject);
+begin
+  OpenDialog1.Filter := 'BCLea Theme|*.bclea';
+  if OpenDialog1.Execute then
+  begin
+    LCDDisplay.LoadThemeFromFile(OpenDialog1.FileName);
+    ApplyTheme;
+    ReRead;
+    frmMain.Caption:= 'Theme Builder - ' + ExtractFileName(OpenDialog1.FileName);
+  end;
+end;
+
+procedure TfrmMain.ReRead;
+begin
+  seL_Ambient.Value := BTheme.COM_AmbientFactor;
+  seL_SpecIndex.Value := BTheme.COM_SpecularIndex;
+  seL_SpecFact.Value := BTheme.COM_SpecularFactor;
+  seL_DistFact.Value := BTheme.COM_LightDestFactor;
+  seL_SrcIntens.Value := BTheme.COM_LightSourceIntensity;
+  seL_SrcDistTerm.Value := BTheme.COM_LightSourceDistanceTerm;
+  seL_SrcDistFact.Value := BTheme.COM_LightSourceDistanceFactor;
+  seL_DiffFact.Value := BTheme.COM_DiffusionFactor;
+  seL_NegDiffFact.Value := BTheme.COM_NegativeDiffusionFactor;
+  seL_PosX.Value := BTheme.COM_LightPositionX;
+  seL_PosY.Value := BTheme.COM_LightPositionY;
+  seL_PosZ.Value := BTheme.COM_LightPositionZ;
+  cbtLightColor.ButtonColor := BTheme.COM_LightColor;
+  cbL_DiffSat.Checked := BTheme.COM_DiffuseSaturation;
+  //BLCDDisplay
+  mmLCDText.Lines := LCDDisplay.Lines;
+  seLCDDisplayLineCount.Value := LCDDisplay.DisplayLineCount;
+  seLCDDisplayCharCount.Value := LCDDisplay.DisplayCharCount;
+  seLCDFrameSize.Value := LCDDisplay.FrameSize;
+  seLCDDotSize.Value := LCDDisplay.DotSize;
+  seLCDDotsSpace.Value := LCDDisplay.DotsSpace;
+  seLCDWidth.Value := LCDDisplay.Width;
+  seLCDHeigth.Value := LCDDisplay.Height;
+  cbLCDAutoSize.Checked := LCDDisplay.AutoSize;
+  cbtLCDFrameColor.ButtonColor := LCDDisplay.FrameColor;
+  cbtLCDBoardColor.ButtonColor := LCDDisplay.BoardColor;
+  cbtLCDDotOnColor.ButtonColor := LCDDisplay.DotColorOn;
+  rgLCDFrameStyle.ItemIndex := integer(LCDDisplay.FrameStyle);
+  rgLCDDotShape.ItemIndex := integer(LCDDisplay.DotShape);
+
+  rgLCDBoardShadow.ItemIndex := integer(BTheme.LCD_BoardShadow);
+  cbLCDBlendOperations.ItemIndex := integer(BTheme.LCD_DotBlendOperation);
+  cbLCDBlured.Checked := boolean(BTheme.LCD_DotBlur);
+  seLCDDotBlured.Value := single(BTheme.LCD_DotBlurRadius);
+  cbLCDBlended.Checked := boolean(BTheme.LCD_DotBlend);
+  seLCDFrameAltitude.Value := integer(LCDDisplay.FrameAltitude);
+  seLCDFrameHeight.Value := LCDDisplay.FrameHeight;
+  //BLED
+  cbtLEDColorOn.ButtonColor := BTheme.LED_ColorOn;
+  cbtLEDColorOff.ButtonColor := BTheme.LED_ColorOff;
+  cbtLEDBkgColor.ButtonColor := BTheme.LED_BkgColor;
+  seLEDSize.Value := BTheme.LED_Size;
+  cbLEDClickable.Checked := BLED.Clickable;
+  cbLEDValue.Checked := BLED.Value;
+  seLEDHeigth.Value := BLED.Height;
+  seLEDWidth.Value := BLED.Width;
+  rgLEDZStyle.ItemIndex := integer(BTheme.LED_Style);
+  seLEDAltitude.Value := BTheme.LED_Altitude;
+  //BCLeaSelector
+  seBSELLineWidth.Value := BTheme.SEL_LineWidth;
+  cbtBSELLineColor.ButtonColor := BTheme.SEL_LineColor;
+  cbtBSELLineBkgColor.ButtonColor := BTheme.SEL_LineBkgColor;
+  cbtBSELBkgColor.ButtonColor := BTheme.SEL_BkgColor;
+  cbtBSELFontShadowColor.ButtonColor := BTheme.SEL_FontShadowColor;
+  seBSELShadowOffsetX.Value := BTheme.SEL_FontShadowOffsetX;
+  seBSELShadowOffsetY.Value := BTheme.SEL_FontShadowOffsetY;
+  seBSELShadowRadius.Value := BTheme.SEL_FontShadowRadius;
+  seBSELPointerSize.Value := BTheme.SEL_PointerSize;
+  rgBSELZStyle.ItemIndex := integer(BTheme.SEL_Style);
+  cbBSELDrawTextPhong.Checked := BTheme.SEL_DrawTextPhong;
+  seBSELAltitude.Value := BTheme.SEL_Altitude;
+  cbBSELDrawText.Checked := BSelector.DrawText;
+  cbBSELDrawTicks.Checked := BSelector.DrawTicks;
+  seBSELWidth.Value := BSelector.Width;
+  seBSELHeigth.Value := BSelector.Height;
+  cbtBSELFontColor.ButtonColor := BSelector.Font.Color;
+  seBSELFontHeigth.Value := BSelector.Font.Height;
+  //RingSlider
+  seBRSLineWidth.Value := BTheme.RS_LineWidth;
+  cbtBRSLineColor.ButtonColor := BTheme.RS_LineColor;
+  cbtBRSLineBkgColor.ButtonColor := BTheme.RS_LineBkgColor;
+  cbtBRSBkgColor.ButtonColor := BTheme.RS_BkgColor;
+  cbtBRSFontShadowColor.ButtonColor := BTheme.RS_FontShadowColor;
+  seBRSShadowOffsetX.Value := BTheme.RS_FontShadowOffsetX;
+  seBRSShadowOffsetY.Value := BTheme.RS_FontShadowOffsetY;
+  seBRSShadowRadius.Value := BTheme.RS_FontShadowRadius;
+  seBRSPointerSize.Value := BTheme.RS_PointerSize;
+  cbtBRSPointerColor.ButtonColor := BTheme.RS_PointerColor;
+  rgBRSZStyle.ItemIndex := integer(BTheme.RS_Style);
+  cbBRSDrawTextPhong.Checked := BTheme.RS_DrawTextPhong;
+  seBRSAltitude.Value := BTheme.RS_Altitude;
+  cbBRSDrawText.Checked := BRingSlider.DrawText;
+  cbBRSDrawPointer.Checked := BRingSlider.DrawPointer;
+  seBRSWidth.Value := BRingSlider.Width;
+  seBRSHeigth.Value := BRingSlider.Height;
+  cbtBRSFontColor.ButtonColor := BRingSlider.Font.Color;
+  seBRSFontHeigth.Value := BRingSlider.Font.Height;
+  //BCLeaQLED
+  cbtQLEDColorOn.ButtonColor := BTheme.QLED_ColorOn;
+  cbtQLEDColorOff.ButtonColor := BTheme.QLED_ColorOff;
+  cbtQLEDBkgColor.ButtonColor := BTheme.QLED_BkgColor;
+  seQLEDSize.Value := BTheme.QLED_Size;
+  cbQLEDClickable.Checked := BQLED.Clickable;
+  cbQLEDValue.Checked := BQLED.Value;
+  seQLEDHeigth.Value := BQLED.Height;
+  seQLEDWidth.Value := BQLED.Width;
+  rgQLEDZStyle.ItemIndex := integer(BTheme.QLED_Style);
+  seQLEDAltitude.Value := BTheme.QLED_Altitude;
+  seQLEDRounding.Value := BTheme.QLED_Rounding;
+end;
+
+procedure TfrmMain.cbLCDAutoSizeChange(Sender: TObject);
+begin
+  LCDDisplay.AutoSize := cbLCDAutoSize.Checked;
+  if not cbLCDAutoSize.Checked then
+  begin
+    LCDDisplay.Width := seLCDWidth.Value;
+    LCDDisplay.Height := seLCDHeigth.Value;
+  end;
+  ReRead;
+end;
+
+procedure TfrmMain.cbLCDBlendedChange(Sender: TObject);
+begin
+  BTheme.LCD_DotBlend := cbLCDBlended.Checked;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.cbLCDBlendOperationsChange(Sender: TObject);
+begin
+  BTheme.LCD_DotBlendOperation := TBlendOperation(cbLCDBlendOperations.ItemIndex);
+  ApplyTheme;
+end;
+
+procedure TfrmMain.cbLCDBluredChange(Sender: TObject);
+begin
+  BTheme.LCD_DotBlur := cbLCDBlured.Checked;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.cbBRSDrawPointerChange(Sender: TObject);
+begin
+  BRingSlider.DrawPointer := cbBRSDrawPointer.Checked;
+end;
+
+procedure TfrmMain.cbBRSDrawTextChange(Sender: TObject);
+begin
+  BRingSlider.DrawText := cbBRSDrawText.Checked;
+end;
+
+procedure TfrmMain.cbBRSDrawTextPhongChange(Sender: TObject);
+begin
+  BRingSlider.DrawTextPhong := cbBRSDrawTextPhong.Checked;
+  BTheme.RS_DrawTextPhong := cbBRSDrawTextPhong.Checked;
+end;
+
+procedure TfrmMain.cbBSELDrawTextChange(Sender: TObject);
+begin
+  BSelector.DrawText := cbBSELDrawText.Checked;
+end;
+
+procedure TfrmMain.cbBSELDrawTextPhongChange(Sender: TObject);
+begin
+  BSelector.DrawTextPhong := cbBSELDrawTextPhong.Checked;
+  BTheme.SEL_DrawTextPhong := cbBSELDrawTextPhong.Checked;
+end;
+
+procedure TfrmMain.cbBSELDrawTicksChange(Sender: TObject);
+begin
+  BSelector.DrawTicks := cbBSELDrawTicks.Checked;
+end;
+
+procedure TfrmMain.btnSaveCharDefsClick(Sender: TObject);
+begin
+  SaveDialog1.Filter := 'BCLeaLCDDisplay CharDefs|*.char.xml';
+  if SaveDialog1.Execute then
+    LCDDisplay.CharDefs.SaveToFile(SaveDialog1.FileName);
+end;
+
+procedure TfrmMain.btnLoadCharDefsClick(Sender: TObject);
+begin
+  OpenDialog1.Filter := 'BCLeaLCDDisplay CharDefs|*.char.xml';
+  if OpenDialog1.Execute then
+    LCDDisplay.CharDefs.LoadFromFile(OpenDialog1.FileName);
+end;
+
+procedure TfrmMain.BThemeChange(Sender: TObject);
+begin
+  //ApplyTheme;
+  //ReRead;
+end;
+
+procedure TfrmMain.BLEDChangeValue(Sender: TObject);
+begin
+  BLEDZoom.Value := BLED.Value;
+  ReRead;
+end;
+
+procedure TfrmMain.BLEDClick(Sender: TObject);
+begin
+  PageControl1.ActivePage := tsLED;
+end;
+
+procedure TfrmMain.BQLEDChangeValue(Sender: TObject);
+begin
+  ReRead;
+end;
+
+procedure TfrmMain.BQLEDClick(Sender: TObject);
+begin
+  PageControl1.ActivePage := tsQLED;
+end;
+
+procedure TfrmMain.BRingSliderClick(Sender: TObject);
+begin
+  PageControl1.ActivePage := tsRingSlider;
+end;
+
+procedure TfrmMain.BSelectorClick(Sender: TObject);
+begin
+  PageControl1.ActivePage := tsSelector;
+end;
+
+procedure TfrmMain.cbLEDClickableChange(Sender: TObject);
+begin
+  BLED.Clickable := cbLEDClickable.Checked;
+end;
+
+procedure TfrmMain.cbLEDValueChange(Sender: TObject);
+begin
+  BLED.Value := cbLEDValue.Checked;
+  BLEDZoom.Value := cbLEDValue.Checked;
+end;
+
+procedure TfrmMain.cbL_DiffSatChange(Sender: TObject);
+begin
+  BTheme.COM_DiffuseSaturation := cbL_DiffSat.Checked;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.cbQLEDClickableChange(Sender: TObject);
+begin
+  BQLED.Clickable := cbQLEDClickable.Checked;
+end;
+
+procedure TfrmMain.cbQLEDValueChange(Sender: TObject);
+begin
+  BQLED.Value := cbQLEDValue.Checked;
+end;
+
+procedure TfrmMain.cbtBRSBkgColorColorChanged(Sender: TObject);
+begin
+  BRingSlider.BackgroundColor := cbtBRSBkgColor.ButtonColor;
+  BTheme.RS_BkgColor := cbtBRSBkgColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtBRSFontColorColorChanged(Sender: TObject);
+begin
+  BRingSlider.Font.Color := cbtBRSFontColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtBRSFontShadowColorColorChanged(Sender: TObject);
+begin
+  BRingSlider.FontShadowColor := cbtBRSFontShadowColor.ButtonColor;
+  BTheme.RS_FontShadowColor := cbtBRSFontShadowColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtBRSLineBkgColorColorChanged(Sender: TObject);
+begin
+  BRingSlider.LineBkgColor := cbtBRSLineBkgColor.ButtonColor;
+  BTheme.RS_LineBkgColor := cbtBRSLineBkgColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtBRSLineColorColorChanged(Sender: TObject);
+begin
+  BRingSlider.LineColor := cbtBRSLineColor.ButtonColor;
+  BTheme.RS_LineColor := cbtBRSLineColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtBRSPointerColorColorChanged(Sender: TObject);
+begin
+  BRingSlider.PointerColor := cbtBRSPointerColor.ButtonColor;
+  BTheme.RS_PointerColor := cbtBRSPointerColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtBSELBkgColorColorChanged(Sender: TObject);
+begin
+  BSelector.BackgroundColor := cbtBSELBkgColor.ButtonColor;
+  BTheme.SEL_BkgColor := cbtBSELBkgColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtBSELFontColorColorChanged(Sender: TObject);
+begin
+  BSelector.Font.Color := cbtBSELFontColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtBSELFontShadowColorColorChanged(Sender: TObject);
+begin
+  BSelector.FontShadowColor := cbtBSELFontShadowColor.ButtonColor;
+  BTheme.SEL_FontShadowColor := cbtBSELFontShadowColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtBSELLineBkgColorColorChanged(Sender: TObject);
+begin
+  BSelector.LineBkgColor := cbtBSELLineBkgColor.ButtonColor;
+  BTheme.SEL_LineBkgColor := cbtBSELLineBkgColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtBSELLineColorColorChanged(Sender: TObject);
+begin
+  BSelector.LineColor := cbtBSELLineColor.ButtonColor;
+  BTheme.SEL_LineColor := cbtBSELLineColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtLEDBkgColorColorChanged(Sender: TObject);
+begin
+  BLED.BackgroundColor := cbtLEDBkgColor.ButtonColor;
+  BLEDZoom.BackgroundColor := cbtLEDBkgColor.ButtonColor;
+  BTheme.LED_BkgColor := cbtLEDBkgColor.ButtonColor;
+end;
+
+procedure TfrmMain.cbtLEDColorOffColorChanged(Sender: TObject);
+begin
+  BLED.ColorOff := cbtLEDColorOff.ButtonColor;
+  BLEDZoom.ColorOff := cbtLEDColorOff.ButtonColor;
+  BTheme.LED_ColorOff := cbtLEDColorOff.ButtonColor;
+end;
+
+procedure TfrmMain.cbtLEDColorOnColorChanged(Sender: TObject);
+begin
+  BLED.ColorOn := cbtLEDColorOn.ButtonColor;
+  BLEDZoom.ColorOn := cbtLEDColorOn.ButtonColor;
+  BTheme.LED_ColorOn := cbtLEDColorOn.ButtonColor;
+end;
+
+procedure TfrmMain.cbtPanelColorColorChanged(Sender: TObject);
+begin
+  pnlComponents.Color := cbtPanelColor.ButtonColor;
+  pnlComponents.Invalidate;
+end;
+
+procedure TfrmMain.mmLCDTextChange(Sender: TObject);
+begin
+  LCDDisplay.Lines.Assign(mmLCDText.Lines);
+end;
+
+procedure TfrmMain.QuitClick(Sender: TObject);
+begin
+  Close;
+end;
+
+procedure TfrmMain.rgBRSZStyleClick(Sender: TObject);
+begin
+  BRingSlider.Style := TZStyle(rgBRSZStyle.ItemIndex);
+  BTheme.RS_Style := TZStyle(rgBRSZStyle.ItemIndex);
+end;
+
+procedure TfrmMain.rgLCDBoardShadowClick(Sender: TObject);
+begin
+  BTheme.LCD_BoardShadow := TBoardShadow(rgLCDBoardShadow.ItemIndex);
+  ApplyTheme;
+end;
+
+procedure TfrmMain.rgBSELZStyleClick(Sender: TObject);
+begin
+  BSelector.Style := TZStyle(rgBSELZStyle.ItemIndex);
+  BTheme.SEL_Style := TZStyle(rgBSELZStyle.ItemIndex);
+end;
+
+procedure TfrmMain.rgLCDFrameStyleClick(Sender: TObject);
+begin
+  LCDDisplay.FrameStyle := TZStyle(rgLCDFrameStyle.ItemIndex);
+  BTheme.LCD_FrameStyle := TZStyle(rgLCDFrameStyle.ItemIndex);
+end;
+
+procedure TfrmMain.rgLCDDotShapeClick(Sender: TObject);
+begin
+  LCDDisplay.DotShape := TDotShape(rgLCDDotShape.ItemIndex);
+  BTheme.LCD_DotShape := TDotShape(rgLCDDotShape.ItemIndex);
+end;
+
+procedure TfrmMain.rgLEDZStyleClick(Sender: TObject);
+begin
+  BLED.Style := TZStyle(rgLEDZStyle.ItemIndex);
+  BLEDZoom.Style := TZStyle(rgLEDZStyle.ItemIndex);
+  BTheme.LED_Style := TZStyle(rgLEDZStyle.ItemIndex);
+end;
+
+procedure TfrmMain.rgQLEDZStyleClick(Sender: TObject);
+begin
+  BQLED.Style := TZStyle(rgQLEDZStyle.ItemIndex);
+  BTheme.QLED_Style := TZStyle(rgQLEDZStyle.ItemIndex);
+end;
+
+procedure TfrmMain.SaveThemeClick(Sender: TObject);
+begin
+  SaveDialog1.Filter := 'BCLea Theme|*.bclea';
+  if SaveDialog1.Execute then
+  begin
+    LCDDisplay.UpdateTheme;
+    LCDDisplay.SaveThemeToFile(SaveDialog1.FileName);
+    frmMain.Caption:= 'Theme Builder - ' + ExtractFileName(SaveDialog1.FileName);
+  end;
+end;
+
+procedure TfrmMain.seBRSAltitudeChange(Sender: TObject);
+begin
+  BRingSlider.Altitude := seBRSAltitude.Value;
+  BTheme.RS_Altitude := seBRSAltitude.Value;
+end;
+
+procedure TfrmMain.seBRSFontHeigthChange(Sender: TObject);
+begin
+  BRingSlider.Font.Height := seBRSFontHeigth.Value;
+end;
+
+procedure TfrmMain.seBRSHeigthChange(Sender: TObject);
+begin
+  BRingSlider.Height := seBRSHeigth.Value;
+end;
+
+procedure TfrmMain.seBRSLineWidthChange(Sender: TObject);
+begin
+  BRingSlider.LineWidth := seBRSLineWidth.Value;
+  BTheme.RS_LineWidth := seBRSLineWidth.Value;
+end;
+
+procedure TfrmMain.seBRSPointerSizeChange(Sender: TObject);
+begin
+  BRingSlider.PointerSize := seBRSPointerSize.Value;
+  BTheme.RS_PointerSize := seBRSPointerSize.Value;
+end;
+
+procedure TfrmMain.seBRSShadowOffsetXChange(Sender: TObject);
+begin
+  BRingSlider.FontShadowOffsetX := seBRSShadowOffsetX.Value;
+  BTheme.RS_FontShadowOffsetX := seBRSShadowOffsetX.Value;
+end;
+
+procedure TfrmMain.seBRSShadowOffsetYChange(Sender: TObject);
+begin
+  BRingSlider.FontShadowOffsetY := seBRSShadowOffsetY.Value;
+  BTheme.RS_FontShadowOffsetY := seBRSShadowOffsetY.Value;
+end;
+
+procedure TfrmMain.seBRSShadowRadiusChange(Sender: TObject);
+begin
+  BRingSlider.FontShadowRadius := seBRSShadowRadius.Value;
+  BTheme.RS_FontShadowRadius := seBRSShadowRadius.Value;
+end;
+
+procedure TfrmMain.seBRSWidthChange(Sender: TObject);
+begin
+  BRingSlider.Width := seBRSWidth.Value;
+end;
+
+procedure TfrmMain.seBSELAltitudeChange(Sender: TObject);
+begin
+  BSelector.Altitude := seBSELAltitude.Value;
+  BTheme.SEL_Altitude := seBSELAltitude.Value;
+end;
+
+procedure TfrmMain.seBSELFontHeigthChange(Sender: TObject);
+begin
+  BSelector.Font.Height := seBSELFontHeigth.Value;
+end;
+
+procedure TfrmMain.seBSELHeigthChange(Sender: TObject);
+begin
+  BSelector.Height := seBSELHeigth.Value;
+end;
+
+procedure TfrmMain.seBSELLineWidthChange(Sender: TObject);
+begin
+  BSelector.LineWidth := seBSELLineWidth.Value;
+  BTheme.SEL_LineWidth := seBSELLineWidth.Value;
+end;
+
+procedure TfrmMain.seBSELPointerSizeChange(Sender: TObject);
+begin
+  BSelector.PointerSize := seBSELPointerSize.Value;
+  BTheme.SEL_PointerSize := seBSELPointerSize.Value;
+end;
+
+procedure TfrmMain.seBSELShadowOffsetXChange(Sender: TObject);
+begin
+  BSelector.FontShadowOffsetX := seBSELShadowOffsetX.Value;
+  BTheme.SEL_FontShadowOffsetX := seBSELShadowOffsetX.Value;
+end;
+
+procedure TfrmMain.seBSELShadowOffsetYChange(Sender: TObject);
+begin
+  BSelector.FontShadowOffsetY := seBSELShadowOffsetY.Value;
+  BTheme.SEL_FontShadowOffsetY := seBSELShadowOffsetY.Value;
+end;
+
+procedure TfrmMain.seBSELShadowRadiusChange(Sender: TObject);
+begin
+  BSelector.FontShadowRadius := seBSELShadowRadius.Value;
+  BTheme.SEL_FontShadowRadius := seBSELShadowRadius.Value;
+end;
+
+procedure TfrmMain.seBSELWidthChange(Sender: TObject);
+begin
+  BSelector.Width := seBSELWidth.Value;
+end;
+
+procedure TfrmMain.seLCDDisplayCharCountChange(Sender: TObject);
+begin
+  LCDDisplay.DisplayCharCount := seLCDDisplayCharCount.Value;
+  ReRead;
+end;
+
+procedure TfrmMain.seLCDDotBluredChange(Sender: TObject);
+begin
+  BTheme.LCD_DotBlurRadius := seLCDDotBlured.Value;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.seLCDDotSizeChange(Sender: TObject);
+begin
+  LCDDisplay.DotSize := seLCDDotSize.Value;
+  BTheme.LCD_DotSize := seLCDDotSize.Value;
+end;
+
+procedure TfrmMain.seLCDDotsSpaceChange(Sender: TObject);
+begin
+  LCDDisplay.DotsSpace := seLCDDotsSpace.Value;
+  BTheme.LCD_DotsSpace := seLCDDotsSpace.Value;
+end;
+
+procedure TfrmMain.seLCDFrameAltitudeChange(Sender: TObject);
+begin
+  LCDDisplay.FrameAltitude := seLCDFrameAltitude.Value;
+  BTheme.LCD_FrameAltitude := seLCDFrameAltitude.Value;
+end;
+
+procedure TfrmMain.seLCDFrameHeightChange(Sender: TObject);
+begin
+  LCDDisplay.FrameHeight := seLCDFrameHeight.Value;
+  BTheme.LCD_FrameHeight := seLCDFrameHeight.Value;
+end;
+
+procedure TfrmMain.seLCDFrameSizeChange(Sender: TObject);
+begin
+  LCDDisplay.FrameSize := seLCDFrameSize.Value;
+  BTheme.LCD_FrameSize := seLCDFrameSize.Value;
+end;
+
+procedure TfrmMain.seLCDHeigthChange(Sender: TObject);
+begin
+  LCDDisplay.Height := seLCDHeigth.Value;
+end;
+
+procedure TfrmMain.seLCDDisplayLineCountChange(Sender: TObject);
+begin
+  LCDDisplay.DisplayLineCount := seLCDDisplayLineCount.Value;
+  ReRead;
+end;
+
+procedure TfrmMain.seLEDAltitudeChange(Sender: TObject);
+begin
+  BLED.Altitude := seLEDAltitude.Value;
+  BLEDZoom.Altitude := seLEDAltitude.Value;
+  BTheme.LED_Altitude := seLEDAltitude.Value;
+end;
+
+procedure TfrmMain.seLEDHeigthChange(Sender: TObject);
+begin
+  BLED.Height := seLEDHeigth.Value;
+end;
+
+procedure TfrmMain.seLEDSizeChange(Sender: TObject);
+begin
+  BLED.Size := seLEDSize.Value;
+  BTheme.LED_Size := seLEDSize.Value;
+  BLEDZoom.Size := 45;
+end;
+
+procedure TfrmMain.seLEDWidthChange(Sender: TObject);
+begin
+  BLED.Width := seLEDWidth.Value;
+end;
+
+procedure TfrmMain.seL_AmbientChange(Sender: TObject);
+begin
+  BTheme.COM_AmbientFactor := seL_Ambient.Value;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.seL_DiffFactChange(Sender: TObject);
+begin
+  BTheme.COM_DiffusionFactor := seL_DiffFact.Value;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.seL_DistFactChange(Sender: TObject);
+begin
+  BTheme.COM_LightSourceDistanceFactor := seL_DistFact.Value;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.seL_NegDiffFactChange(Sender: TObject);
+begin
+  BTheme.COM_NegativeDiffusionFactor := seL_NegDiffFact.Value;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.seL_PosXChange(Sender: TObject);
+begin
+  BTheme.COM_LightPositionX := seL_PosX.Value;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.seL_PosYChange(Sender: TObject);
+begin
+  BTheme.COM_LightPositionY := seL_PosY.Value;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.seL_PosZChange(Sender: TObject);
+begin
+  if seL_PosZ.Value > 0 then
+  begin
+    BTheme.COM_LightPositionZ := seL_PosZ.Value;
+    ApplyTheme;
+  end;
+end;
+
+procedure TfrmMain.seL_SpecFactChange(Sender: TObject);
+begin
+  BTheme.COM_SpecularFactor := seL_SpecFact.Value;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.seL_SpecIndexChange(Sender: TObject);
+begin
+  BTheme.COM_SpecularIndex := seL_SpecIndex.Value;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.seL_SrcDistFactChange(Sender: TObject);
+begin
+  BTheme.COM_LightSourceDistanceFactor := seL_SrcDistFact.Value;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.seL_SrcDistTermChange(Sender: TObject);
+begin
+  BTheme.COM_LightSourceDistanceTerm := seL_SrcDistTerm.Value;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.seL_SrcIntensChange(Sender: TObject);
+begin
+  BTheme.COM_LightSourceIntensity := seL_SrcIntens.Value;
+  ApplyTheme;
+end;
+
+procedure TfrmMain.seLCDWidthChange(Sender: TObject);
+begin
+  LCDDisplay.Width := seLCDWidth.Value;
+  ReRead;
+end;
+
+end.