Pārlūkot izejas kodu

Merge pull request #252 from sganz/dev-bgracontrols

New SuperLED component and test program
Leandro Oscar Ezequiel Diaz 4 mēneši atpakaļ
vecāks
revīzija
dc028fd968

+ 6 - 0
README.md

@@ -222,6 +222,12 @@ Another gauge.
 
 Author: Digeo.
 
+### TSuperLED
+![SuperLED](docs/img/SuperLED.png)
+Flexible nice looking LED display component. Supports fast drawing, many options, easy to use. All BGRA based.
+
+Author: Sandy Ganz
+
 ### TSuperGauge
 ![SuperGauge](docs/img/SuperGauge-V200.png)
 Updated and Enhanced Analog Gauge. Many new features, faster drawing, additonal events

+ 17 - 12
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="2"/>
-    <Files Count="84">
+    <Files Count="85">
       <Item1>
         <Filename Value="atshapelinebgra.pas"/>
         <HasRegisterProc Value="True"/>
@@ -274,14 +274,14 @@
         <UnitName Value="BGRAKnob"/>
       </Item50>
       <Item51>
-        <Filename Value="bgraresizespeedbutton.pas"/>
+        <Filename Value="bgrashape.pas"/>
         <HasRegisterProc Value="True"/>
-        <UnitName Value="BGRAResizeSpeedButton"/>
+        <UnitName Value="BGRAShape"/>
       </Item51>
       <Item52>
-        <Filename Value="bgrashape.pas"/>
+        <Filename Value="bgraresizespeedbutton.pas"/>
         <HasRegisterProc Value="True"/>
-        <UnitName Value="BGRAShape"/>
+        <UnitName Value="BGRAResizeSpeedButton"/>
       </Item52>
       <Item53>
         <Filename Value="bgraspeedbutton.pas"/>
@@ -422,23 +422,28 @@
         <UnitName Value="SuperGaugeCommon"/>
       </Item80>
       <Item81>
-        <Filename Value="bgradialogs.pas"/>
+        <Filename Value="superled.pas"/>
         <HasRegisterProc Value="True"/>
-        <UnitName Value="BGRADialogs"/>
+        <UnitName Value="superled"/>
       </Item81>
       <Item82>
-        <Filename Value="bgraformatui.pas"/>
-        <UnitName Value="BGRAFormatUI"/>
+        <Filename Value="bgradialogs.pas"/>
+        <HasRegisterProc Value="True"/>
+        <UnitName Value="BGRADialogs"/>
       </Item82>
       <Item83>
+        <Filename Value="bgraformatui.pas"/>
+        <UnitName Value="BGRAFormatUI"/>
+      </Item83>
+      <Item84>
         <Filename Value="superspinner.pas"/>
         <HasRegisterProc Value="True"/>
         <UnitName Value="SuperSpinner"/>
-      </Item83>
-      <Item84>
+      </Item84>
+      <Item85>
         <Filename Value="superspinnercommon.pas"/>
         <UnitName Value="SuperSpinnerCommon"/>
-      </Item84>
+      </Item85>
     </Files>
     <CompatibilityMode Value="True"/>
     <LazDoc Paths="fpdoc"/>

+ 11 - 9
bgracontrols.pas

@@ -19,14 +19,15 @@ uses
   BCSVGButton, BCSVGViewer, BCThemeManager, BCToolBar, BCTools, 
   BCTrackbarUpdown, BCTypes, BGRAColorTheme, BGRAControlsInfo, 
   BGRACustomDrawn, BGRAFlashProgressBar, BGRAGraphicControl, BGRAImageList, 
-  BGRAImageManipulation, BGRAImageTheme, BGRAKnob, BGRAResizeSpeedButton, 
-  BGRAShape, BGRASpeedButton, BGRASpriteAnimation, BGRASVGImageList, 
-  BGRASVGTheme, BGRATheme, BGRAThemeButton, BGRAThemeCheckBox, 
-  BGRAThemeRadioButton, BGRAVirtualScreen, ColorSpeedButton, DTAnalogClock, 
-  DTAnalogCommon, DTAnalogGauge, DTThemedClock, DTThemedGauge, MaterialColors, 
-  bgrasvgimagelistform, BCLeaLCDDisplay, BCLeaLED, BCLeaQLED, BCLeaRingSlider, 
-  BCLeaSelector, BCLeaTheme, BCLeaLCDDisplay_EditorRegister, BCLeaBoard, 
-  BCLeaEngrave, SuperGauge, SuperGaugeCommon, BGRADialogs, BGRAFormatUI, 
+  BGRAImageManipulation, BGRAImageTheme, BGRAKnob, BGRAShape, 
+  BGRAResizeSpeedButton, BGRASpeedButton, BGRASpriteAnimation, 
+  BGRASVGImageList, BGRASVGTheme, BGRATheme, BGRAThemeButton, 
+  BGRAThemeCheckBox, BGRAThemeRadioButton, BGRAVirtualScreen, 
+  ColorSpeedButton, DTAnalogClock, DTAnalogCommon, DTAnalogGauge, 
+  DTThemedClock, DTThemedGauge, MaterialColors, bgrasvgimagelistform, 
+  BCLeaLCDDisplay, BCLeaLED, BCLeaQLED, BCLeaRingSlider, BCLeaSelector, 
+  BCLeaTheme, BCLeaLCDDisplay_EditorRegister, BCLeaBoard, BCLeaEngrave, 
+  SuperGauge, SuperGaugeCommon, SuperLED, BGRADialogs, BGRAFormatUI,
   SuperSpinner, SuperSpinnerCommon, LazarusPackageIntf;
 
 implementation
@@ -72,8 +73,8 @@ begin
   RegisterUnit('BGRAImageManipulation', @BGRAImageManipulation.Register);
   RegisterUnit('BGRAImageTheme', @BGRAImageTheme.Register);
   RegisterUnit('BGRAKnob', @BGRAKnob.Register);
-  RegisterUnit('BGRAResizeSpeedButton', @BGRAResizeSpeedButton.Register);
   RegisterUnit('BGRAShape', @BGRAShape.Register);
+  RegisterUnit('BGRAResizeSpeedButton', @BGRAResizeSpeedButton.Register);
   RegisterUnit('BGRASpeedButton', @BGRASpeedButton.Register);
   RegisterUnit('BGRASpriteAnimation', @BGRASpriteAnimation.Register);
   RegisterUnit('BGRASVGImageList', @BGRASVGImageList.Register);
@@ -99,6 +100,7 @@ begin
   RegisterUnit('BCLeaBoard', @BCLeaBoard.Register);
   RegisterUnit('BCLeaEngrave', @BCLeaEngrave.Register);
   RegisterUnit('SuperGauge', @SuperGauge.Register);
+  RegisterUnit('SuperLED', @SuperLED.Register);
   RegisterUnit('BGRADialogs', @BGRADialogs.Register);
   RegisterUnit('SuperSpinner', @SuperSpinner.Register);
 end;

BIN
docs/img/SuperLED.png


+ 47 - 0
icons/superled.lrs

@@ -0,0 +1,47 @@
+LazarusResources.Add('tsuperled','PNG',[
+  #137'PNG'#13#10#26#10#0#0#0#13'IHDR'#0#0#0#24#0#0#0#24#8#3#0#0#0#215#169#205
+  +#202#0#0#3#0'PLTE'#255#255#255'www01'#206#196#1#1#171#163#167#149#3#3#142#142
+  +'o^_'#164#211':9'#1#2#255#146'BA'#204#212#212#156#155#155#24#27#239#197#131
+  +#131#129#129'l'#206#31#30'OP'#185#146'!!'#187#194#194'//'#248'13'#214#153'pp'
+  +#147#146#149'kk'#149#161'llop'#156#210#223#226#140#138#138#197#9#9#178'ed'
+  +#173#178#178'|||'#26#28#244#156'YYBB'#209#163#0#0'lm'#157#128#128#128'NO'#176
+  +'99'#234#176'88'#192'QP'#217#0#0#198#170#170#190'HG'#209#0#0'SU'#218#137#135
+  +#135'DE'#182#203#176#176#192'43'#162#21#21'de'#165#181'FG~~'#129'*+'#221#214
+  +#213#217#195#203#204#204',*'#182#189#189#169'GG'#13#15#247#197'KJ'#218#229
+  +#229#191#0#0'33'#237#146#146'l'#215#218#198#207#18#17'RS'#181#184'tt'#190'XX'
+  +#155#153#136#130#130'|DE'#196#197#176#176'ttzss'#150'IJ'#201';<'#183#189#161
+  +#161#179#0#0#186',,Z['#184#129#129#140'@A'#227'GH'#198#195#194#174#164#164
+  +#164#199#147#147#219#228#232#202'A@'#204#1#1':;'#213'gg'#172#197#196#195#180
+  +#181#181'YZ'#179'/2'#245#158#8#8#208#14#14#166'""'#170#168#168#14#16#248'st'
+  +#160#212#212#212#136#136'{OP'#201#175'qp'#162#144#147#212'UR.0'#224#173#1#1#6
+  +#9#254'zvv'#211'DBRS'#186#203#204#204#226#228#228'jj'#166'"$'#234'FH'#217#210
+  +#21#21#173#171#153#147'OO'#197#139#139#210',*'#169'LK{{'#147'IJ'#224#130#127
+  +#127#208#8#7'||'#138#155#0#0#138#138't'#144#142#142'EF'#205#207#196#196#132
+  +#132'u'#8#11#252'JJ'#196#213#225#225'DD'#189'\]'#171#166#154#154'68'#211'qq'
+  +#153#190#177#177'46'#243#212'HE'#189#187#191'ww'#132#152#150#150#137#137#130
+  +#212#222#222#209#28#27#207#15#15'BD'#221'LM'#185#207'TR'#207'KJ'#213#218#205
+  +'??'#185#129#129#144#221#233#233'bb'#177'01'#225'd'#0#0#0#0#0#29#0#15#133#232
+  +#0#29#9#232#0#0#0#0#0#0#187#184#0#152#12#14#12#14#200#232#133#216#0#0#9#0#0
+  +#134#0#0#0'S'#242#196#233'j'#0#0'v'#234#0#0#0'''N'#224#0#0#238#0#0#0#0#0#0#0
+  +#0#2#242#156#0#128#0'S'#192#16#0'S'#243#216'$'#0#0#188'v'#239#152#140#3#255
+  +#255#254#243'p'#255#203#0'Svi@'#134#0#0#0#0#0#152#0#0#12#14#200#143#216#148#0
+  +#1#0')'#0#0'viB'#0#0'`'#7'`'#0#0#0#0#0#0#0#16#0#128#0#5#192#0#0#0#0#0#0#0#0#2
+  +#0#0#0#128#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0'b'#0#152#0'd'#12#14#200
+  +#14#200#152#0#0#12#255#0#0#255#255#255#134#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0#0
+  +#24#0#0#0#0#0#0#0#0#243#24#0'@'#0'S'#0#0#0#0#0#0#243'`'#0#8#0'S'#11#167'H'#13
+  +'8H'#0#12#12#2#0#0#0#0#0'S'#1#1#132#199#0#217'w;{'#0#0#0#1'tRNS'#0'@'#230#216
+  +'f'#0#0#0#1'bKGD'#0#136#5#29'H'#0#0#0#9'pHYs'#0#0#153#202#0#0#153#202#1#227
+  +#145#164'"'#0#0#1',IDAT('#207'c`'#160#0'Xq[a'#17#229#158'mT'#199#23#213#229
+  +#128'.'#238#224#163'e-'#224#26'+'#235#145'U'#134'*'#30#24'SRR?''U/68K'#24'I<'
+  +'!'#193'>'#127'a'#181#158#158'^,3'#179#217'R$'#137'>'#247#146#5#169'z '#16#27
+  +#20#164#131#228#4'n'#221'i'#214'z'#16'P'#168'"'#215#135'd'#148'1G5D'#131'^a'
+  +#155'-'#178'Dp'#253'\'#184'D'#3#146#4#183'f'#181'+D<'#182#173'-w6'#146'k%'
+  +#245'Z'#160'V'#180#165'LA'#178#188'L8M;'#150'96'#150#185#176#173'M'#9#197#243
+  +#229#145'i'#204#142'A*mmm\'#220#9'(^/'#151#175'5Qic'#21#18#227#206'B'#11',Ki'
+  +#155#137'y,V'#209#211'1'#195'7'#129'{'#145#11#154#144'r/'#130#237#13#194#222
+  +#16'f%C'#220'$'#6'N'#16#179#168#151'A'#145#1#200#12#239#1#203#244'X'#0'u'#128
+  +#153#138'q'#5#12'`'#166#29'T{'#134'(C'#17#3'C'#14#131#162#127'''H'#31'T'#25
+  +#147'(C'#156'('#200'(E'#134#140'^'#134'J'#144'Q'#222#188'`'#13#243'z'#20#25
+  +#170'4'#166#138'4'#233'kLMvb'#8#211#152#186#28'('#10#0#21#250'M'#186'yIH'#249
+  +#0#0#0#0'IEND'#174'B`'#130
+]);

BIN
images/bgracontrols_images.res


+ 3 - 0
images/bgracontrols_images_list.txt

@@ -149,6 +149,9 @@ tsupergauge_200.png
 tsuperspinner.png
 tsuperspinner_150.png
 tsuperspinner_200.png
+tsuperled.png
+tsuperled_150.png
+tsuperled_200.png
 tbcroundedimage.png
 tbcroundedimage_150.png
 tbcroundedimage_200.png

+ 15 - 0
images/svg/tsuperled.svg

@@ -0,0 +1,15 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<!--Generator: Xara Designer (www.xara.com), SVG filter version: 6.7.0.0-->
+<svg fill="none" fill-rule="evenodd" stroke="black" stroke-width="0.501" stroke-linejoin="bevel" stroke-miterlimit="10" font-family="Times New Roman" font-size="16" style="font-variant-ligatures:none" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" version="1.1" overflow="visible" width="18pt" height="18pt" viewBox="0 -18 18 18">
+ <defs>
+  <image id="Bitmap" preserveAspectRatio="none" width="1" height="1" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABcAAAAXCAYAAADgKtSgAAAACXBIWXMAAA7DAAAOwwHHb6hkAAADzElEQVRIiWKgGWBgYAAAAAD//6IdZmBgAAAAAP//YiTBdCYGBgaQ+v8MDAz/CKpmYGAAAAAA//+EzCEKACAQAMFpFk36/xfKoWAVxC6YNs3+5gkF9baROwMTgYX9lDgAAAD//8JlODMDA4NgMgODm6esbIY0G6sZx7dv7Ix//jB8+frt552fPy+t//t3yUYGhp0MDAxPoZagAgYGBgAAAAD//8JmOMhgibniYp2m2lrR///9Y2D4+pWB4cNHBoYvXxkYvn5hYPj6jeHn378MuxgYdtQwMDQwMDDcZID4CAEYGBgAAAAA//8CGYQOROaKi/eYmJtFM7CzQ0L4zx8Ghu8/GBi+f2dg+PGT4e/v3wx/GBgY5BkYVBQZGBT2MzCchxr+G24YAwMDAAAA//9iQQ/jFAYGd1ND/ej/bGwMDP//MzB8+8rAcPwEiiKQwSAMMsmKgcHFhYHhxB4GhrcMDAwP4ZHNwMAAAAAA//8CpQBkwO+lqpz+n42VgeHfXwaGN28ZGI4cw/AaKJZB4Ac0sL0YGKIZGBgUGBgY2OCKGBgYAAAAAP//QjYcxBaR5eI2BQfBt+8MDAcPYYsnMAAloU9Qw8UYGGQZIJgLroCBgQEAAAD//0IOFlDk8rP//sP+H2QwE7qnMME3aKLnYmAAmSPAwMDACVfFwMAAAAAA//9CNhxkGut/UOSBUgcovAkAROAyMjD8+w8KEoR5DAwMAAAAAP//QuaA1P78+vnTL+5fP9kY/uLMGxjgKxPTX4Z/f0FR8AsuycDAAAAAAP//QvY7yLT3Nz59vgtOz6B0jQeAEjYM3GFmBmUkUGr5DhdkYGAAAAAA//9CD9g3C79+nf/nIyjDfAHbhpJwoQBk8Gd4iDAy7P795wADA8MDaDRAAAMDAwAAAP//Qs9Efx4yMHwU/PdPVYuBQQmUlkF+fc/AwPAYmoifIfkdpPkAI+O17f//z2dgYLiIkksZGBgAAAAA//9CNxwc7kcZGG4yMzAoqTMwKMAyC8gSZF+AktZeBobrixkYJjEwMJxiYGB4glKIMTAwAAAAAP//wpb9QQ77cpqB4eIZBoa33AwM4hwMDPzM0MT5lYHh71UGhmeLGBg272NgALkYZDDIUyD7EYCBgQEAAAD//8JX5ILyiSQDA4MyAwODHBsDg8QvSK4HRdprBgaG+9BwBrF/YuhmYGAAAAAA//8iVJ6DkioHyCJ2Bga+n5A8AzLoKzRzgnyJveJgYGAAAAAA//+iHWZgYAAAAAD//6IdZmBgAAAAAP//oh1mYGAAAAAA//8DAJDK5bVE5zetAAAAAElFTkSuQmCC">
+   <title>1</title>
+  </image>
+ </defs>
+ <g id="Layer 1" transform="scale(1 -1)">
+  <use transform="translate(0 20.25) scale(17.25 -17.25)" xlink:href="#Bitmap" stroke-width="0" fill="none" stroke="none"/>
+  <rect x="-8.9995" y="-8.9995" width="17.999" height="17.999" rx="0" ry="0" transform="matrix(1 0 0 1 8.999 8.998)" fill-rule="nonzero" stroke-linejoin="miter" stroke-width="0.75" stroke="none"/>
+  <text xml:space="preserve" transform="translate(-0.25 0.13) scale(1 -1)" kerning="auto" font-size="6.234" fill="#0003ff" stroke="none" stroke-width="0.148" stroke-linecap="round" stroke-linejoin="round" font-family="Clarendon"><tspan x="0" y="0">SLED</tspan></text>
+ </g>
+</svg>

