| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734 |
- // 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.
|