| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452 |
- // SPDX-License-Identifier: LGPL-3.0-linking-exception
- {
- Created by BGRA Controls Team
- Dibo, Circular, lainz (007) and contributors.
- 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) ******************************
- - Edivando S. Santos Brasil | [email protected]
- (Compatibility with delphi VCL 11/2018)
- ***************************** END CONTRIBUTOR(S) *****************************}
- unit BGRAShape;
- {$I bgracontrols.inc}
- interface
- uses
- Classes, SysUtils, {$IFDEF FPC}LResources,{$ENDIF} Forms, Controls, Graphics, Dialogs,
- {$IFNDEF FPC}Types, BGRAGraphics, GraphType, FPImage, {$ENDIF}
- BCBaseCtrls, BGRABitmap, BGRABitmapTypes, BCTypes;
- type
- TBGRAShapeType = (stRegularPolygon, stEllipse);
- { TBGRAShape }
- TBGRAShape = class(TBGRAGraphicCtrl)
- private
- { Private declarations }
- FBorderColor: TColor;
- FBorderOpacity: byte;
- FBorderStyle: TPenStyle;
- FBorderWidth: integer;
- FBorderGradient: TBCGradient;
- FUseBorderGradient: boolean;
- FFillColor: TColor;
- FFillOpacity: byte;
- FFillGradient: TBCGradient;
- FUseFillGradient: boolean;
- FRoundRadius: integer;
- FBGRA: TBGRABitmap;
- FSideCount: integer;
- FRatioXY: single;
- FUseRatioXY: boolean;
- FAngle: single;
- FShapeType: TBGRAShapeType;
- procedure SetAngle(const AValue: single);
- procedure SetBorderColor(const AValue: TColor);
- procedure SetBorderGradient(const AValue: TBCGradient);
- procedure SetBorderOpacity(const AValue: byte);
- procedure SetBorderStyle(const AValue: TPenStyle);
- procedure SetBorderWidth(AValue: integer);
- procedure SetFillColor(const AValue: TColor);
- procedure SetFillGradient(const AValue: TBCGradient);
- procedure SetFillOpacity(const AValue: byte);
- procedure SetRatioXY(const AValue: single);
- procedure SetRoundRadius(AValue: integer);
- procedure SetShapeType(const AValue: TBGRAShapeType);
- procedure SetSideCount(AValue: integer);
- procedure SetUseBorderGradient(const AValue: boolean);
- procedure SetUseFillGradient(const AValue: boolean);
- procedure SetUseRatioXY(const AValue: boolean);
- protected
- { Protected declarations }
- procedure Paint; override;
- public
- { Public declarations }
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; 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 AutoSize;
- property Align;
- property Anchors;
- property Angle: single Read FAngle Write SetAngle {$IFDEF FPC}default 0{$ENDIF};
- property BorderWidth: integer Read FBorderWidth Write SetBorderWidth default 1;
- property BorderOpacity: byte Read FBorderOpacity Write SetBorderOpacity default 255;
- property BorderColor: TColor Read FBorderColor Write SetBorderColor;
- property BorderGradient: TBCGradient Read FBorderGradient Write SetBorderGradient;
- property BorderStyle: TPenStyle
- Read FBorderStyle Write SetBorderStyle default psSolid;
- property FillColor: TColor Read FFillColor Write SetFillColor;
- property FillOpacity: byte Read FFillOpacity Write SetFillOpacity;
- property FillGradient: TBCGradient Read FFillGradient Write SetFillGradient;
- property SideCount: integer Read FSideCount Write SetSideCount default 4;
- property RatioXY: single Read FRatioXY Write SetRatioXY {$IFDEF FPC}default 1{$ENDIF};
- property UseRatioXY: boolean Read FUseRatioXY Write SetUseRatioXY default False;
- property UseFillGradient: boolean Read FUseFillGradient
- Write SetUseFillGradient default False;
- property UseBorderGradient: boolean Read FUseBorderGradient
- Write SetUseBorderGradient default False;
- property ShapeType: TBGRAShapeType
- Read FShapeType Write SetShapeType default stRegularPolygon;
- property BorderSpacing;
- property Caption;
- property PopupMenu;
- property RoundRadius: integer Read FRoundRadius Write SetRoundRadius default 0;
- property Visible;
- property OnClick;
- property OnDblClick;
- property OnMouseDown;
- property OnMouseEnter;
- property OnMouseLeave;
- property OnMouseMove;
- property OnMouseUp;
- end;
- {$IFDEF FPC}procedure Register;{$ENDIF}
- implementation
- uses BCTools;
- {$IFDEF FPC}
- procedure Register;
- begin
- RegisterComponents('BGRA Controls', [TBGRAShape]);
- end;
- {$ENDIF}
- { TBGRAShape }
- procedure TBGRAShape.SetBorderColor(const AValue: TColor);
- begin
- if FBorderColor = AValue then
- exit;
- FBorderColor := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetBorderGradient(const AValue: TBCGradient);
- begin
- if FBorderGradient = AValue then
- exit;
- FBorderGradient.Assign(AValue);
- Invalidate;
- end;
- procedure TBGRAShape.SetAngle(const AValue: single);
- begin
- if FAngle = AValue then
- exit;
- FAngle := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetBorderOpacity(const AValue: byte);
- begin
- if FBorderOpacity = AValue then
- exit;
- FBorderOpacity := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetBorderStyle(const AValue: TPenStyle);
- begin
- if FBorderStyle = AValue then
- exit;
- FBorderStyle := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetBorderWidth(AValue: integer);
- begin
- if AValue < 0 then
- AValue := 0;
- if FBorderWidth = AValue then
- exit;
- FBorderWidth := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetFillColor(const AValue: TColor);
- begin
- if FFillColor = AValue then
- exit;
- FFillColor := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetFillGradient(const AValue: TBCGradient);
- begin
- if FFillGradient = AValue then
- exit;
- FFillGradient.Assign(AValue);
- Invalidate;
- end;
- procedure TBGRAShape.SetFillOpacity(const AValue: byte);
- begin
- if FFillOpacity = AValue then
- exit;
- FFillOpacity := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetRatioXY(const AValue: single);
- begin
- if FRatioXY = AValue then
- exit;
- FRatioXY := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetRoundRadius(AValue: integer);
- begin
- if AValue < 0 then
- AValue := 0;
- if FRoundRadius = AValue then
- exit;
- FRoundRadius := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetShapeType(const AValue: TBGRAShapeType);
- begin
- if FShapeType = AValue then
- exit;
- FShapeType := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetSideCount(AValue: integer);
- begin
- if AValue < 3 then
- AValue := 3;
- if FSideCount = AValue then
- exit;
- FSideCount := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetUseBorderGradient(const AValue: boolean);
- begin
- if FUseBorderGradient = AValue then
- exit;
- FUseBorderGradient := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetUseFillGradient(const AValue: boolean);
- begin
- if FUseFillGradient = AValue then
- exit;
- FUseFillGradient := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.SetUseRatioXY(const AValue: boolean);
- begin
- if FUseRatioXY = AValue then
- exit;
- FUseRatioXY := AValue;
- Invalidate;
- end;
- procedure TBGRAShape.Paint;
- var
- cx, cy, rx, ry, curRatio, a: single;
- coords: array of TPointF;
- minCoord, maxCoord: TPointF;
- i: integer;
- borderGrad, fillGrad: TBGRACustomScanner;
- scaling: Double;
- begin
- if FBGRA = nil then FBGRA := TBGRABitmap.Create;
- scaling := GetCanvasScaleFactor;
- FBGRA.SetSize(round(Width*scaling), round(Height*scaling));
- FBGRA.FillTransparent;
- FBGRA.PenStyle := FBorderStyle;
- with FBGRA.Canvas2D do
- begin
- lineJoin := 'round';
- if FUseBorderGradient then
- begin
- borderGrad := CreateGradient(FBorderGradient, Classes.rect(0, 0, FBGRA.Width, FBGRA.Height));
- strokeStyle(borderGrad);
- end
- else
- begin
- borderGrad := nil;
- strokeStyle(ColorToBGRA(ColorToRGB(FBorderColor), FBorderOpacity));
- end;
- lineStyle(FBGRA.CustomPenStyle);
- lineWidth := FBorderWidth*scaling;
- if FUseFillGradient then
- begin
- fillGrad := CreateGradient(FFillGradient, Classes.rect(0, 0, FBGRA.Width, FBGRA.Height));
- fillStyle(fillGrad);
- end
- else
- begin
- fillGrad := nil;
- fillStyle(ColorToBGRA(ColorToRGB(FFillColor), FFillOpacity));
- end;
- cx := FBGRA.Width / 2;
- cy := FBGRA.Height / 2;
- rx := (FBGRA.Width - FBorderWidth*scaling) / 2;
- ry := (FBGRA.Height - FBorderWidth*scaling) / 2;
- if FUseRatioXY and (ry <> 0) and (FRatioXY <> 0) then
- begin
- curRatio := rx / ry;
- if FRatioXY > curRatio then
- ry := ry / (FRatioXY / curRatio)
- else
- rx := rx / (curRatio / FRatioXY);
- end;
- if FShapeType = stRegularPolygon then
- begin
- setlength(coords, FSideCount);
- for i := 0 to high(coords) do
- begin
- a := (i / FSideCount + FAngle / 360) * 2 * Pi;
- coords[i] := PointF(sin(a), -cos(a));
- end;
- minCoord := coords[0];
- maxCoord := coords[0];
- for i := 1 to high(coords) 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 high(coords) 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 high(coords) do
- begin
- lineTo((coords[i] + coords[(i + 1) mod length(coords)]) * (1 / 2));
- arcTo(coords[(i + 1) mod length(coords)], coords[(i + 2) mod
- length(coords)], FRoundRadius);
- end;
- closePath;
- end
- else
- begin
- save;
- translate(cx, cy);
- scale(rx, ry);
- beginPath;
- arc(0, 0, 1, 0, 2 * Pi);
- restore;
- end;
- fill;
- if FBorderWidth <> 0 then
- stroke;
- fillStyle(BGRAWhite);
- strokeStyle(BGRABlack);
- fillGrad.Free;
- borderGrad.Free;
- end;
- FBGRA.Draw(Self.Canvas, rect(0,0,Width,Height), False);
- end;
- constructor TBGRAShape.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- with GetControlClassDefaultSize do
- SetInitialBounds(0, 0, CX, CY);
- FBGRA := nil;
- FBorderColor := clWindowText;
- FBorderOpacity := 255;
- FBorderWidth := 1;
- FBorderStyle := psSolid;
- FBorderGradient := TBCGradient.Create(Self);
- FBorderGradient.Point2XPercent := 100;
- FBorderGradient.StartColor := clWhite;
- FBorderGradient.EndColor := clBlack;
- FFillColor := clWindow;
- FFillOpacity := 255;
- FFillGradient := TBCGradient.Create(Self);
- FRoundRadius := 0;
- FSideCount := 4;
- FRatioXY := 1;
- FUseRatioXY := False;
- end;
- destructor TBGRAShape.Destroy;
- begin
- FBGRA.Free;
- FFillGradient.Free;
- FBorderGradient.Free;
- inherited Destroy;
- end;
- {$IFDEF FPC}
- procedure TBGRAShape.SaveToFile(AFileName: string);
- var
- AStream: TMemoryStream;
- begin
- AStream := TMemoryStream.Create;
- try
- WriteComponentAsTextToStream(AStream, Self);
- AStream.SaveToFile(AFileName);
- finally
- AStream.Free;
- end;
- end;
- procedure TBGRAShape.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 TBGRAShape.OnFindClass(Reader: TReader; const AClassName: string;
- var ComponentClass: TComponentClass);
- begin
- if CompareText(AClassName, 'TBGRAShape') = 0 then
- ComponentClass := TBGRAShape;
- end;
- end.
|