BIN
images/tsuperled.png


BIN
images/tsuperled_150.png


BIN
images/tsuperled_200.png


+ 734 - 0
superled.pas

@@ -0,0 +1,734 @@
+// SPDX-License-Identifier: LGPL-3.0-linking-exception
+{
+  Part of BGRA Controls. Made by third party.
+  For detailed information see readme.txt
+
+  Site: https://sourceforge.net/p/bgra-controls/
+  Wiki: http://wiki.lazarus.freepascal.org/BGRAControls
+  Forum: http://forum.lazarus.freepascal.org/index.php/board,46.0.html
+
+}
+{******************************* CONTRIBUTOR(S) ******************************
+- Sandy Ganz | [email protected]
+  Evolved from BGRAShape, thin wrapper to make a nice looking LED component. Fast
+  cached drawing and a bunch of shape, size and drawing options. Special thanks
+  to the BGRA team for nice code in the BGRAShape component that was easily
+  reused and modified.
+
+  Note On Auto Scale -
+
+  This component by default has Auto Scale OFF. That means that it will not be
+  subjected to any LCL Auto Scaling based on DPI or Screen Zoom (as far as I can test).
+  Auto Scale will ONLY cause a change in the component at run time on items that are scaled
+  by the Paint procedure. This means that toggling the Auto Scale property will
+  NOT change the ClientWidth/Height of the component after the initial form is created.
+
+  Again, changing the Auto Scale setting will not change the Component width/height
+  after the component is created. It must be set prior to form create for the scale
+  of the ClientWidth/Height to be affected. After that, it will not change.
+
+  In the case of the SuperLED the only item that currently will be modified is
+  the 'BorderThickness' IF Auto Scale is set to True. The drawing of the border
+  will change between 1.0 Scale and what ever the new scale is at run time, but
+  again the components ClientWidth and Height will not.
+
+***************************** END CONTRIBUTOR(S) *****************************}
+{******************************** CHANGE LOG *********************************
+v1.00 - 07-11-2025 Begat sjg by [email protected]
+v1.01 - 07-27-2025 Minor Code clean, Comments about Auto Scale
+
+******************************* END CHANGE LOG *******************************}
+
+unit SuperLED;
+
+{$I bgracontrols.inc}
+
+interface
+
+uses
+  Classes, SysUtils, {$IFDEF FPC} LResources, {$ENDIF} Forms, Controls, Graphics, Dialogs,
+  {$IFNDEF FPC} Types, BGRAGraphics, GraphType, FPImage, {$ENDIF}
+  BCBaseCtrls, BGRABitmap, BGRAShape, BGRABitmapTypes, BGRAGradientScanner, BCTypes;
+
+const
+  VERSIONSTR = '1.01';            // SLED version, Should ALWAYS show as a delta when merging!
+  BASELINE_SIZE = 32;             // Default size for the LED
+  MAX_SHAPE_SIDES = 6;            // Max sides for a shape, Hexagon is 6
+  DARKEN_PERCENT = 50;            // Darkening Default for the Inactive color
+  BRIGHTNESS_SCALER = 32767;      // Used to make scale sorta 0-100 percent in Brightness where 32767 is 100%
+
+type
+  TSLEDStyle = (slsFlat, slsShaded);
+  TSLEDShape = (slshRound, slshSquare, slshTriangle, slshPentagon, slshHexagon);
+
+  { TSuperLED }
+
+  TSuperLED = class(TBGRAGraphicCtrl)
+  private
+    { Private declarations }
+
+    FActive: boolean;
+    FAutoScale: boolean;
+    FActiveColor: TColor;
+    FInactiveColor: TColor;
+    FInactiveBrightness: integer;
+    FStyle: TSLEDStyle;
+    FShape: TSLEDShape;
+    FOnChange: TNotifyEvent;
+    FActiveBmp: TBGRABitmap;
+    FInactiveBmp: TBGRABitmap;
+    FBorderColor: TColor;
+    FBorderOpacity: byte;
+    FBorderStyle: TPenStyle;
+    FBorderThickness: integer;
+    FRoundRadius: integer;
+    FFillOpacity: byte;
+    FBorderGradient: TBCGradient;
+    FFillGradient: TBCGradient;
+    FAngle: single;
+    FScaling: Double;
+    FDirty: boolean;
+
+    function ShapeToCount(AShape: TSLEDShape): integer;
+    procedure SetActive(AValue: boolean);
+    procedure SetActiveColor(AValue: TColor);
+    procedure SetAutoScale(AValue: boolean);
+    procedure SetInactiveColor(AValue: TColor);
+    procedure SetInactiveBrightness(AValue: integer);
+    procedure SetBorderColor(AValue: TColor);
+    procedure SetBorderOpacity(Avalue: byte);
+    procedure SetBorderThickness(AValue: integer);
+    procedure SetBorderStyle(AValue: TPenStyle);
+    procedure SetStyle(AValue: TSLEDStyle);
+    procedure SetShape(AValue: TSLEDShape);
+    procedure SetAngle(AValue: single);
+    procedure SetRoundRadius(AValue: integer);
+    procedure SetFillOpacity(AValue: byte);
+    procedure SetOnChange(AValue: TNotifyEvent);
+    procedure DoChange;
+
+  protected
+    { Protected declarations }
+
+    class function GetControlClassDefaultSize: TSize; override;
+    procedure Paint; override;
+    procedure SetColor(AValue: TColor); override;
+    function GetColor: TColor;
+    procedure DoSetBounds(ALeft, ATop, AWidth, AHeight: Integer); override;
+    procedure DrawLED;
+    procedure DrawLEDBmp(LEDBitmap: TBGRABitmap; Active: boolean);
+    function CreateGradient(AGradient: TBCGradient; ARect: TRect): TBGRAGradientScanner;
+    function Brightness(Color: TColor; Brightness: integer): TBGRAPixel;
+
+  public
+    { Public declarations }
+
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    procedure AutoAdjustLayout(AMode: TLayoutAdjustmentPolicy;
+          const AFromPPI, AToPPI, AOldFormWidth, ANewFormWidth: Integer); override;
+  public
+    { Streaming }
+
+    {$IFDEF FPC}
+    procedure SaveToFile(AFileName: string);
+    procedure LoadFromFile(AFileName: string);
+    {$ENDIF}
+    procedure OnFindClass({%H-}Reader: TReader; const AClassName: string;
+      var ComponentClass: TComponentClass);
+
+  published
+    { Published declarations }
+
+    property ActiveColor: TColor read FActiveColor write SetActiveColor default clRed;
+    property InactiveColor: TColor read FInactiveColor write SetInactiveColor default clBlack;
+    property InactiveBrightness: integer read FInactiveBrightness write SetInactiveBrightness default DARKEN_PERCENT;
+    property BorderColor: TColor read FBorderColor write SetBorderColor default clGray;
+    property BorderOpacity: byte read FBorderOpacity write SetBorderOpacity default 255;
+    property BorderThickness: integer read FBorderThickness write SetBorderThickness default 1;
+    property BorderStyle: TPenStyle Read FBorderStyle Write SetBorderStyle default psSolid;
+    property RoundRadius: integer read FRoundRadius write SetRoundRadius default 0;
+    property FillOpacity: byte read FFillOpacity write SetFillOpacity default 255;
+    property Style: TSLEDStyle read FStyle write SetStyle default slsShaded;
+    property Shape: TSLEDShape read FShape write SetShape default slshRound;
+    property Angle: single read FAngle write SetAngle default 0;
+    property Active: boolean read FActive write SetActive default False;
+    property AutoScale: boolean read FAutoScale write SetAutoScale default False;
+    property Color: TColor read GetColor write SetColor default clNone; // need to override the ancestor since we need to dirty to update
+    property Align;
+    property ShowHint;
+    property Anchors;
+    property OnClick;
+    property OnDblClick;
+    property OnMouseDown;
+    property OnMouseEnter;
+    property OnMouseLeave;
+    property OnMouseMove;
+    property OnMouseUp;
+
+    // Debug Only TO allow easy reading of Auto Scale Factor
+    // property ScalingFactor: double read FScaling;
+  end;
+
+{$IFDEF FPC}procedure Register;{$ENDIF}
+
+implementation
+
+uses BCTools; // possibly get the gradient code into here
+
+{$IFDEF FPC}
+procedure Register;
+begin
+  RegisterComponents('BGRA Controls', [TSuperLED]);
+end;
+{$ENDIF}
+
+{ TSuperLED }
+
+procedure TSuperLED.AutoAdjustLayout(AMode: TLayoutAdjustmentPolicy;
+  const AFromPPI, AToPPI, AOldFormWidth, ANewFormWidth: Integer);
+begin
+  // If autoscaling then we will let the system mess with the component size
+  // otherwise it will just leave it along as the ACTUAL size in the designer
+  // as 1:1 with no scaling on anything. By not calling AutoAdjustLayout()
+  // Scaling will be 1:1
+  //
+  // Note - that toggling the AutoScale setting will cause a repaint
+  // but NOT a resize of the Components client area
+
+  if FAutoScale then
+    inherited AutoAdjustLayout(AMode, AFromPPI, AToPPI, AOldFormWidth, ANewFormWidth);
+end;
+
+constructor TSuperLED.Create(AOwner: TComponent);
+begin
+  inherited Create(AOwner);
+
+  with GetControlClassDefaultSize do
+    SetInitialBounds(0, 0, CX, CY);
+
+  FDirty := True;
+  FActiveBmp := TBGRABitmap.Create;
+  FInactiveBmp := TBGRABitmap.Create;
+  FActiveColor := clRed;
+  FInactiveColor := clBlack;
+  FInactiveBrightness := DARKEN_PERCENT; // In percent of brightness, 100 is full on, 0 black
+  FShape := slshRound;
+  FStyle := slsShaded;
+  FBorderColor := clGray;
+  FBorderOpacity := 255;
+  FBorderThickness := 1;
+  FBorderStyle := psSolid;
+  FRoundRadius := 0;
+  FFillOpacity := 255;
+  FAngle := 0;
+  FScaling := 1.0;
+  FAutoScale := False;
+  Color := clNone;
+
+  // Border Gradient
+
+  FBorderGradient := TBCGradient.Create(Self);
+  FBorderGradient.Point2XPercent := 100;
+  FBorderGradient.StartColor := FBorderColor;
+  FBorderGradient.EndColor := Brightness(FActiveColor, FInactiveBrightness);
+
+  // Fill Gradient
+
+  FFillGradient := TBCGradient.Create(Self);
+  FFillGradient.StartColor := FActiveColor;
+  FFillGradient.EndColor := Brightness(FActiveColor, FInactiveBrightness);
+end;
+
+destructor TSuperLED.Destroy;
+begin
+  FActiveBmp.Free;
+  FInactiveBmp.Free;
+  FFillGradient.Free;
+  FBorderGradient.Free;
+
+  inherited Destroy;
+end;
+
+// Override the base class which has a rectangular dimension
+
+class function TSuperLED.GetControlClassDefaultSize: TSize;
+begin
+  // Set the preferred size of the control. This may be subject to scaling!
+
+  Result.CX := BASELINE_SIZE;
+  Result.CY := BASELINE_SIZE;
+end;
+
+procedure TSuperLED.DoSetBounds(ALeft, ATop, AWidth, AHeight: Integer);
+begin
+  inherited;
+
+  FDirty := true; // Called on Resize of component
+end;
+
+// Original from BCTools.pas
+
+function TSuperLED.CreateGradient(AGradient: TBCGradient; ARect: TRect): TBGRAGradientScanner;
+begin
+  Result := TBGRAGradientScanner.Create(
+    ColorToBGRA(ColorToRGB(AGradient.StartColor), AGradient.StartColorOpacity),
+    ColorToBGRA(ColorToRGB(AGradient.EndColor), AGradient.EndColorOpacity),
+    AGradient.GradientType, PointF(ARect.Left + Round(
+    ((ARect.Right - ARect.Left) / 100) * AGradient.Point1XPercent),
+    ARect.Top + Round(((ARect.Bottom - ARect.Top) / 100) * AGradient.Point1YPercent)),
+    PointF(ARect.Left + Round(((ARect.Right - ARect.Left) / 100) *
+    AGradient.Point2XPercent), ARect.Top + Round(
+    ((ARect.Bottom - ARect.Top) / 100) * AGradient.Point2YPercent)),
+    AGradient.ColorCorrection, AGradient.Sinus);
+end;
+
+// sets the brightness for a color. Useful for a single
+// color setting and dim or bright changes on that.
+// Brightness = 0  Black
+// Brightness = 100 Origional Color
+// Brightness > 100 your mileage may vary
+//
+// In precent as indicated above
+
+function TSuperLED.Brightness(Color: TColor; Brightness: integer): TBGRAPixel;
+begin
+  Result := ApplyIntensityFast(ColorToBGRA(ColorToRGB(Color)), Round((Brightness / 100) * BRIGHTNESS_SCALER));
+end;
+
+// given a shape type get the number of sides. slshRound is not really
+// used but here just in case...
+
+function TSuperLED.ShapeToCount(AShape: TSLEDShape): integer;
+begin
+  // Only allow a few predefined shapes for the LED, so this helper
+  // Translates to what's needed if a polygon is drawn. slshRound
+  // is not really used, but left in just because.
+  //
+  // TSLEDShape = (slshRound = 0, slshSquare = 4, slshTriangle = 3,
+  //               slshPentagon = 5, slshHexagon = 6)
+
+  case AShape of
+    slshRound: Result := 0;
+    slshTriangle: Result := 3;
+    slshSquare: Result := 4;
+    slshPentagon: Result := 5;
+    slshHexagon: Result := 6;
+  else
+      Result := 0;  // slshRound
+  end;
+end;
+
+procedure TSuperLED.SetActive(AValue: boolean);
+begin
+  if FActive = AValue then
+    Exit;
+
+  FActive := AValue;
+  Invalidate; // don't set the dirty flag since we don't count this as dirty, just a redraw
+end;
+
+procedure TSuperLED.SetActiveColor(AValue: TColor);
+begin
+  if FActiveColor = AValue then
+    Exit;
+
+  FActiveColor := AValue;
+  DoChange;
+end;
+
+// The Set/Get color must be overidden since they are in the ancestor class
+// and we need to know they changed since the LED needs to see a Dirty flag
+// to repaint efficently the way we pre-paint active and inactive bitmaps
+
+function TSuperLED.GetColor: TColor;
+begin
+  Result := inherited Color;
+end;
+
+procedure TSuperLED.SetColor(AValue: TColor);
+begin
+  if inherited Color = AValue then
+    Exit;
+
+  inherited SetColor(AValue);
+  DoChange;
+end;
+
+procedure TSuperLED.SetInactiveColor(AValue: TColor);
+begin
+  if FInactiveColor = AValue then
+    Exit;
+
+  FInactiveColor := AValue;
+  DoChange;
+end;
+
+// allows a 0-100% change in brightness for the INACTIVE state as
+// well as used for the gradient transistions
+
+procedure TSuperLED.SetInactiveBrightness(AValue: integer);
+begin
+  if (FInactiveBrightness = AValue) or (AValue < 0) or (AValue > 100) then
+    Exit;
+
+  FInactiveBrightness := AValue;
+  DoChange;
+end;
+
+procedure TSuperLED.SetBorderColor(AValue: TColor);
+begin
+  if FBorderColor = AValue then
+    Exit;
+
+  FBorderColor := AValue;
+  DoChange;
+end;
+
+procedure TSuperLED.SetBorderOpacity(Avalue: byte);
+begin
+  if FBorderOpacity = AValue then
+    Exit;
+
+  FBorderOpacity := AValue;
+  DoChange;
+end;
+
+procedure TSuperLED.SetBorderThickness(Avalue: integer);
+begin
+  if (FBorderThickness = AValue) or (AValue < 0) then
+    Exit;
+
+  FBorderThickness := AValue;
+  DoChange;
+end;
+
+procedure TSuperLED.SetBorderStyle(AValue: TPenStyle);
+begin
+  if FBorderStyle = AValue then
+    Exit;
+
+  FBorderStyle := AValue;
+  DoChange;
+end;
+
+procedure TSuperLED.SetStyle(AValue: TSLEDStyle);
+begin
+  if FStyle = AValue then
+    Exit;
+
+  FStyle := AValue;
+  DoChange;
+end;
+
+procedure TSuperLED.SetShape(AValue: TSLEDShape);
+begin
+  if FShape = AValue then
+    Exit;
+
+  FShape := AValue;
+  DoChange;
+end;
+
+procedure TSuperLED.SetAngle(AValue: single);
+begin
+  if FAngle = AValue then
+    Exit;
+
+  FAngle := AValue;
+  DoChange;
+end;
+
+procedure TSuperLED.SetAutoScale(AValue: boolean);
+begin
+  if FAutoScale = AValue then
+    Exit;
+
+  FAutoScale := AValue;
+  DoChange;
+end;
+
+procedure TSuperLED.SetRoundRadius(AValue: integer);
+begin
+  if FRoundRadius = AValue then
+    Exit;
+
+  FRoundRadius := AValue;
+  DoChange;
+end;
+
+procedure TSuperLED.SetFillOpacity(AValue: byte);
+begin
+  if FFillOpacity = AValue then
+    Exit;
+
+  FFillOpacity := AValue;
+  DoChange;
+end;
+
+procedure TSuperLED.SetOnChange(AValue: TNotifyEvent);
+begin
+  FOnChange := AValue;
+
+  // this will not dirty it
+
+  if Assigned(FOnChange) then
+    FOnChange(Self);
+end;
+
+procedure TSuperLED.DoChange;
+begin
+  FDirty := True;
+  Invalidate;   // if we get here a prop must have changed, mark dirty
+
+  if Assigned(FOnChange) then
+    FOnChange(Self);
+end;
+
+procedure TSuperLED.Paint;
+begin
+  inherited Paint;
+
+  // Scaling should only affect visuals that are not based on Width/Height
+  // as they change when scaled, so if based ClientWidth/Height, good, but not all are!
+  // IF Scaling then this may/will be not 1:1 if the LCL is scaling the form.
+  // Also note that set properties for objects like Border thickness will need to
+  // be scaled scaled here.
+
+  // Somewhat experimental, seems to work OK
+
+  if FAutoScale then
+    FScaling := ScaleDesignToForm(BASELINE_SIZE)/BASELINE_SIZE // just get the ratio from arbitrary dims
+  else
+    FScaling := 1.0;  // not scaling the component, so no scale of anything else done
+
+  DrawLED;
+
+  if FActive then
+  begin
+    // draw the Active BMP to the canvas
+
+    FActiveBmp.Draw(Canvas, 0, 0, False);
+  end
+  else
+  begin
+    // Draw the Inactive BMP to the canvas
+
+    FInactiveBmp.Draw(Canvas, 0, 0, False);
+  end;
+end;
+
+procedure TSuperLED.DrawLED;
+begin
+  // See if we need to redraw the bitmaps, we always do both
+  // the Active and Inactive as we need both.
+
+  if Not FDirty then
+    Exit;
+
+  FDirty := False;
+
+  // Draw the Active then Inactive
+
+  FActiveBmp.SetSize(Width, Height);
+  FInactiveBmp.SetSize(Width, Height);
+
+  // Clear bitmap to transparent or background color.
+  // NOTE we must overide the ancestor class to force a dirty
+  // flag for design time repaint, see SetColor() code/comments
+
+  if Color = clNone then
+  begin
+    FActiveBmp.FillTransparent;
+    FInactiveBmp.FillTransparent;
+  end
+  else
+  begin
+    FActiveBmp.Fill(Color);
+    FInactiveBmp.Fill(Color);
+  end;
+
+  // The magic happens in DrawLEDBmp!
+
+  DrawLEDBmp(FActiveBmp, True);
+  DrawLEDBmp(FInactiveBmp, False);
+end;
+
+procedure TSuperLED.DrawLEDBmp(LEDBitmap: TBGRABitmap; Active: boolean);
+var
+  cx, cy, rx, ry, a: single;
+  coords: array[0..MAX_SHAPE_SIDES] of TPointF;
+  minCoord, maxCoord: TPointF;
+  i: integer;
+  borderGrad, fillGrad: TBGRACustomScanner;
+  sideCnt: integer;
+  flatFillColor : TColor;
+
+begin
+  // Basline code from BGRAShape, changed to work a bit better
+  // with the simplified LED shapes and borders. Also updated to
+  // support different fill color based on the state and Gradient borders
+
+  sideCnt := ShapeToCount(FShape);  // get the number of sides for the users shape
+  LEDBitmap.PenStyle := FBorderStyle;
+
+  FFillGradient.EndColor := Brightness(FActiveColor, FInactiveBrightness);
+  FBorderGradient.Startcolor := FBorderColor;
+  FBorderGradient.EndColor := Brightness(FBorderColor, FInactiveBrightness);
+
+  // set up anything related to the state, mostly color
+
+  if Active then
+  begin
+    FFillGradient.StartColor := FActiveColor;
+    flatFillColor := FActiveColor;
+  end
+  else
+    begin
+      FFillGradient.StartColor := FInactiveColor;
+      flatFillColor := Brightness(FInactiveColor, FInactiveBrightness); // allow brightness on flat
+    end;
+
+  with LEDBitmap.Canvas2D do
+  begin
+    lineJoin := 'round';
+
+    // if we are shaded we gradient both fill and border
+    // if not we draw both flat.
+
+    if FStyle = slsShaded then // use Gradient
+    begin
+      FBorderGradient.StartColorOpacity := FBorderOpacity; // sjg - Added Opacity to both
+      FBorderGradient.EndColorOpacity := FBorderOpacity;
+      borderGrad := CreateGradient(FBorderGradient, Classes.rect(0, 0, LEDBitmap.Width, LEDBitmap.Height));
+      strokeStyle(borderGrad);
+    end
+    else
+      begin
+        borderGrad := nil;
+        strokeStyle(ColorToBGRA(ColorToRGB(FBorderColor), FBorderOpacity));
+      end;
+
+    lineStyle(LEDBitmap.CustomPenStyle);
+    lineWidth := FBorderThickness * FScaling;
+
+    if FStyle = slsShaded then
+    begin
+      fillGrad := CreateGradient(FFillGradient, Classes.rect(0, 0, LEDBitmap.Width, LEDBitmap.Height));
+      fillStyle(fillGrad);
+    end
+    else
+      begin
+        fillGrad := nil;
+        fillStyle(ColorToBGRA(ColorToRGB(flatFillColor), FFillOpacity));
+      end;
+
+    cx := LEDBitmap.Width / 2;
+    cy := LEDBitmap.Height / 2;
+    rx := (LEDBitmap.Width - FBorderThickness * FScaling) / 2;
+    ry := (LEDBitmap.Height - FBorderThickness * FScaling) / 2;
+
+    // Now Draw a circle or polygon
+
+    if FShape = slshRound then
+    begin
+      // slshRound - circle
+
+      save;
+      translate(cx, cy);
+      scale(rx, ry);
+      beginPath;
+      arc(0, 0, 1, 0, 2 * Pi);
+      restore;
+    end
+    else
+      begin
+        // Polygon drawing all here
+
+        for i := 0 to sideCnt - 1 do
+        begin
+          a := (i / sideCnt + FAngle / 360) * 2 * Pi;
+          coords[i] := PointF(sin(a), -cos(a));
+        end;
+
+        minCoord := coords[0];
+        maxCoord := coords[0];
+
+        for i := 1 to sideCnt - 1 do
+        begin
+          if coords[i].x < minCoord.x then
+            minCoord.x := coords[i].x;
+          if coords[i].y < minCoord.y then
+            minCoord.y := coords[i].y;
+          if coords[i].x > maxCoord.x then
+            maxCoord.x := coords[i].x;
+          if coords[i].y > maxCoord.y then
+            maxCoord.y := coords[i].y;
+        end;
+
+        for i := 0 to sideCnt - 1 do
+        begin
+          with (coords[i] - minCoord) do
+            coords[i] := PointF((x / (maxCoord.x - minCoord.x) - 0.5) *
+              2 * rx + cx, (y / (maxCoord.y - minCoord.y) - 0.5) * 2 * ry + cy);
+        end;
+
+        beginPath;
+
+        for i := 0 to sideCnt - 1 do
+        begin
+          lineTo((coords[i] + coords[(i + 1) mod sideCnt]) * (1 / 2));
+          arcTo(coords[(i + 1) mod sideCnt], coords[(i + 2) mod sideCnt], FRoundRadius);
+        end;
+
+        closePath;
+      end;
+
+    fill;
+    if FBorderThickness <> 0 then
+      stroke;
+
+    fillStyle(BGRAWhite);
+    strokeStyle(BGRABlack);
+
+    fillGrad.Free;
+    borderGrad.Free;
+  end;
+end;
+
+{$IFDEF FPC}
+procedure TSuperLED.SaveToFile(AFileName: string);
+var
+  AStream: TMemoryStream;
+begin
+  AStream := TMemoryStream.Create;
+  try
+    WriteComponentAsTextToStream(AStream, Self);
+    AStream.SaveToFile(AFileName);
+  finally
+    AStream.Free;
+  end;
+end;
+
+procedure TSuperLED.LoadFromFile(AFileName: string);
+var
+  AStream: TMemoryStream;
+begin
+  AStream := TMemoryStream.Create;
+  try
+    AStream.LoadFromFile(AFileName);
+    ReadComponentFromTextStream(AStream, TComponent(Self), OnFindClass);
+  finally
+    AStream.Free;
+  end;
+end;
+{$ENDIF}
+
+procedure TSuperLED.OnFindClass(Reader: TReader; const AClassName: string;
+  var ComponentClass: TComponentClass);
+begin
+  if CompareText(AClassName, 'TSuperLED') = 0 then
+    ComponentClass := TSuperLED;
+end;
+
+end.

+ 272 - 0
test/test_superled/about.lfm

@@ -0,0 +1,272 @@
+object AboutFrm: TAboutFrm
+  Left = 1199
+  Height = 653
+  Top = 173
+  Width = 615
+  BorderStyle = bsSingle
+  Caption = 'About Super Gauge'
+  ClientHeight = 653
+  ClientWidth = 615
+  Color = clSkyBlue
+  DesignTimePPI = 144
+  FormStyle = fsStayOnTop
+  Icon.Data = {
+    9E09000000000100010018180000010020008809000016000000280000001800
+    0000300000000100200000000000000900006400000064000000000000000000
+    0000FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00F2F2
+    F2FF7B7B7BFF393939FF101010FF090909FF090909FF101010FF323232FF7373
+    73FFDEDEDEFFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFFFF737373FF0909
+    09FF282828FF535353FF6C6C6CFF7B7B7BFF7B7B7BFF6C6C6CFF5A5A5AFF3232
+    32FF090909FF535353FFE7E7E7FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00F2F2F2FF323232FF212121FF6C6C
+    6CFF848484FF848484FF848484FF848484FF848484FF848484FF848484FF8484
+    84FF7B7B7BFF424242FF101010FFADADADFFFFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFFFF323232FF323232FF7B7B7BFFA4A4
+    A4FFCECECEFFD6D6D6FFD6D6D6FF959595FF8B8B8BFFD6D6D6FFDEDEDEFFCECE
+    CEFFC4C4C4FF848484FF646464FF101010FFADADADFFFFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00737373FF212121FF7B7B7BFF848484FFB4B4
+    B4FFB4B4B4FF848484FFCECECEFFCECECEFFD6D6D6FFCECECEFF848484FFB4B4
+    B4FFDEDEDEFF848484FF848484FF6C6C6CFF101010FFCECECEFFFFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00F2F2F2FF090909FF6C6C6CFF848484FF848484FF8B8B
+    8BFFDEDEDEFFFFFFFFFFF7F7F7FFA4A4A4FFF2F2F2FFADADADFF848484FFCECE
+    CEFFCECECEFF9E9E9EFF848484FF848484FF5A5A5AFF323232FFFFFFFFFFFFFF
+    FF00FFFFFF00FFFFFF00848484FF282828FF848484FF848484FF848484FFADAD
+    ADFFE7E7E7FF959595FF9E9E9EFFADADADFFD6D6D6FFCECECEFF848484FF9595
+    95FFCECECEFF848484FF848484FF848484FF848484FF282828FFBBBBBBFFFFFF
+    FF00FFFFFF00FFFFFF00323232FF535353FF848484FF848484FF848484FF8B8B
+    8BFFDEDEDEFFCECECEFFDEDEDEFFB4B4B4FF8B8B8BFFDEDEDEFFDEDEDEFFD6D6
+    D6FFCECECEFF848484FF848484FF848484FF848484FF646464FF646464FFFFFF
+    FF00FFFFFF00FFFFFF00101010FF6C6C6CFF848484FF848484FF848484FF8484
+    84FF848484FF848484FF848484FF737373FF6C6C6CFF848484FF848484FF8484
+    84FF848484FF848484FF6B6B95FF6978A7FF809393FF7B7B7BFF282828FFFFFF
+    FF00FFFFFF00FFFFFF00090909FF7C9E9EFF809B9BFF848484FF848484FF8484
+    84FF848484FF848484FF737373FF737373FF6C6C6CFF737373FF848484FF8484
+    84FF848484FF848484FF4C4CB4FF6287C3FF80A5A5FF7B7B7BFF090909FFFFFF
+    FF00FFFFFF00FFFFFF00090909FF7C9E9EFF80B5B5FF848484FF848484FF8484
+    84FF848484FF848484FF8B8B8BFF5B81B6FF4F75A9FF7B7B7BFF848484FF8484
+    84FF848484FF848484FF3131CEFF77B5C6FF809393FF7B7B7BFF090909FFFFFF
+    FF00FFFFFF00FFFFFF00101010FF728282FF7FC6C7FF848484FF848484FF8484
+    84FF848484FF848484FF848484FF5B81B6FF4D76AFFF848484FF848484FF8484
+    84FF848484FF7A7A86FF2929D6FF7FD6D7FF848484FF7B7B7BFF282828FFFFFF
+    FF00FFFFFF00FFFFFF00323232FF5A5A5AFF7FDCDCFF848484FF848484FF8484
+    84FF848484FF848484FF848484FF4777B9FF4777B9FF848484FF848484FF8484
+    84FF848484FF3939C6FF637AB4FF7FBFBFFF848484FF6C6C6CFF5A5A5AFFFFFF
+    FF00FFFFFF00FFFFFF00737373FF323232FF80AFAFFF80B5B5FF848484FF8484
+    84FF848484FF848484FF848484FF4777B9FF4777B9FF848484FF848484FF8484
+    84FF4F4FB0FF3E41C4FF7FDCDCFF848484FF848484FF323232FFB4B4B4FFFFFF
+    FF00FFFFFF00FFFFFF00DEDEDEFF090909FF7B7B7BFF7FD6D7FF809B9BFF8484
+    84FF848484FF848484FF848484FF4777B9FF4777B9FF848484FF70708FFF3131
+    CEFF3E41C4FF7FD6D7FF809B9BFF848484FF737373FF212121FFF7F7F7FFFFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00535353FF424242FF848484FF7ECDD0FF80BD
+    BDFF848484FF848484FF848484FF4777B9FF2A5AD5FF2929D6FF3131CEFF6C8F
+    B8FF7FDCDCFF809393FF848484FF7B7B7BFF282828FFA4A4A4FFFFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00E7E7E7FF101010FF646464FF848484FF80A5
+    A5FF7FD6D7FF7FD1D2FF80BDBDFF4792D4FF3F8CDDFF7ECDD0FF7FD6D7FF80B5
+    B5FF848484FF848484FF848484FF424242FF5A5A5AFFFFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00B4B4B4FF101010FF6C6C6CFF8484
+    84FF848484FF848484FF809B9BFF4789CCFF4786C9FF808989FF848484FF8484
+    84FF848484FF7B7B7BFF424242FF393939FFF7F7F7FFFFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00ADADADFF101010FF5A5A
+    5AFF848484FF848484FF848484FF848484FF848484FF848484FF848484FF8484
+    84FF6C6C6CFF282828FF535353FFF7F7F7FFFFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00CECECEFF3232
+    32FF282828FF646464FF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF6C6C6CFF3939
+    39FF212121FFA4A4A4FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FFFFB4B4B4FF646464FF282828FF101010FF101010FF282828FF5A5A5AFFADAD
+    ADFFF7F7F7FFFFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFFFF00FFFF
+    FF00000000000000000000000000000000000000000000000000000000000000
+    0000000000000000000000000000000000000000000000000000000000000000
+    0000000000000000000000000000000000000000000000000000000000000000
+    0000
+  }
+  OnCreate = FormCreate
+  OnShow = FormShow
+  Position = poMainFormCenter
+  LCLVersion = '3.6.0.0'
+  object Panel1: TPanel
+    Left = 0
+    Height = 53
+    Top = 600
+    Width = 615
+    Align = alBottom
+    ClientHeight = 53
+    ClientWidth = 615
+    ParentBackground = False
+    TabOrder = 1
+    object CloseBtn: TBitBtn
+      Left = 480
+      Height = 45
+      Top = 3
+      Width = 113
+      Caption = 'Close'
+      ImageIndex = 6
+      OnClick = CloseBtnClick
+      TabOrder = 0
+    end
+  end
+  object SLVersionLbl: TLabel
+    Left = 16
+    Height = 45
+    Top = 208
+    Width = 177
+    Caption = 'SLVersionLbl'
+    Font.CharSet = ANSI_CHARSET
+    Font.Height = -32
+    Font.Pitch = fpVariable
+    Font.Quality = fqDraft
+    ParentFont = False
+  end
+  object NameLbl: TLabel
+    Left = 16
+    Height = 54
+    Top = 64
+    Width = 474
+    Caption = 'Super LED Test Program'
+    Font.CharSet = ANSI_CHARSET
+    Font.Height = -40
+    Font.Name = 'Segoe UI Black'
+    Font.Pitch = fpVariable
+    Font.Quality = fqDraft
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
+  object NameLbl1: TLabel
+    Left = 16
+    Height = 54
+    Top = 160
+    Width = 357
+    Caption = 'Super LED Version'
+    Font.CharSet = ANSI_CHARSET
+    Font.Height = -40
+    Font.Name = 'Segoe UI Black'
+    Font.Pitch = fpVariable
+    Font.Quality = fqDraft
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
+  object SLTestVersionLbl: TLabel
+    Left = 16
+    Height = 45
+    Top = 112
+    Width = 233
+    Caption = 'SLTestVersionLbl'
+    Font.CharSet = ANSI_CHARSET
+    Font.Height = -32
+    Font.Pitch = fpVariable
+    Font.Quality = fqDraft
+    ParentFont = False
+  end
+  object Memo1: TMemo
+    Left = 0
+    Height = 280
+    Top = 320
+    Width = 615
+    Align = alBottom
+    Lines.Strings = (
+      'Super LED About (Keep Scrolling)'
+      ''
+      'LED control that supports various shapes, shading, and a few other'
+      'features such as abitly to Auto Scale or not.'
+      ''
+      'Originally based on the BGRAShape drawing routings.'
+      ''
+      'Super LED is fast and will create bitmaps for Active and Inactive'
+      'states so drawing will not re-render unless a property changes and'
+      'they are required to be redrawn. '
+      ''
+      'Toggling the Active/Inactive state is much faster due to the caching.'
+    )
+    ReadOnly = True
+    ScrollBars = ssBoth
+    TabOrder = 0
+    TabStop = False
+  end
+  object Image1: TImage
+    Left = 16
+    Height = 50
+    Top = 8
+    Width = 54
+    Picture.Data = {
+      1754506F727461626C654E6574776F726B47726170686963FD06000089504E47
+      0D0A1A0A0000000D494844520000003000000030080300000060DC09B5000003
+      00504C5445FFFFFF7676760102FFBC0101A4B0B09C0000696A9A8C8C6D5556AC
+      BF2D2DE9E7E789434396A2A22527D8D3D3D3929D9D86866F3C3DD6D115146C6D
+      D47F7F6FCF4846961A1A8B8B8BC1BEBE1316ED864C4CD100007475C53739C494
+      946C1E20EE8863637F8081BF3E3EA30000BECACA74749E4C4DCCDAD7D73E40BF
+      7E7E81AD8A8AF3F3F39B8585A75E5EADB8B8BC24254344CC2629F17B7B9A0E11
+      FECC00002F31DC9FAAAA8B7A7AAB7A7AAB0000BB5656DDE5E5B32C2C77777960
+      60C15E60BCD02827826A6AC5CACAB54F4F676799908D8DCF403EB660600508FD
+      A0323284848C6F70BFD10B0A7C7C935D5EBC3638E97F807F9C9C7AAD0C0C5456
+      C4C61E1DB4C1C17273A0895555AE66666A6BB3B84D4E8A8A79952727D2514FD1
+      302F80809C6566B2D93C3BACA2A23537C7D1201F9A8A8AC400006F70D4989778
+      1E21F7ECEBEB6B6CAC2F32EF2A2BDD9494821617F65153CF3232E0CDCDCDD24A
+      49A4A4A4B3B4B4D13C3BC046463234D93C3ED91315FB6A6B969E2C2CBCBBBBAB
+      ABABB300004B4DC25557BDCD29284344D2E4E9E9FAF9F9D7D7D9865454A56D6C
+      7575AACE0B0A888772D21C1B7D7D7D8A8A83DA41405A5BB5A657569D49499C9B
+      9BA97272CF514F7C7EC5B55A5C1F22FFF0EFEF1C1EEB9A9A6BCC2221D1454389
+      8A929393938A8AAFAE2524808080DCDBDB6666AEAC86867A7BA49E9090CE4E4C
+      D153515A5BA54446C5E5E4E42B2DED2729E23B3DE58283921619FDD134334A4C
+      D2292BE3BC3434AD1414DC4947CF39387574889E55549E0A0AC40D0CA60A0ACD
+      D5D50C0FF5C3C4C48B8A74C7D2D23234EE1A1CF4AD94944648D4D22C2BBBC6C5
+      5E5FD58C4A4A7778C53E3FEB8B8585B06969815D5D171AE8ABB5B52223ED9AA3
+      A3727395CA35347474B2878881877C7C82827B858575E2DFDF0A0BFE7072D3D1
+      1817B4BBBBD1100FA29C9CA4ADADD125245A5BAB2224F36D6EA67F809D6263BA
+      CB1B1AD049464F50CD4748CC6465A1D3413ED4DADA4648D9889292CE54523E40
+      E32023FC9494732627E29C1E1EA68686A85A5A92928AC62C2B7374CEC12020B1
+      7A7CB10F0E6FD5FEC70000000174524E530040E6D86600000001624B47448462
+      D05A710000000970485973000099CA000099CA01E391A4220000038949444154
+      48C7DD556B4814411C1F66DB0F59AD7852945B14ED61D1F6506EAD2EA3B4E805
+      42904911296875D1A25477DD751E5D1795192244EF078AD41275741A9EF6A0E7
+      519E67F6F24110B4B675E2072DB41756F49CD97BE41D73E6873EF5FF3033FB9B
+      DF6FFEFF99F9CF7F01F84FCD284992D13E54B2C88BFBD3D3D3F7A3DE38043A2F
+      F6699502AFD75B60D6F689FCDF24A2C8E478974DFE56D1DDBD7AF8E2F3CA1D51
+      1C94CFBF682A9897E773E7F93ACB3559AC70659A56E207E1974839E72DF9954B
+      DD7919AA8065CB4E2A4C49ECF525656EBEE962A5C5E2F6050582B04E89E9438A
+      6BFA72C879DCD4D363C9D0BCCA52F906837032C7E58AE160D16B53EE0767AEC9
+      87B9AA210165F8B988ECC225B52EBBF621D7E92C67C386F814356BB724921D5C
+      A844F4817CE4817238A8275A920B639CB236FFA2C9E91EC8670507B2F9661743
+      8AC8BFB377748F298B8D30875ECFFDF2F61162128D479FF5F656BA23E8024B71
+      1CAD3F76EF34690B9BF65AAE5B36463A600D344D7333489BE03DD32BDC6EB786
+      24F8AA257838EDD9D4EDF3F9C882266248553F3A3B3BA3051412E80F9242128D
+      23E7975794BF8CDAB41E09567D21DDB56BCAB02359DD1A4D245F407CFAEC0E46
+      245EDC9C5B9AB2A86BC00EB8C3334917878E69E40AB62C627DD6811D5CBDE0E1
+      C9C9677E4E6196208414787D5A7FA3959C7CC8C5EC35286A94D2E815A0B453E9
+      34B7ABDD13E305492E7BFC08414D69879EA303C67DAEB2C77A40E8899AE39328
+      35A543026EFD123313BB0CF08CBD3DF33365087AE0B89BCDF10A3358D9E0A5B1
+      FEF74FD7DFD6A3A4E6E831CD8FFDF641CB0C2E6446BB3FFE5C666952E9A43955
+      7EBBF12F854C2D958C47691DE6F7B72A1E268E6786568C5DA87ABB50CF0CB180
+      7B18493AC078FEE50F64DFD65A5B3248010945566B51820AF5A759D3EAEB6B8A
+      AC29E02D466B82B86A5DB078619D0C27829406082726ABD876087569A3ACB570
+      1CC86E83F04C5135845D21012C56DB33B88121F03EFC88BB8616D42C57511BAC
+      0E4C5D820DB86B2C8C125C469FA0F86E186D0C4F42E4BE2B21380C090A614372
+      0D0403D13F933688AD314A207F9263090078532DAB9F01ECDD291CD2231CD29E
+      4F61343B24D810E8E53F827E5B700FDB405A6D18AD0FEC1580A9EAF900A80B4F
+      C12D00A4C295916757178E6882AE0BB6A5421980361497ACD3E11397F149E061
+      0BB062D42687D64776023CA8C51183EF891D1D8989A8390150B3591D8E070F55
+      744190FC1BB97E5770F34B6C020000000049454E44AE426082
+    }
+  end
+  object AuthorLbl: TLabel
+    Left = 72
+    Height = 32
+    Top = 264
+    Width = 429
+    Caption = 'Author : Sandy Ganz, [email protected]'
+    Font.CharSet = ANSI_CHARSET
+    Font.Height = -24
+    Font.Pitch = fpVariable
+    Font.Quality = fqDraft
+    ParentFont = False
+  end
+end

+ 60 - 0
test/test_superled/about.pas

@@ -0,0 +1,60 @@
+unit about;
+
+{$mode ObjFPC}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,
+  Buttons, SuperLED;
+
+type
+
+  { TAboutFrm }
+
+  TAboutFrm = class(TForm)
+    CloseBtn: TBitBtn;
+    Image1: TImage;
+    AuthorLbl: TLabel;
+    Memo1: TMemo;
+    NameLbl: TLabel;
+    NameLbl1: TLabel;
+    Panel1: TPanel;
+    SLVersionLbl: TLabel;
+    SLTestVersionLbl: TLabel;
+    procedure CloseBtnClick(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+    procedure FormShow(Sender: TObject);
+  private
+
+  public
+    VersionStr: string;
+  end;
+
+var
+  AboutFrm: TAboutFrm;
+
+implementation
+
+{$R *.lfm}
+
+{ TAboutFrm }
+
+procedure TAboutFrm.FormCreate(Sender: TObject);
+begin
+  SLTestVersionLbl.Caption := '??';
+end;
+
+procedure TAboutFrm.FormShow(Sender: TObject);
+begin
+  SLTestVersionLbl.Caption := VersionStr;
+  SLVersionLbl.Caption := SuperLED.VERSIONSTR;
+end;
+
+procedure TAboutFrm.CloseBtnClick(Sender: TObject);
+begin
+  Close;
+end;
+
+end.
+

BIN
test/test_superled/project1.ico


+ 96 - 0
test/test_superled/project1.lpi

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

+ 26 - 0
test/test_superled/project1.lpr

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

+ 988 - 0
test/test_superled/sltest.lfm

@@ -0,0 +1,988 @@
+object SLTestFrm: TSLTestFrm
+  Left = 425
+  Height = 541
+  Top = 174
+  Width = 1000
+  Caption = 'Super LED Test'
+  ClientHeight = 541
+  ClientWidth = 1000
+  DesignTimePPI = 144
+  Menu = MainMenu1
+  OnConstrainedResize = FormConstrainedResize
+  OnCreate = FormCreate
+  OnDestroy = FormDestroy
+  LCLVersion = '3.6.0.0'
+  object SuperLED: TSuperLED
+    Left = 100
+    Height = 32
+    Hint = 'Single Click To Toggle State, Double Click to Change Color to Green'
+    Top = 100
+    Width = 32
+    BorderThickness = 2
+    ShowHint = True
+    OnClick = SuperLEDClick
+    OnDblClick = SuperLEDDblClick
+  end
+  object LEDTs: TPageControl
+    Left = 223
+    Height = 403
+    Top = 0
+    Width = 777
+    ActivePage = BasicTab
+    Align = alRight
+    TabIndex = 0
+    TabOrder = 0
+    object BasicTab: TTabSheet
+      Caption = 'Basic'
+      ClientHeight = 365
+      ClientWidth = 769
+      object GroupBox1: TGroupBox
+        Left = 8
+        Height = 312
+        Top = 16
+        Width = 248
+        Caption = 'Size'
+        ClientHeight = 282
+        ClientWidth = 244
+        ParentBackground = False
+        TabOrder = 0
+        object WidthAddBtn: TBitBtn
+          Left = 8
+          Height = 45
+          Hint = 'Increase Width'
+          Top = 40
+          Width = 113
+          Caption = 'Width'
+          Images = ImageList1
+          ImageIndex = 0
+          OnClick = WidthAddBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 0
+        end
+        object WidthSubBtn: TBitBtn
+          Left = 128
+          Height = 45
+          Hint = 'Decrease Width'
+          Top = 40
+          Width = 113
+          Caption = 'Width'
+          Images = ImageList1
+          ImageIndex = 1
+          OnClick = WidthSubBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 1
+        end
+        object HeightAddBtn: TBitBtn
+          Left = 8
+          Height = 45
+          Hint = 'Increase Height'
+          Top = 88
+          Width = 113
+          Caption = 'Height'
+          Images = ImageList1
+          ImageIndex = 0
+          OnClick = HeightAddBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 2
+        end
+        object HeightSubBtn: TBitBtn
+          Left = 128
+          Height = 45
+          Hint = 'Decrease Height'
+          Top = 88
+          Width = 113
+          Caption = 'Height'
+          Images = ImageList1
+          ImageIndex = 1
+          OnClick = HeightSubBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 3
+        end
+        object ResetSizeBtn: TBitBtn
+          Left = 9
+          Height = 45
+          Hint = 'Reset to Default'
+          Top = 232
+          Width = 232
+          Caption = 'Reset Size'
+          Images = ImageList1
+          ImageIndex = 7
+          OnClick = ResetSizeBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 4
+        end
+        object WidthLbl: TLabel
+          Left = 8
+          Height = 25
+          Top = 0
+          Width = 62
+          Caption = 'Width : '
+        end
+        object WidthValLbl: TLabel
+          Left = 72
+          Height = 25
+          Top = 0
+          Width = 35
+          Caption = 'N/A'
+          Font.Style = [fsBold]
+          ParentFont = False
+        end
+        object HeightLbl: TLabel
+          Left = 128
+          Height = 25
+          Top = 0
+          Width = 67
+          Caption = 'Height : '
+        end
+        object HeightValLbl: TLabel
+          Left = 192
+          Height = 25
+          Top = 0
+          Width = 35
+          Caption = 'N/A'
+          Font.Style = [fsBold]
+          ParentFont = False
+        end
+        object WidthHeightSubBtn: TBitBtn
+          Left = 128
+          Height = 45
+          Hint = 'Decrease Size Width and Height, This is a SQUARE compoent '#13#10'so will alway fit the minimum sized Width or Height. This does'#13#10'them together.'
+          Top = 136
+          Width = 113
+          Caption = 'W&&H Size'
+          Images = ImageList1
+          ImageIndex = 1
+          OnClick = WidthHeightSubBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 5
+        end
+        object WidthHeightAddBtn: TBitBtn
+          Left = 9
+          Height = 45
+          Hint = 'Increase Size Width and Height, This is a SQUARE compoent '#13#10'so will alway fit the minimum sized Width or Height. This does'#13#10'them together.'
+          Top = 136
+          Width = 113
+          Caption = 'W&&H Size'
+          Images = ImageList1
+          ImageIndex = 0
+          OnClick = WidthHeightAddBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 6
+        end
+        object MakeBigBtn: TBitBtn
+          Left = 8
+          Height = 45
+          Hint = 'Makes Big'
+          Top = 184
+          Width = 232
+          Caption = 'Make Big'
+          Images = ImageList1
+          ImageIndex = 14
+          OnClick = MakeBigBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 7
+        end
+      end
+      object GroupBox2: TGroupBox
+        Left = 264
+        Height = 312
+        Top = 16
+        Width = 248
+        Caption = 'Position'
+        ClientHeight = 282
+        ClientWidth = 244
+        ParentBackground = False
+        TabOrder = 1
+        object LeftAddBtn: TBitBtn
+          Left = 8
+          Height = 45
+          Hint = 'Increase Left'
+          Top = 40
+          Width = 113
+          Caption = 'Left'
+          Images = ImageList1
+          ImageIndex = 0
+          OnClick = LeftAddBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 0
+        end
+        object TopSubBtn: TBitBtn
+          Left = 120
+          Height = 45
+          Hint = 'Decrease Top'
+          Top = 88
+          Width = 113
+          Caption = 'Top'
+          Images = ImageList1
+          ImageIndex = 1
+          OnClick = TopSubBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 1
+        end
+        object TopAddBtn: TBitBtn
+          Left = 8
+          Height = 45
+          Hint = 'Increase Top'
+          Top = 88
+          Width = 113
+          Caption = 'Top'
+          Images = ImageList1
+          ImageIndex = 0
+          OnClick = TopAddBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 2
+        end
+        object LeftSubBtn: TBitBtn
+          Left = 120
+          Height = 45
+          Hint = 'Decrease Left'
+          Top = 40
+          Width = 113
+          Caption = 'Left'
+          Images = ImageList1
+          ImageIndex = 1
+          OnClick = LeftSubBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 3
+        end
+        object ResetPositionBtn: TBitBtn
+          Left = 1
+          Height = 45
+          Hint = 'Reset To Default'
+          Top = 232
+          Width = 232
+          Caption = 'Reset Position'
+          Images = ImageList1
+          ImageIndex = 7
+          OnClick = ResetPositionBtnClick
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 4
+        end
+        object LeftLbl: TLabel
+          Left = 8
+          Height = 25
+          Top = 0
+          Width = 43
+          Caption = 'Left : '
+        end
+        object LeftValLbl: TLabel
+          Left = 72
+          Height = 25
+          Top = 0
+          Width = 35
+          Caption = 'N/A'
+          Font.Style = [fsBold]
+          ParentFont = False
+        end
+        object TopLbl: TLabel
+          Left = 128
+          Height = 25
+          Top = 0
+          Width = 43
+          Caption = 'Top : '
+        end
+        object TopValLbl: TLabel
+          Left = 192
+          Height = 25
+          Top = 0
+          Width = 35
+          Caption = 'N/A'
+          Font.Style = [fsBold]
+          ParentFont = False
+        end
+      end
+      object GroupBox5: TGroupBox
+        Left = 520
+        Height = 312
+        Top = 16
+        Width = 200
+        Caption = 'Basic'
+        ClientHeight = 282
+        ClientWidth = 196
+        TabOrder = 2
+        object AutoScaleCb: TCheckBox
+          Left = 8
+          Height = 29
+          Hint = 'Enable Auto Scaling'
+          Top = 240
+          Width = 116
+          Caption = 'Auto Scale'
+          Font.Style = [fsBold]
+          ParentFont = False
+          TabOrder = 0
+          OnChange = AutoScaleCbChange
+        end
+        object BackgroundColorCb: TColorBox
+          Left = 8
+          Height = 26
+          Hint = 'Frame Color'
+          Top = 32
+          Width = 171
+          Style = [cbStandardColors, cbExtendedColors, cbIncludeNone, cbCustomColor]
+          ColorDialog = ColorDialog1
+          ItemHeight = 20
+          OnChange = BackgroundColorCbChange
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 1
+        end
+        object BackgroundColorLbl: TLabel
+          Left = 8
+          Height = 25
+          Top = 0
+          Width = 143
+          Caption = 'Background Color'
+        end
+        object ActiveStateCb: TCheckBox
+          Left = 8
+          Height = 29
+          Top = 200
+          Width = 73
+          Caption = 'Active'
+          ParentFont = False
+          TabOrder = 2
+          OnChange = ActiveStateCbChange
+        end
+      end
+    end
+    object BorderTab: TTabSheet
+      Caption = 'Border'
+      ClientHeight = 365
+      ClientWidth = 769
+      object GroupBox6: TGroupBox
+        Left = 8
+        Height = 232
+        Top = 16
+        Width = 304
+        Caption = 'Border'
+        ClientHeight = 202
+        ClientWidth = 300
+        TabOrder = 0
+        object BorderColorLbl: TLabel
+          Left = 8
+          Height = 25
+          Top = 9
+          Width = 101
+          Caption = 'Border Color'
+        end
+        object BorderColorCb: TColorBox
+          Left = 121
+          Height = 26
+          Hint = 'Border Color'
+          Top = 8
+          Width = 171
+          Style = [cbStandardColors, cbExtendedColors, cbIncludeNone, cbCustomColor]
+          ColorDialog = ColorDialog1
+          ItemHeight = 20
+          OnChange = BorderColorCbChange
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 0
+        end
+        object BorderThicknessLbl: TLabel
+          Left = 8
+          Height = 25
+          Top = 152
+          Width = 133
+          Caption = 'Border Thickness'
+        end
+        object BorderThicknessSpe: TSpinEditEx
+          Left = 160
+          Height = 33
+          Hint = 'Set Border Thickness'
+          Top = 144
+          Width = 97
+          MaxLength = 0
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 1
+          OnChange = BorderThicknessSpeChange
+          MaxValue = 1000
+          MinValue = -1000
+          MinRepeatValue = 10
+          NullValue = 0
+          Value = 0
+        end
+        object BorderStyleLbl: TLabel
+          Left = 8
+          Height = 25
+          Top = 104
+          Width = 95
+          Caption = 'Border Style'
+        end
+        object BorderStyleCb: TComboBox
+          Left = 142
+          Height = 33
+          Hint = 'Border Pen Style'
+          Top = 96
+          Width = 150
+          ItemHeight = 25
+          ItemIndex = 0
+          Items.Strings = (
+            'psSolid'
+            'psDash'
+            'psDot'
+            'psDashDot'
+            'psDashDotDot'
+            'psinsideFrame'
+            'psPattern'
+            'psClear'
+          )
+          TabOrder = 2
+          Text = 'psSolid'
+          OnChange = BorderStyleCbChange
+        end
+        object BorderOpacityLbl: TLabel
+          Left = 8
+          Height = 25
+          Top = 56
+          Width = 119
+          Caption = 'Border Opacity'
+        end
+        object BorderOpacitySpe: TSpinEditEx
+          Left = 160
+          Height = 33
+          Hint = 'Set Border Opacity 0-255'
+          Top = 48
+          Width = 97
+          MaxLength = 0
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 3
+          OnChange = BorderOpacitySpeChange
+          MaxValue = 255
+          MinRepeatValue = 10
+          NullValue = 0
+          Value = 0
+        end
+      end
+    end
+    object DrawingTab: TTabSheet
+      Caption = 'Drawing'
+      ClientHeight = 365
+      ClientWidth = 769
+      object GroupBox3: TGroupBox
+        Left = 8
+        Height = 208
+        Top = 16
+        Width = 326
+        Caption = 'Colors'
+        ClientHeight = 178
+        ClientWidth = 322
+        TabOrder = 0
+        object DrawingActiveColorLbl: TLabel
+          Left = 16
+          Height = 25
+          Top = 8
+          Width = 96
+          Caption = 'Active Color'
+        end
+        object DrawingInactiveColorLbl: TLabel
+          Left = 13
+          Height = 25
+          Top = 48
+          Width = 108
+          Caption = 'Inactive Color'
+        end
+        object DrawingFillOpacityLbl: TLabel
+          Left = 16
+          Height = 25
+          Top = 88
+          Width = 87
+          Caption = 'Fill Opacity'
+        end
+        object DrawingInactiveBrightnessLbl: TLabel
+          Left = 16
+          Height = 25
+          Top = 128
+          Width = 147
+          Caption = 'Inactive Brightness'
+        end
+        object DrawingActiveColorCb: TColorBox
+          Left = 136
+          Height = 26
+          Hint = 'Sets the Active Color'
+          Top = 7
+          Width = 171
+          Style = [cbStandardColors, cbExtendedColors, cbIncludeNone, cbCustomColor]
+          ColorDialog = ColorDialog1
+          ItemHeight = 20
+          OnChange = DrawingActiveColorCbChange
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 0
+        end
+        object DrawingInactiveColorCb: TColorBox
+          Left = 136
+          Height = 26
+          Hint = 'Sets the Inactive Color'
+          Top = 47
+          Width = 171
+          Style = [cbStandardColors, cbExtendedColors, cbIncludeNone, cbCustomColor]
+          ColorDialog = ColorDialog1
+          ItemHeight = 20
+          OnChange = DrawingInactiveColorCbChange
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 1
+        end
+        object DrawingFillOpacitySpe: TSpinEditEx
+          Left = 184
+          Height = 33
+          Hint = 'Fill Opacity 0-255'#13#10
+          Top = 80
+          Width = 97
+          MaxLength = 0
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 2
+          OnChange = DrawingFillOpacitySpeChange
+          MaxValue = 255
+          MinRepeatValue = 10
+          NullValue = 0
+          Value = 0
+        end
+        object DrawingInactiveBrightnessSpe: TSpinEditEx
+          Left = 184
+          Height = 33
+          Hint = 'Inactive Brightness 0-Dark, 100 Lightest'
+          Top = 120
+          Width = 97
+          MaxLength = 0
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 3
+          OnChange = DrawingInactiveBrightnessSpeChange
+          MaxValue = 100
+          MinRepeatValue = 10
+          NullValue = 0
+          Value = 0
+        end
+      end
+      object GroupBox4: TGroupBox
+        Left = 344
+        Height = 206
+        Top = 16
+        Width = 326
+        Caption = 'Shape'
+        ClientHeight = 176
+        ClientWidth = 322
+        TabOrder = 1
+        object DrawingShapeLbl: TLabel
+          Left = 20
+          Height = 25
+          Top = 8
+          Width = 49
+          Caption = 'Shape'
+        end
+        object DrawingStyleLbl: TLabel
+          Left = 20
+          Height = 25
+          Top = 48
+          Width = 37
+          Caption = 'Style'
+        end
+        object DrawingRadiusLbl: TLabel
+          Left = 20
+          Height = 25
+          Top = 96
+          Width = 110
+          Caption = 'Round Radius'
+        end
+        object DrawingShapeCb: TComboBox
+          Left = 112
+          Height = 33
+          Hint = 'LED Shape'
+          Top = 0
+          Width = 150
+          ItemHeight = 25
+          Items.Strings = (
+            'slshRound'
+            'slshSquare'
+            'slshTriangle'
+            'slshPentagon'
+            'slshHexagon'
+          )
+          TabOrder = 0
+          OnChange = DrawingShapeCbChange
+        end
+        object DrawingAngleLbl: TLabel
+          Left = 20
+          Height = 25
+          Top = 128
+          Width = 46
+          Caption = 'Angle'
+        end
+        object DrawingStyleCb: TComboBox
+          Left = 112
+          Height = 33
+          Hint = 'LED Fill Style'
+          Top = 40
+          Width = 150
+          ItemHeight = 25
+          Items.Strings = (
+            'slsFlat'
+            'slsShaded'
+          )
+          TabOrder = 1
+          OnChange = DrawingStyleCbChange
+        end
+        object DrawingRoundRadiusSpe: TSpinEditEx
+          Left = 165
+          Height = 33
+          Hint = 'Corner Radius'
+          Top = 80
+          Width = 97
+          MaxLength = 0
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 2
+          OnChange = DrawingRoundRadiusSpeChange
+          MaxValue = 255
+          MinRepeatValue = 10
+          NullValue = 0
+          Value = 0
+        end
+        object DrawingAngleSpe: TFloatSpinEditEx
+          Left = 165
+          Height = 33
+          Hint = 'Angle in Degrees'
+          Top = 120
+          Width = 97
+          MaxLength = 0
+          ParentShowHint = False
+          ShowHint = True
+          TabOrder = 3
+          OnChange = DrawingAngleSpeChange
+          MaxValue = 360
+          MinValue = -360
+          MinRepeatValue = 10
+        end
+      end
+    end
+  end
+  object AutoScaleLbl: TLabel
+    Left = 32
+    Height = 25
+    Top = 13
+    Width = 164
+    Caption = 'Auto Scale Enabled'
+    Font.Color = clRed
+    Font.Style = [fsBold]
+    ParentFont = False
+  end
+  object GroupBox7: TGroupBox
+    Left = 0
+    Height = 138
+    Top = 403
+    Width = 1000
+    Align = alBottom
+    Caption = 'Action'
+    ClientHeight = 108
+    ClientWidth = 996
+    TabOrder = 1
+    object ToggleStateBitBtn: TBitBtn
+      Left = 8
+      Height = 45
+      Top = 32
+      Width = 198
+      Caption = 'Toggle LED State'
+      Images = ImageList1
+      ImageIndex = 7
+      OnClick = ToggleStateBitBtnClick
+      TabOrder = 0
+    end
+    object LEDStateLbl: TLabel
+      Left = 16
+      Height = 25
+      Top = 8
+      Width = 48
+      Caption = 'State :'
+    end
+    object LEDStatusLbl: TLabel
+      Left = 80
+      Height = 25
+      Top = 8
+      Width = 16
+      Caption = '??'
+      Font.Style = [fsBold]
+      ParentFont = False
+    end
+    object ComboBox1: TComboBox
+      Left = 264
+      Height = 33
+      Hint = 'Pick a premade style'
+      Top = 44
+      Width = 496
+      ItemHeight = 25
+      Items.Strings = (
+        'Default LED'
+        'Round Green Active Red Inactive Shaded'
+        'Triangle Green Active Red Inactive Shaded'
+        'Square Green Active Red Inactive Shaded'
+        'Pentagon Green Active Red Inactive Shaded'
+        'Hexagon Green Active Red Inactive Shaded'
+        'Rounded Triangle Active Red Inactive Shaded'
+        'Rounded Square Active Red Inactive Shaded'
+        'Rounded Green Active, Red Inactive, Flat, Thick Border'
+        'Rounded Green Active,  Dark Green Inactive, Flat, Dotted Border'
+        'Rounded Rectangle, Shaded'
+        'Oval Shaded, Rotated'
+      )
+      ParentShowHint = False
+      ShowHint = True
+      TabOrder = 1
+      Text = 'Pick Preset Styles'
+      OnChange = ComboBox1Change
+    end
+    object PresetsLbl: TLabel
+      Left = 264
+      Height = 25
+      Top = 8
+      Width = 116
+      Caption = 'Preset Designs'
+    end
+  end
+  object MainMenu1: TMainMenu
+    Left = 256
+    Top = 368
+    object MenuItem1: TMenuItem
+      Caption = 'File'
+      object AboutMenu: TMenuItem
+        Caption = 'About'
+        OnClick = AboutMenuClick
+      end
+      object ExitMenu: TMenuItem
+        Caption = 'Exit'
+        OnClick = ExitMenuClick
+      end
+    end
+  end
+  object ColorDialog1: TColorDialog
+    Color = clBlack
+    CustomColors.Strings = (
+      'ColorA=000000'
+      'ColorB=000080'
+      'ColorC=008000'
+      'ColorD=008080'
+      'ColorE=800000'
+      'ColorF=800080'
+      'ColorG=808000'
+      'ColorH=808080'
+      'ColorI=C0C0C0'
+      'ColorJ=0000FF'
+      'ColorK=00FF00'
+      'ColorL=00FFFF'
+      'ColorM=FF0000'
+      'ColorN=FF00FF'
+      'ColorO=FFFF00'
+      'ColorP=FFFFFF'
+      'ColorQ=C0DCC0'
+      'ColorR=F0CAA6'
+      'ColorS=F0FBFF'
+      'ColorT=A4A0A0'
+    )
+    Left = 472
+    Top = 368
+  end
+  object ImageList1: TBGRAImageList
+    UseBGRADraw = False
+    Left = 360
+    Top = 368
+    Bitmap = {
+      4C7A100000001000000010000000611600000000000078DAED9B0B5C4ED9FAC7
+      776F737119628ECC8C199718CC08E18C19CC4C62189719D78663308C5B382E43
+      A4DC2A9752547289081DB98F4BA84C88123A2E6FE1AD7457E99E222AEA8D7EFF
+      E759ED376FAF423EFFCFE77FE67F667F3EBFCFDA7BADE7BBD6B3D77A9EB5F7EE
+      2249FF994790C3B832958F2D54BB972168F5CF65B5E555BB9703091781B810A8
+      BC17A3D6BCF712202608883E0DD5CE45B5E78941E429E0961F545E96AFE48356
+      8D2953EDB21163A9762C44EE1F9BCB71C317083F825C3FD772D5D6D9506D9905
+      95C74C04D90E2B7BD9781A0ED70F0157F703577C80306FE0D20E20741B549BA6
+      BDE08FCA6BC12B39847800E73742B561F20B7CD00AF332D5B6DFA0F29C0BF635
+      E7984325977BD8AE5CB571AAE054EE9310B4F48757AEA76AB3C54BC77B25BF71
+      0A10B41E38B30EAAF5136BCFBBFF0A043A01A71CA0721D5F6B3E68C9A032E654
+      AEE310B4646099F4D7F1D7518BFCE77C546D9F0FED9CFA33E5BFC657D5E6E934
+      9E05B4F3FFECD2C1E57FADF87FC601E0459516374261AE391EE52E90652EEAAA
+      B3ADCA1922236E1B526FA84B2FEFC1637F27149D74C493D05D284F8D50539B27
+      D934A9813546467472E9E9F578E8D4070FECBB237F5957E45A7740E6FC36489B
+      DF1605876D4136A964DBE1C571A3539FEC9F8FA235BD51ECDC07454EA678B8B2
+      87E823C7EA33A4CF6981640B4364BB8FA23EA252AAF8413E9704AE27A6374ADC
+      0640BDE1072ABF4791EB40A8A3CEE0D1E1A5C898678494191F20E1D706B87F60
+      31901EEB59395774BFEC338FCB6CF9D69150BB0FC6939DF40C918F8223B6C47F
+      88C45F1B226EF2FB284F0957136BC0735B7AD947DC6FD11A5394B87E2F582E8B
+      1CBF1573A839EE1F5C22C6BF3D461F8567B680D66824AFCF633F27BACF2E283E
+      4039FC548D971DD9DBA723FA1F0AE4EDB582667D8B4E388A797EB467EE2BF9AC
+      6D53113D4A42DEBE45CC5BA2F09E39AF6FE6FCD6C8B66A4FFD18E39E4D475166
+      2F6C8F8774DF40B960737D2C85EF51C4179E95FDA7F9E3D848B76C87F4B92DC4
+      3C67CE6B2DCA6CC77E325B4EEC7CC48C7D478C1D33B1A13C7F4506620D682D1E
+      1EB517EBCB6B944AF32CCA39AD5078F528B2BD6654B0A3253176FE7E1B5EBFAD
+      5AF1D3846382632381D687D788E7397E427DC48EAB237CE671994D5F3B946330
+      E58538E698CC884AE2358A9FD2A48219ADA8E4622634A471ADAB8FDFCA3E8A9A
+      B05FE529116A5EDFBC7D56423C575C277CAE297FAAFA6240EB3252AC4FC51A8D
+      1475AFE2FECAFFCAFC2F3BED8AB2DBE750E0608A5C1BE3DAE57FE876395BCAF1
+      C8E31F221F383F5E27FFCB823655E65AC969373CB0FB42E452C66FCFC7AF29FF
+      1F9F58F5D2DC45592932DCCC6BCCFFA2A3B62FC5CB894F7719FED2FC2FF45D59
+      69FFC87795C8E5BBB33E46F2B426944FEFBD56FE8B7596F33E73A59960F9BE6B
+      93FF79BB7F43D1B56348FE677324D0B87FE5FF7F5FFE733E704CBF51FE9F7B9E
+      8785271CDE30FF51EBE77F59A06B4DD92762FA65F9CFFB1DEF5962EF08747B9E
+      87C7560ABEE8FA3111D335E53FF751E0D85BEC59BCEF680ECEE1CC95BD913CAB
+      39E5C3BBAFFDFCD71CB5CD7FCDF35F73BC49FE73C9FB15EB4DF33FC3ED27A4B9
+      8CF82BFFFFA4F95F7C60A178A77DD3F77FF12E4CAAF5F35F7EFFD71CB579FE6B
+      BFFF6B8ED77DFE73FE17D337CB931DBF8ABE2ADFF9E93D3CDBF13BA4D0FBF0AB
+      F29FBF77F8781CB0B6927F78D44EEC1F85F43C7D55FEF3B752757B178BDFC36B
+      F7FC7FCED7F6FD3F7FFFA24A3A47C3D632FFB3BDA623CB73EA7F5DFE1717A351
+      6E2ECC490B649973DD6B70867171D876E346B97ACF9E223839E5C1D13117BB76
+      3D4044C43335B579924D931A58E3E86824AF5FFF087DFAA4A37BF71474ED9A88
+      0E1DA2D1A64D38DAB6BD025BDBBB209B54B2EDA03B2ED7CF9F7F1FBD7BE7109F
+      0753D31CF4E891467D24E0B3CF22D1A2C555181A0663D4A85B888A428AB61FEC
+      338FCBECA8518FE0E5552A4A53D36C7CF14532BEF9260E0E0E69D44F181A3408
+      C4E2C589888D85A766AEF87ED9671E97593E52529E61F8F03C0C1C988EC4C48A
+      3A3BBB24346C1888F7DFF74778F85335B1063CB73E3E45E27ED9671E3739F999
+      B0BF73A70C494915DFE3F1F18FF1F9E7FF16E3EBEB1FC3962D99207624AF0FCF
+      73972E09E27EB90F1E3729A9AC32FE13129EA05BB7703469128CFAF54F41A138
+      022BAB3868D6D7D13147CC33F7D1BD7B32060C48AF1C57C377EE7C158D1B9FC5
+      BBEF9E84241DC6A24582B7BC770FE6BCBEAD5B87A37D7B9598AB848452D9E727
+      888B7B22CE63638BD0B26590F05D927EAFF49FE78F63A35DBBAB628D56AF4E13
+      F671718F69EDC2D1A9D335C4C41489BA850B2305DBB0E171317F45451031CD6B
+      616F9F46EB1B22D688E7B9438730B1DEEC338F6B651589BFFDED84E06D6CE279
+      FDB66AC54F138E098E0D5E1F16CF33CF559D3A27659F0F0B76E8D0AB1C8329BA
+      71CC31497D242D599244F31C20189E670DC73E5B5BC7571BBF1AD1FD3461BF22
+      229EAA797E788D587CCE75DC5653FEE8F86240EBC2B16129AF11CFF3EB3FFF65
+      65C546E8D796890CD8D5D57741FF5DD7772ECE8B3CE0F8ECE61EFBD2734E13C3
+      CEAD9F353B2736BC0EDBE4C4851B1C98F1D5656D2E2525440ADE346F69C2898D
+      65E5A937E8A5318292E83A25C11520F1321E5D3D5A7EC975CADD731BFE392270
+      F9F0ABE11E73A0CD5F18D56D75FA69AF677187D7A995DB173C507ACECF8DF259
+      569A1FECFD0C9101C0AD9340842FEE1E5EFD4C7D7937549ECFF9F3EBA70FF55F
+      3AF4D1F98D73EC6EF97B7DA2A98F3AE653DF6FCBF89FCFD80EBF92E7E7F20C97
+      ABFE0C5D63B77FE6577BAF9D716B59D39C441DF36C7C7AC9A08C8ADF47B90081
+      CE50AD9F80D799CF9C38A541E0A2FE57D5C7E999E84FEFF17EF6422AD7B1AFC7
+      C787F754F96DB7D355A49FD7328D0D5D2F25D9EA8AD81EAF3386F045F68B7D64
+      5F03ADFB5F25DF1BBD16EFF68B9813313734473C5711FE5B1AD7389FC7F7B4A4
+      39DF53C96FB2A8F8FD04AF0DAD513EAD15AF99BFC7F89F238FF9BC57199B7E5E
+      2D4236CCB60F583AB430C865FA8F953CC582FAD26E111BE277201C2BAA00DCA7
+      D889F2595EAADC669917EE6555107FC4459D767AFBD30B9BE7AFD0F687639163
+      926393623485639563164914BB294AD0FB2138A6E37D37A88337CDB541484895
+      FBE15CE09CE0F3ECB8F03A41EEB36605AD9970E9868F7D896ABF03AE7BD9E41E
+      B3ECEF1515B0B3536DF3F14D647FD3BE91FD757B73D20259E65CF72A2E2423C4
+      50F290B6499E925ADA23413A248BCFB9CE53F2249B6AF72FB3CB66C6D2162959
+      D89F2385E8E8BCDCD71629D56C9F598717C6A57AE944359CAE4E883E52B4FD10
+      3E1F7A3957EF62BDE7D787C4FD6CD5CC95B8B77335B3866186882C8AC4EAD4D5
+      15756CBB5552136BC0732BE6A786B1342C1F5CD6BF58BFA28D186247F2FA68FB
+      6E9F628FE8E2687C10F6411596EB9A8635AD720F9AF5D5F0DCB7F658DAE7DC57
+      95FBAAE02D75FDD71EB34696E523FB5FCDFC69FA78C1678DCE55C493FD657B91
+      33D266BA3AF4E29C573B2EEB20699BB4552B7E9A704CBC69FCC8F1DB81EA936A
+      8CDF73F2B81CBF97CD3AD4903F4D38473836AAE48F4F45BC704B4DF953257F2F
+      8BB81A29AF8FA5380FB3AFF5F3DFDEBEDC88F5A6FB88425F7D86F5BAF62121E5
+      CDF5F4D5417A8AD24D321FC2E273AEA3B6B36C53134BB6774905667DCB86EBF2
+      5CC76D6C43B69F5465A97F7D75B060CDCA3B6AF95FC98B3ECCCA3BD1F543B23D
+      AFCDAF58F1CC8CEAE9FD5F6DA173FF5578569F3E6533D876C58A72534D9D9EE2
+      A9BB42A12E0A097956E7553CF95E876C8B8971ABB453949D22BB6BBA73D2B76F
+      D94C5635EBA224264087BF5E8B75255EEDAFE5FFFA0AFFCBEBBEC61AD7655B66
+      B4E6CFB462FECAA6BF8AAF6EFE840FFAEA73BC36B4469D6B62B98DD7986D79CD
+      75FCFA58133F34C64CEDB5E073AED38A9F6635DCDB27B21F2015F39CCAE27354
+      8C5B35F65EECA3623E787D695DFC597CCE75BA3EFF7F919E9E5E47D2112DFD83
+      24BD4A5ABC832C3E5F4D3A5E4B5EA3FE2467D2A95AF21F92F691F6925C4941B5
+      E47F272D96EB2791426BC95F23D9F1DF7350E9295F3793EDDE268D2679C9D2CC
+      75254FC75CD21D594348274807647E28693FA993ACFD9AF9D5F0D6FDFE2EE5AC
+      9A3478E6976DA58EEFD795C6B76D22756FDA40E327FBB354CBEFA59AF9D5F0F7
+      9D2C98F7BD32B56F77DF41EDA5C041ED113FAEA759AF8F1AB3FD1FA4A95AFC54
+      CDFCEAF0ED890F3F3AB0DD53E253888765D7566CEF23C784A4151FA1BAFE5BF5
+      ED2A4DED6624ADFAF21331BECF771DCC7A7ED488ED7F269D277D21EBBC3CBFDA
+      F327A69EA44F7A9B5487549F6440FA90B49474857495345C9E6783D7E4DF2719
+      923E207D446A466AAACDFF992599796C2329DF50DB24D38DCA3B77EEE04DC4AC
+      F4B59B3225250570E905B87E03B8F70136F507D6F706DCE811B3953E13BDE9FB
+      76377DAF07D0F76DC461407900CC302BF558A74C4B4B030ED263F6C86F6443DF
+      E9211B81934B803F56559C876C004ED127E3CDA3C0BD44204305669895BA3B2A
+      B3B2B270C96F1532948780187A5DBA7D9A4A52FA4D3A0F248EBE4923FD80840B
+      405634703F15CC302B755DA9BC77EF1E26ADE88D59CE83107486C6CAB8556177
+      2F01C88DAFB87E403EE6DD010AD281E2FB608659A9F372E583070FF0F52F1FE1
+      87D99F63FCB25ED87D74258243BD91181588FCBB1128CE8E212EAD827D7C1F28
+      7B026698953AD8280B0B0B317AE8FB183BA229268F6D8185B3BB60F9C29E70B2
+      ED87CDCEC3F12F8FF138BA7B26CE1EB341F4450F14C49E0233CC4AED2C954F9E
+      3CC1F6E95FE05F737AE1C0C23E3861FB03CEAD1B836BDBA723F6B00D32829C51
+      70DD132571FBF12CFD04DD57209861566A3D4759565656853FBE7C30CEACF909
+      97364CC08D1D33117F6021D24FD822FFCC1A1487AEC7D3AB5BC00CB392E12FCA
+      F2F272BC899895DEE9B9537A77B0F28DC4AC24BD23E773B35A8A9977FEAFF3B7
+      9DC25FD61FED49E34896A4C55AB2224D230D6AA738F511DBB6559C241D933E56
+      AC24EE24F3DF0DE91CB6719F7B5E4CF0D1E2C7174F3E066B9B5312AEFCF14CED
+      BFFB61D65ACBD40BFDDB863A93ED60E2EB32FFA9E228F573FCF31F3B5DF43873
+      F051D1E983F7F1C7FE3C5C3B5D8EC003F942DC075F9F39741F6453BCE0E7685F
+      627E21BE2EF39F2A8E4CF15E97151FB0370FFF3E5506FF3DF770787B7AE539EB
+      FCD1C2CAF3358B944FE78DBE7592B8619F2A0E4B6D14075604EC7DF0C4DB2D01
+      C7BD73C8EF12ECDD74074ED661D8EA1889DFB7A5C37757B668635FB8F4DB9DFF
+      D8CCE8D466629BB756F8AC3CB23DB7F08857163C564761A74B3C6CA69FC66EF7
+      3BE0BA9D2E09F05A1B87439EE9E29A75744736965B445E2376B49162E7D839A3
+      C22E72FD56C7DB983DCE17DB9D63E1609D8A0E9FDEC6FC699138B5EF01F9904B
+      F795855DAE89E45F2ABC5D52EF11BBCC48B1BDA191BEA7F5CF6681410B279DCF
+      FAE7185FF556E7088C1EB20BF6B4DD19B70FC61687DBB0B63803878561D4773C
+      7C36DCC5BECDE965C46D265E6AA5EF51AFA5FEA6012DF5372E6FFAC5AE133673
+      778AFC1C356423A68FBD287CDAB4329AC64E610E3BD6DD117D90BD77E33E3E52
+      63F3835223F303929ECF99DE6FB91C0D5B9CF904464D87DC6A5E67FEA996FAAE
+      FB36D8470AD675D94D9A8B3B3427C9586F7B0BDC26D91D92F4F69C15ACDED6E3
+      01CCEA2DF7086EF0ADD5F016FACE5D49235AE83BFDCE73CFB29D132A4AAEA3B6
+      6F04AFCDDA7A9C972C9DFB35F8668144ED2427A9B9FE6AD3E6FAAB7C357DF039
+      D7711BF19FEAB2528F7E55FEC6B6A9FE24E9137D5B7F66B9FC44DFAEB781A26F
+      45E302CFC57145209F37074B237E1D4C35F5480D488DB49FFD1FEB2F09649E4B
+      B9AE81FCAE00BD61338EE87DFD633FB9EE6FF27B424BD2A7A4CF499D1A2A4C27
+      34D3B73E4BE544B98E6DEA6AFB696464244D9B364D5AB76E1DE7959CA77E949F
+      015F51DE2D6DABF05F46D73DDA2A7C396F28F60F0AAE79F3E6D2F8F1E3257B7B
+      7BC9D1D15197277BBF6557039F893C6CAB38614B7C4F0D3F72E44869C18205D2
+      E2C58BABE37BB27D58C0538AE13CCAE78ADCA6BC5D41FCD7CCCF9E3DBB269ED8
+      E37697FCCAE0E7938B80BDF774FA38E448FCB7D5F16BD7AE35717272B2B870BC
+      54E4EBC9DD3955FAF05C9348797D1F6D14FBD6EAF20E0E0E26AB56ADB2282929
+      417171318EEDCCAED287C7EA38CAD304CAE77CB456EC76D5E6EDECEC4C962F5F
+      6EF1F8F1633C7AF4A8529A3E36AEB88DCDAB62B1DF2397586F77521F0D6F6363
+      63B268D1228BA2A222F16CD695DB7215DCEDA2B067631628EF371A2976F43552
+      EC12F367696969326FDE3C0B7E26E7E5E5BDA0888808DCBC7913DE6E69C47A79
+      50CE7F47BCC4FCAC59B34C66CE9C69F1F0E143E4E4E4BCA06BD7AE41A9542231
+      31115F7EF9A5452B7DCFFE468A6D92869F32658A454141013233335F50585818
+      AE5CB982D8D858B46FDFDEA24D9B3626ADF4B74ACC7FA4B0921AEB0D93C68C19
+      23787E9FD2566868282E5DBA84A8A828346BD6CCA269D3A626AD5AB5923ED49F
+      2FD5D16B5719F303070E34F9F6DB6F451FA9A9A942C1C1C108A18FED5BB76EC1
+      C0C0C0E2BDF7DE33A152AA53A7CE0B7F3FDFA85123A9458B16DCB7457272B298
+      2B8DDE7EFB6D0B854261427AD99FE03726B5AB5BB7EEC07AF5EA59C88C057D5F
+      5850BD19A9859CAB9CD70DE59CE5BCD7745A576E6B26DB7D28BF1B3491F70F03
+      795FE07DE55D99D597BF3774BF7F7B92B6E87C8B6BB4456EAFF2EDA9C36F9D3E
+      7D7A16E5102807E1EEEE0E373737383B3B8362248BDB6BE07D35A21C02C5243A
+      77EE0C5A3351F235D76BDBE9F07FA75B091F3E7C38287FD0AF5F3FD0BAE2B7DF
+      7E13255F733DB7B31DDBEBFA4F077FDBF92D59B204A6A6A69833670EACACAC44
+      C9D75CCFEDB25D4DF77FCADADA1A23468CC0E8D1A341B9214ABEE67AED9F2BE8
+      F0811AF1986C6F626282962D5B8A92AFB95EDB4E87FF8AFC8AEFDFBF3F2897D1
+      A74F1F0C183000B4978B92AFB99EDBD98EEDABB9FF1EFC6D3B77EE5CF4EDDB17
+      93274F06ADA528F99AEBB95DB6ABE9FE2FF03DB3BFB4AF63E2C489A2E46BAEE7
+      F61AEEFF9246142782E9D1A3078C8D8D45C9D75CAF6DA7C37F4D7EE5F6ECD913
+      161616F8FEFBEFD1725E4B18EE3614255F733DB7B31DDB5773FF5FF3773DED47
+      225E8C038D617CC958947CCDF5DC2EDB55FD86D5FA37AA499326E1C71F7F446F
+      FA7E1C143D48947CCDF5DC5EDDFFDDC8B9C9797B89C67A326AD4280C1D3A54F8
+      CD255F733DB7CB395E5F87E75CEF429A415292B2AB91526EEFCAFBC3FFE63700
+      F928516E49E6E6E6D24F3FFDD480FCFD8A644E9A2C8BCFBFE236B6615B66AAE1
+      3F9B3CF9D799DEDE5B7E8F895126E7E56594B0F89CEBB88D6D6AE03F9B31639A
+      4D4444705A5656021E3EBC870B17CE8B92C575DC468F2A1BB6D5E6870C19D2F0
+      975FC6CD0E0F0F4E4B49B98982821CC1B8B8B854F25CC76D376E84A64D98307E
+      36331A7EF0E0C1BDB66F773F9294A4A4E7567C25B37AF5EACA7316B725274760
+      E7CE2D4798D1F0B4CE63AF5F3F97CABCB6E89D0ABA752C95EADFA9CC3CFF397F
+      DF590909CA124DBB66BC61C3865519FFC1832CD17EF7EEED1266343CED6F7392
+      92224AB4D9EEDDBB8B3D8BF74F8E3FDE07780F3874E85FC8C8882B6146C3F7EA
+      D56B424444E85D6D3E393951E42E97CF9580B8382562626EDC6546C3D358BD37
+      6F76F3E3F9651FB5FBD0F5FFEEDD4878796DF36346C377EBD6AD51BF7EDF5947
+      455DCBCCCF4FAFC2682B3F3F03F1F1D199B40F5A33A3E1BB74E92275ECD8D1E4
+      871F063B737B61E1FD1758AEBB7327219372D9996D99D1CE7F7A764B868686DD
+      68BF5EE1EAEA72362E2E86FA79505A5858501A1F1F9B49CFC1B3C4AC601BB6D5
+      DE03E8784BFEF99EF15B6FBDF50DBD0B4CA0770E1BD21A59365CC76DFC2E2FEF
+      156F69F1FC2EF0DE6BFE1CE103D956C1ECFF0018A27FCF
+    }
+  end
+end

+ 613 - 0
test/test_superled/sltest.pas

@@ -0,0 +1,613 @@
+// SPDX-License-Identifier: LGPL-3.0-linking-exception
+{
+  Part of BGRA Controls. Made by third party.
+  For detailed information see readme.txt
+
+  Site: https://sourceforge.net/p/bgra-controls/
+  Wiki: http://wiki.lazarus.freepascal.org/BGRAControls
+  Forum: http://forum.lazarus.freepascal.org/index.php/board,46.0.html
+
+}
+{******************************* CONTRIBUTOR(S) ******************************
+- Sandy Ganz | [email protected]
+  Test Program for SuperLED
+***************************** END CONTRIBUTOR(S) *****************************}
+
+unit sltest;
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, Menus,
+  ComCtrls, ColorBox, Buttons, SpinEx, BGRATheme, SuperLED,
+  BGRAImageList, about;
+
+const
+  VERSIONSTR = '1.00';            // SL TEST version, Should ALWAYS show as a delta when merging!
+
+type
+
+  { TSLTestFrm }
+
+  TSLTestFrm = class(TForm)
+    AutoScaleCb: TCheckBox;
+    BackgroundColorCb: TColorBox;
+    BackgroundColorLbl: TLabel;
+    AutoScaleLbl: TLabel;
+    ComboBox1: TComboBox;
+    GroupBox7: TGroupBox;
+    BorderColorCb: TColorBox;
+    BorderColorLbl: TLabel;
+    BorderOpacityLbl: TLabel;
+    BorderOpacitySpe: TSpinEditEx;
+    BorderStyleCb: TComboBox;
+    BorderStyleLbl: TLabel;
+    BorderThicknessLbl: TLabel;
+    BorderThicknessSpe: TSpinEditEx;
+    ActiveStateCb: TCheckBox;
+    DrawingRoundRadiusSpe: TSpinEditEx;
+    DrawingShapeCb: TComboBox;
+    DrawingFillOpacitySpe: TSpinEditEx;
+    DrawingActiveColorCb: TColorBox;
+    ColorDialog1: TColorDialog;
+    DrawingInactiveBrightnessSpe: TSpinEditEx;
+    DrawingInactiveColorCb: TColorBox;
+    DrawingActiveColorLbl: TLabel;
+    DrawingFillOpacityLbl: TLabel;
+    DrawingInactiveBrightnessLbl: TLabel;
+    DrawingInactiveColorLbl: TLabel;
+    DrawingRadiusLbl: TLabel;
+    DrawingStyleCb: TComboBox;
+    DrawingShapeLbl: TLabel;
+    DrawingStyleLbl: TLabel;
+    GroupBox1: TGroupBox;
+    GroupBox2: TGroupBox;
+    GroupBox3: TGroupBox;
+    GroupBox4: TGroupBox;
+    GroupBox5: TGroupBox;
+    GroupBox6: TGroupBox;
+    HeightAddBtn: TBitBtn;
+    HeightLbl: TLabel;
+    HeightSubBtn: TBitBtn;
+    HeightValLbl: TLabel;
+    ImageList1: TBGRAImageList;
+    DrawingAngleLbl: TLabel;
+    LEDStateLbl: TLabel;
+    LEDStatusLbl: TLabel;
+    LeftAddBtn: TBitBtn;
+    LeftLbl: TLabel;
+    LeftSubBtn: TBitBtn;
+    LeftValLbl: TLabel;
+    MainMenu1: TMainMenu;
+    DrawingAngleSpe: TFloatSpinEditEx;
+    MenuItem1: TMenuItem;
+    AboutMenu: TMenuItem;
+    ExitMenu: TMenuItem;
+    LEDTs: TPageControl;
+    PresetsLbl: TLabel;
+    ResetPositionBtn: TBitBtn;
+    ResetSizeBtn: TBitBtn;
+    MakeBigBtn: TBitBtn;
+    SuperLED: TSuperLED;
+    BasicTab: TTabSheet;
+    BorderTab: TTabSheet;
+    DrawingTab: TTabSheet;
+    ToggleStateBitBtn: TBitBtn;
+    TopAddBtn: TBitBtn;
+    TopLbl: TLabel;
+    TopSubBtn: TBitBtn;
+    TopValLbl: TLabel;
+    WidthAddBtn: TBitBtn;
+    WidthHeightAddBtn: TBitBtn;
+    WidthHeightSubBtn: TBitBtn;
+    WidthLbl: TLabel;
+    WidthSubBtn: TBitBtn;
+    WidthValLbl: TLabel;
+    procedure AboutMenuClick(Sender: TObject);
+    procedure AutoScaleCbChange(Sender: TObject);
+    procedure ComboBox1Change(Sender: TObject);
+    procedure FormConstrainedResize({%H-}Sender: TObject; var {%H-}MinWidth, {%H-}MinHeight,
+      {%H-}MaxWidth, {%H-}MaxHeight: TConstraintSize);
+    procedure MakeBigBtnClick(Sender: TObject);
+    procedure SuperLEDDblClick(Sender: TObject);
+    procedure ToggleStateBitBtnClick(Sender: TObject);
+    procedure BorderColorCbChange(Sender: TObject);
+    procedure BackgroundColorCbChange(Sender: TObject);
+    procedure BorderOpacitySpeChange(Sender: TObject);
+    procedure BorderStyleCbChange(Sender: TObject);
+    procedure ActiveStateCbChange(Sender: TObject);
+    procedure DrawingActiveColorCbChange(Sender: TObject);
+    procedure DrawingAngleSpeChange(Sender: TObject);
+    procedure DrawingFillOpacitySpeChange(Sender: TObject);
+    procedure DrawingInactiveBrightnessSpeChange(Sender: TObject);
+    procedure DrawingInactiveColorCbChange(Sender: TObject);
+    procedure DrawingRoundRadiusSpeChange(Sender: TObject);
+    procedure DrawingShapeCbChange(Sender: TObject);
+    procedure DrawingStyleCbChange(Sender: TObject);
+    procedure ExitMenuClick(Sender: TObject);
+    procedure FormCreate(Sender: TObject);
+    procedure FormDestroy(Sender: TObject);
+    procedure BorderThicknessSpeChange(Sender: TObject);
+    procedure HeightAddBtnClick(Sender: TObject);
+    procedure HeightSubBtnClick(Sender: TObject);
+    procedure LeftAddBtnClick(Sender: TObject);
+    procedure LeftSubBtnClick(Sender: TObject);
+    procedure ResetPositionBtnClick(Sender: TObject);
+    procedure ResetSizeBtnClick(Sender: TObject);
+    procedure SuperLEDClick(Sender: TObject);
+    procedure TopAddBtnClick(Sender: TObject);
+    procedure TopSubBtnClick(Sender: TObject);
+    procedure WidthAddBtnClick(Sender: TObject);
+    procedure WidthHeightAddBtnClick(Sender: TObject);
+    procedure WidthHeightSubBtnClick(Sender: TObject);
+    procedure WidthSubBtnClick(Sender: TObject);
+  private
+    FSavedLED: TSuperLED;
+  public
+    procedure LEDDefaults;
+    procedure UpdateAllStats;
+    procedure UpdateBasicStats;
+    procedure UpdateWHStats;
+    procedure UpdateLTStats;
+    procedure UpdateBorderStats;
+    procedure UpdateDrawingStats;
+  end;
+
+var
+  SLTestFrm: TSLTestFrm;
+
+implementation
+
+{$R *.lfm}
+
+{ TSLTestFrm }
+
+procedure TSLTestFrm.ActiveStateCbChange(Sender: TObject);
+begin
+  SuperLED.Active := ActiveStateCb.Checked;
+  UpdateBasicStats;
+end;
+
+procedure TSLTestFrm.DrawingActiveColorCbChange(Sender: TObject);
+begin
+  SuperLED.ActiveColor := DrawingActiveColorCb.Selected;
+end;
+
+procedure TSLTestFrm.DrawingAngleSpeChange(Sender: TObject);
+begin
+  SuperLED.Angle := DrawingAngleSpe.Value;
+end;
+
+procedure TSLTestFrm.DrawingFillOpacitySpeChange(Sender: TObject);
+begin
+  SuperLED.FillOpacity := DrawingFillOpacitySpe.Value;
+end;
+
+procedure TSLTestFrm.DrawingInactiveBrightnessSpeChange(Sender: TObject);
+begin
+  SuperLED.InactiveBrightness := DrawingInactiveBrightnessSpe.Value;
+end;
+
+procedure TSLTestFrm.DrawingInactiveColorCbChange(Sender: TObject);
+begin
+  SuperLED.InactiveColor := DrawingInactiveColorCb.Selected;
+end;
+
+procedure TSLTestFrm.DrawingRoundRadiusSpeChange(Sender: TObject);
+begin
+  SuperLED.RoundRadius := DrawingRoundRadiusSpe.Value;
+end;
+
+procedure TSLTestFrm.DrawingShapeCbChange(Sender: TObject);
+begin
+  // CB items must match the items in TSLEDShape
+  SuperLED.Shape := TSLEDShape(DrawingShapeCb.ItemIndex);
+end;
+
+procedure TSLTestFrm.DrawingStyleCbChange(Sender: TObject);
+begin
+  // CB items must match the items in TSLEDStyle
+  SuperLED.Style := TSLEDStyle(DrawingStyleCb.ItemIndex);
+end;
+
+procedure TSLTestFrm.ExitMenuClick(Sender: TObject);
+begin
+  Close;
+end;
+
+procedure TSLTestFrm.FormCreate(Sender: TObject);
+begin
+  Caption := 'Super LED Test Application ' + VERSIONSTR;
+
+  UpdateAllStats;
+
+  // Create a SuperLED to have defaults, clean up in form destroy
+
+  FSavedLED := TSuperLED.Create(nil);
+end;
+
+procedure TSLTestFrm.FormDestroy(Sender: TObject);
+begin
+  FSavedLED.Free;
+end;
+
+procedure TSLTestFrm.BorderThicknessSpeChange(Sender: TObject);
+begin
+  SuperLED.BorderThickness := BorderThicknessSpe.Value;
+end;
+
+procedure TSLTestFrm.HeightAddBtnClick(Sender: TObject);
+begin
+  SuperLED.Height := SuperLED.Height + 5;
+  UpdateWHStats;
+end;
+
+procedure TSLTestFrm.HeightSubBtnClick(Sender: TObject);
+begin
+  SuperLED.Height := SuperLED.Height - 5;
+  UpdateWHStats;
+end;
+
+procedure TSLTestFrm.LeftAddBtnClick(Sender: TObject);
+begin
+  SuperLED.Left := SuperLED.Left + 5;
+  UpdateLTStats;
+end;
+
+procedure TSLTestFrm.LeftSubBtnClick(Sender: TObject);
+begin
+  SuperLED.Left := SuperLED.Left - 5;
+  UpdateLTStats;
+end;
+
+procedure TSLTestFrm.ResetPositionBtnClick(Sender: TObject);
+begin
+  SuperLED.Left := 100;
+  SuperLED.Top := 100;
+  UpdateLTStats;
+end;
+
+procedure TSLTestFrm.ResetSizeBtnClick(Sender: TObject);
+begin
+  SuperLED.Width := 32;
+  SuperLED.Height := 32;
+
+  // Make sure visiable
+
+  ResetPositionBtn.Click;
+  UpdateWHStats;
+end;
+
+procedure TSLTestFrm.SuperLEDClick(Sender: TObject);
+begin
+  ToggleStateBitBtn.OnClick(self);
+end;
+
+procedure TSLTestFrm.TopAddBtnClick(Sender: TObject);
+begin
+  SuperLED.Top := SuperLED.Top + 5;
+  UpdateLTStats;
+end;
+
+procedure TSLTestFrm.TopSubBtnClick(Sender: TObject);
+begin
+  SuperLED.Top := SuperLED.Top - 5;
+  UpdateLTStats;
+end;
+
+procedure TSLTestFrm.WidthAddBtnClick(Sender: TObject);
+begin
+  SuperLED.Width := SuperLED.Width + 5;
+  UpdateWHStats;
+end;
+
+procedure TSLTestFrm.WidthHeightAddBtnClick(Sender: TObject);
+begin
+  SuperLED.Height := SuperLED.Height + 5;
+  SuperLED.Width := SuperLED.Width + 5;
+  SuperLED.Left := SuperLED.Left - 2;
+  SuperLED.Top := SuperLED.Top - 2;
+  UpdateWHStats;
+  UpdateLTStats;
+end;
+
+procedure TSLTestFrm.WidthHeightSubBtnClick(Sender: TObject);
+begin
+  SuperLED.Height := SuperLED.Height - 5;
+  SuperLED.Width := SuperLED.Width - 5;
+  SuperLED.Left := SuperLED.Left + 2;
+  SuperLED.Top := SuperLED.Top + 2;
+  UpdateWHStats;
+  UpdateLTStats;
+end;
+
+procedure TSLTestFrm.WidthSubBtnClick(Sender: TObject);
+begin
+  SuperLED.Width := SuperLED.Width - 5;
+  UpdateWHStats;
+end;
+
+procedure TSLTestFrm.LEDDefaults;
+begin
+  // Reset anything from the saved default LED back to the active one
+
+  with SuperLED do
+  begin
+    // Basic Settings, check properties for important ones
+    // and add any new here!
+
+    Width := FSavedLED.Width;
+    Height := FSavedLED.Height;
+
+    Angle := FSavedLED.Angle;
+    AutoScale := FSavedLED.AutoScale;
+    BorderColor := FSavedLED.BorderColor;
+    BorderOpacity := FSavedLED.BorderOpacity;
+    BorderStyle := FSavedLED.BorderStyle;
+    BorderThickness := FSavedLED.BorderThickness;
+    Color := FSavedLED.Color;
+    FillOpacity := FSavedLED.FillOpacity;
+    InactiveBrightness := FSavedLED.InactiveBrightness;
+    InactiveColor := FSavedLED.InactiveColor;
+    RoundRadius := FSavedLED.RoundRadius;
+    Shape := FSavedLED.Shape;
+    Style := FSavedLED.Style;
+  end;
+end;
+
+procedure TSLTestFrm.UpdateAllStats;
+begin
+  UpdateWHStats;
+  UpdateLTStats;
+  UpdateBasicStats;
+  UpdateBorderStats;
+  UpdateDrawingStats;
+end;
+
+procedure TSLTestFrm.UpdateBasicStats;
+begin
+  AutoScaleCb.Checked := SuperLED.AutoScale;
+  BackgroundColorCb.Selected := SuperLED.Color;
+  AutoScaleLbl.Visible := SuperLED.AutoScale;
+
+  if SuperLED.Active then
+  begin
+    LEDStatusLbl.Font.Color := SuperLED.ActiveColor;
+    LEDStatusLbl.Caption := 'Active';
+  end
+  else
+  begin
+    LEDStatusLbl.Font.Color := SuperLED.InactiveColor;
+    LEDStatusLbl.Caption := 'Inactive';
+  end;
+
+end;
+
+procedure TSLTestFrm.UpdateWHStats;
+begin
+    WidthValLbl.Caption := IntToStr(SuperLED.Width);
+    HeightValLbl.Caption := IntToStr(SuperLED.Height);
+end;
+
+procedure TSLTestFrm.UpdateLTStats;
+begin
+  LeftValLbl.Caption := IntToStr(SuperLED.Left);
+  TopValLbl.Caption := IntToStr(SuperLED.Top);
+end;
+
+procedure TSLTestFrm.UpdateBorderStats;
+begin
+  BorderColorCb.Selected := SuperLED.BorderColor;
+  BorderThicknessSpe.Value := SuperLED.BorderThickness;
+  BorderStyleCb.ItemIndex := ord(SuperLed.BorderStyle);
+  BorderOpacitySpe.Value := SuperLED.BorderOpacity;
+  DrawingInactiveBrightnessSpe.Value := SuperLED.InactiveBrightness;
+end;
+
+procedure TSLTestFrm.UpdateDrawingStats;
+begin
+  DrawingActiveColorCb.Selected := SuperLED.ActiveColor;
+  DrawingInactiveColorCb.Selected := SuperLED.InactiveColor;
+  DrawingFillOpacitySpe.Value := SuperLED.FillOpacity;
+  DrawingShapeCb.ItemIndex := ord(SuperLED.Shape);
+  DrawingStyleCb.ItemIndex := ord(SuperLED.Style);
+  DrawingRoundRadiusSpe.Value := SuperLED.RoundRadius;
+  DrawingAngleSpe.Value := SuperLED.Angle;
+end;
+
+procedure TSLTestFrm.AboutMenuClick(Sender: TObject);
+begin
+  AboutFrm.VersionStr := VERSIONSTR;
+  AboutFrm.show;
+end;
+
+procedure TSLTestFrm.AutoScaleCbChange(Sender: TObject);
+begin
+  SuperLED.AutoScale := AutoScaleCb.Checked;
+  UpdateBasicStats;
+end;
+
+procedure TSLTestFrm.ComboBox1Change(Sender: TObject);
+begin
+  // set up any presets from combo here
+
+  LEDDefaults;
+  with SuperLED do
+  begin
+    case ComboBox1.ItemIndex of
+    0:begin
+        // reset to default, add anything else here for default if needed
+      end;
+
+    1:begin // Round Green/Red no transition in gradient colors
+        ActiveColor := clLime;
+        InactiveColor := clRed;
+        Shape := slshRound;
+        Style := slsShaded;
+        InactiveBrightness := 0;  // allows full inactive color to be shown, no gradient
+      end;
+    2:begin // Triangle
+      ActiveColor := clLime;
+      InactiveColor := clRed;
+      Shape := slshTriangle;
+      Style := slsShaded;
+      Angle := 60;  // Rotate so point down
+      InactiveBrightness := 0;
+      end;
+    3:begin // Square
+      ActiveColor := clLime;
+      InactiveColor := clRed;
+      Shape := slshSquare;
+      Style := slsShaded;
+      Angle := 45;  // Rotate so flat up
+      InactiveBrightness := 0;
+      end;
+    4:begin // Pentagon
+      ActiveColor := clLime;
+      InactiveColor := clRed;
+      Shape := slshPentagon;
+      Style := slsShaded;
+      Angle := 0;
+      InactiveBrightness := 0;
+      end;
+    5:begin // Hexagon
+      ActiveColor := clLime;
+      InactiveColor := clRed;
+      Shape := slshHexagon;
+      Style := slsShaded;
+      Angle := 0;
+      InactiveBrightness := 0;
+      end;
+    6:begin // Triangle Rounded
+      ActiveColor := clLime;
+      InactiveColor := clRed;
+      Shape := slshTriangle;
+      Style := slsShaded;
+      Angle := 60;  // Rotate so point down
+      InactiveBrightness := 0;
+      RoundRadius := 5;
+      end;
+    7:begin // Square Rounded
+      ActiveColor := clLime;
+      InactiveColor := clRed;
+      Shape := slshSquare;
+      Style := slsShaded;
+      Angle := 45;  // Rotate so flat up
+      InactiveBrightness := 0;
+      RoundRadius := 5;
+      end;
+    8:begin // Flat Green Active, Red Inactive, Thick Border
+        ActiveColor := clLime;
+        InactiveColor := clRed;
+        BorderThickness := 5;
+        Shape := slshRound;
+        Style := slsFlat;
+        InactiveBrightness := 100;  // allows full inactive color to be shown, no gradient
+      end;
+    9:begin // Flat Green Active, Dark Green Inactive, Dotted Border
+        ActiveColor := clLime;
+        InactiveColor := clLime;
+        BorderThickness := 3;
+        BorderStyle := psDot;
+        BorderColor := clBlack;
+        Shape := slshRound;
+        Style := slsFlat;
+        InactiveBrightness := 20;  // light green for off
+      end;
+    10:begin
+        ActiveColor := clLime;
+        InactiveColor := clBlack;
+        BorderThickness := 5;
+        Shape := slshSquare;
+        Style := slsShaded;
+        Width := Height * 2;
+        Left := 116 - Width div 2; // fudge it to the center of the rectangle
+        Angle := 45;  // Rotate so flat up
+        InactiveBrightness := 25; // just a touch of color
+        RoundRadius := 5;
+      end;
+    11:begin
+        ActiveColor := clLime;
+        InactiveColor := clBlack;
+        BorderThickness := 5;
+        Shape := slshRound;
+        Style := slsShaded;
+        Width := Height * 2;
+        Left := 116 - Width div 2; // fudge it to the center of the rectangle
+        Angle := 0;  // No rotation on slshRound types!
+        InactiveBrightness := 25; // just a touch of color
+        RoundRadius := 5;
+      end;
+    end;
+  end;
+  UpdateAllStats;
+end;
+
+procedure TSLTestFrm.FormConstrainedResize(Sender: TObject; var MinWidth,
+  MinHeight, MaxWidth, MaxHeight: TConstraintSize);
+begin
+  UpdateAllStats;
+end;
+
+procedure TSLTestFrm.MakeBigBtnClick(Sender: TObject);
+begin
+  with SuperLED do
+  begin
+    Height := Height * 2;
+    Width := Width * 2;
+    Left := 100 - Width div 2;
+    Top := 100 - Height div 2;
+  end;
+  UpdateWHStats;
+  UpdateLTStats;
+end;
+
+procedure TSLTestFrm.SuperLEDDblClick(Sender: TObject);
+begin
+  // Double Click just mess with colors to see if it works
+  // Won't do much if the user changes the colors
+
+  if SuperLED.ActiveColor = clRed then
+    SuperLED.ActiveColor := clLime
+  else
+    SuperLED.ActiveColor := clRed;
+  SuperLED.Active := True;  // force active just because
+  UpdateBasicStats;
+end;
+
+procedure TSLTestFrm.ToggleStateBitBtnClick(Sender: TObject);
+begin
+  SuperLED.Active := not SuperLED.Active;
+  ActiveStateCb.Checked := SuperLED.Active;
+  UpdateBasicStats;
+end;
+
+procedure TSLTestFrm.BorderColorCbChange(Sender: TObject);
+begin
+  SuperLED.BorderColor := BorderColorCb.Selected;
+end;
+
+procedure TSLTestFrm.BackgroundColorCbChange(Sender: TObject);
+begin
+  SuperLED.Color := BackgroundColorCb.Selected;
+end;
+
+procedure TSLTestFrm.BorderOpacitySpeChange(Sender: TObject);
+begin
+  SuperLED.BorderOpacity := BorderOpacitySpe.Value;
+end;
+
+procedure TSLTestFrm.BorderStyleCbChange(Sender: TObject);
+var
+  bs : integer;
+begin
+  // assumes items are matching in the cb
+
+  bs := BorderStyleCb.ItemIndex;
+  SuperLED.BorderStyle := TPenStyle(bs);
+end;
+
+end.
+