1 | unit BGRAShape;
|
---|
2 |
|
---|
3 | {$mode objfpc}{$H+}
|
---|
4 |
|
---|
5 | interface
|
---|
6 |
|
---|
7 | uses
|
---|
8 | Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
|
---|
9 | BGRABitmap, BGRABitmapTypes, BCTypes;
|
---|
10 |
|
---|
11 | type
|
---|
12 | TBGRAShapeType = (stRegularPolygon, stEllipse);
|
---|
13 |
|
---|
14 | { TBGRAShape }
|
---|
15 |
|
---|
16 | TBGRAShape = class(TGraphicControl)
|
---|
17 | private
|
---|
18 | { Private declarations }
|
---|
19 | FBorderColor: TColor;
|
---|
20 | FBorderOpacity: byte;
|
---|
21 | FBorderStyle: TPenStyle;
|
---|
22 | FBorderWidth: integer;
|
---|
23 | FBorderGradient: TBCGradient;
|
---|
24 | FUseBorderGradient: boolean;
|
---|
25 | FFillColor: TColor;
|
---|
26 | FFillOpacity: byte;
|
---|
27 | FFillGradient: TBCGradient;
|
---|
28 | FUseFillGradient: boolean;
|
---|
29 | FRoundRadius: integer;
|
---|
30 | FBGRA: TBGRABitmap;
|
---|
31 | FSideCount: integer;
|
---|
32 | FRatioXY: single;
|
---|
33 | FUseRatioXY: boolean;
|
---|
34 | FAngle: single;
|
---|
35 | FShapeType: TBGRAShapeType;
|
---|
36 | procedure SetAngle(const AValue: single);
|
---|
37 | procedure SetBorderColor(const AValue: TColor);
|
---|
38 | procedure SetBorderGradient(const AValue: TBCGradient);
|
---|
39 | procedure SetBorderOpacity(const AValue: byte);
|
---|
40 | procedure SetBorderStyle(const AValue: TPenStyle);
|
---|
41 | procedure SetBorderWidth(AValue: integer);
|
---|
42 | procedure SetFillColor(const AValue: TColor);
|
---|
43 | procedure SetFillGradient(const AValue: TBCGradient);
|
---|
44 | procedure SetFillOpacity(const AValue: byte);
|
---|
45 | procedure SetRatioXY(const AValue: single);
|
---|
46 | procedure SetRoundRadius(AValue: integer);
|
---|
47 | procedure SetShapeType(const AValue: TBGRAShapeType);
|
---|
48 | procedure SetSideCount(AValue: integer);
|
---|
49 | procedure SetUseBorderGradient(const AValue: boolean);
|
---|
50 | procedure SetUseFillGradient(const AValue: boolean);
|
---|
51 | procedure SetUseRatioXY(const AValue: boolean);
|
---|
52 | protected
|
---|
53 | { Protected declarations }
|
---|
54 | procedure Paint; override;
|
---|
55 | procedure Resize; override;
|
---|
56 | public
|
---|
57 | { Public declarations }
|
---|
58 | constructor Create(AOwner: TComponent); override;
|
---|
59 | destructor Destroy; override;
|
---|
60 | published
|
---|
61 | { Published declarations }
|
---|
62 | property AutoSize;
|
---|
63 | property Align;
|
---|
64 | property Anchors;
|
---|
65 | property Angle: single Read FAngle Write SetAngle default 0;
|
---|
66 | property BorderWidth: integer Read FBorderWidth Write SetBorderWidth default 1;
|
---|
67 | property BorderOpacity: byte Read FBorderOpacity Write SetBorderOpacity default 255;
|
---|
68 | property BorderColor: TColor Read FBorderColor Write SetBorderColor;
|
---|
69 | property BorderGradient: TBCGradient Read FBorderGradient Write SetBorderGradient;
|
---|
70 | property BorderStyle: TPenStyle
|
---|
71 | Read FBorderStyle Write SetBorderStyle default psSolid;
|
---|
72 | property FillColor: TColor Read FFillColor Write SetFillColor;
|
---|
73 | property FillOpacity: byte Read FFillOpacity Write SetFillOpacity;
|
---|
74 | property FillGradient: TBCGradient Read FFillGradient Write SetFillGradient;
|
---|
75 | property SideCount: integer Read FSideCount Write SetSideCount default 4;
|
---|
76 | property RatioXY: single Read FRatioXY Write SetRatioXY default 1;
|
---|
77 | property UseRatioXY: boolean Read FUseRatioXY Write SetUseRatioXY default False;
|
---|
78 | property UseFillGradient: boolean Read FUseFillGradient
|
---|
79 | Write SetUseFillGradient default False;
|
---|
80 | property UseBorderGradient: boolean Read FUseBorderGradient
|
---|
81 | Write SetUseBorderGradient default False;
|
---|
82 | property ShapeType: TBGRAShapeType
|
---|
83 | Read FShapeType Write SetShapeType default stRegularPolygon;
|
---|
84 | property BorderSpacing;
|
---|
85 | property Caption;
|
---|
86 | property PopupMenu;
|
---|
87 | property RoundRadius: integer Read FRoundRadius Write SetRoundRadius default 0;
|
---|
88 | property Visible;
|
---|
89 |
|
---|
90 | property OnClick;
|
---|
91 | property OnDblClick;
|
---|
92 | property OnMouseDown;
|
---|
93 | property OnMouseEnter;
|
---|
94 | property OnMouseLeave;
|
---|
95 | property OnMouseMove;
|
---|
96 | property OnMouseUp;
|
---|
97 | end;
|
---|
98 |
|
---|
99 | procedure Register;
|
---|
100 |
|
---|
101 | implementation
|
---|
102 |
|
---|
103 | uses BCTools;
|
---|
104 |
|
---|
105 | procedure Register;
|
---|
106 | begin
|
---|
107 | {$I bgrashape_icon.lrs}
|
---|
108 | RegisterComponents('BGRA Controls', [TBGRAShape]);
|
---|
109 | end;
|
---|
110 |
|
---|
111 | { TBGRAShape }
|
---|
112 |
|
---|
113 | procedure TBGRAShape.SetBorderColor(const AValue: TColor);
|
---|
114 | begin
|
---|
115 | if FBorderColor = AValue then
|
---|
116 | exit;
|
---|
117 | FBorderColor := AValue;
|
---|
118 | Invalidate;
|
---|
119 | end;
|
---|
120 |
|
---|
121 | procedure TBGRAShape.SetBorderGradient(const AValue: TBCGradient);
|
---|
122 | begin
|
---|
123 | if FBorderGradient = AValue then
|
---|
124 | exit;
|
---|
125 | FBorderGradient.Assign(AValue);
|
---|
126 | Invalidate;
|
---|
127 | end;
|
---|
128 |
|
---|
129 | procedure TBGRAShape.SetAngle(const AValue: single);
|
---|
130 | begin
|
---|
131 | if FAngle = AValue then
|
---|
132 | exit;
|
---|
133 | FAngle := AValue;
|
---|
134 | Invalidate;
|
---|
135 | end;
|
---|
136 |
|
---|
137 | procedure TBGRAShape.SetBorderOpacity(const AValue: byte);
|
---|
138 | begin
|
---|
139 | if FBorderOpacity = AValue then
|
---|
140 | exit;
|
---|
141 | FBorderOpacity := AValue;
|
---|
142 | Invalidate;
|
---|
143 | end;
|
---|
144 |
|
---|
145 | procedure TBGRAShape.SetBorderStyle(const AValue: TPenStyle);
|
---|
146 | begin
|
---|
147 | if FBorderStyle = AValue then
|
---|
148 | exit;
|
---|
149 | FBorderStyle := AValue;
|
---|
150 | Invalidate;
|
---|
151 | end;
|
---|
152 |
|
---|
153 | procedure TBGRAShape.SetBorderWidth(AValue: integer);
|
---|
154 | begin
|
---|
155 | if AValue < 0 then
|
---|
156 | AValue := 0;
|
---|
157 | if FBorderWidth = AValue then
|
---|
158 | exit;
|
---|
159 | FBorderWidth := AValue;
|
---|
160 | Invalidate;
|
---|
161 | end;
|
---|
162 |
|
---|
163 | procedure TBGRAShape.SetFillColor(const AValue: TColor);
|
---|
164 | begin
|
---|
165 | if FFillColor = AValue then
|
---|
166 | exit;
|
---|
167 | FFillColor := AValue;
|
---|
168 | Invalidate;
|
---|
169 | end;
|
---|
170 |
|
---|
171 | procedure TBGRAShape.SetFillGradient(const AValue: TBCGradient);
|
---|
172 | begin
|
---|
173 | if FFillGradient = AValue then
|
---|
174 | exit;
|
---|
175 | FFillGradient.Assign(AValue);
|
---|
176 | Invalidate;
|
---|
177 | end;
|
---|
178 |
|
---|
179 | procedure TBGRAShape.SetFillOpacity(const AValue: byte);
|
---|
180 | begin
|
---|
181 | if FFillOpacity = AValue then
|
---|
182 | exit;
|
---|
183 | FFillOpacity := AValue;
|
---|
184 | Invalidate;
|
---|
185 | end;
|
---|
186 |
|
---|
187 | procedure TBGRAShape.SetRatioXY(const AValue: single);
|
---|
188 | begin
|
---|
189 | if FRatioXY = AValue then
|
---|
190 | exit;
|
---|
191 | FRatioXY := AValue;
|
---|
192 | Invalidate;
|
---|
193 | end;
|
---|
194 |
|
---|
195 | procedure TBGRAShape.SetRoundRadius(AValue: integer);
|
---|
196 | begin
|
---|
197 | if AValue < 0 then
|
---|
198 | AValue := 0;
|
---|
199 | if FRoundRadius = AValue then
|
---|
200 | exit;
|
---|
201 | FRoundRadius := AValue;
|
---|
202 | Invalidate;
|
---|
203 | end;
|
---|
204 |
|
---|
205 | procedure TBGRAShape.SetShapeType(const AValue: TBGRAShapeType);
|
---|
206 | begin
|
---|
207 | if FShapeType = AValue then
|
---|
208 | exit;
|
---|
209 | FShapeType := AValue;
|
---|
210 | Invalidate;
|
---|
211 | end;
|
---|
212 |
|
---|
213 | procedure TBGRAShape.SetSideCount(AValue: integer);
|
---|
214 | begin
|
---|
215 | if AValue < 3 then
|
---|
216 | AValue := 3;
|
---|
217 | if FSideCount = AValue then
|
---|
218 | exit;
|
---|
219 | FSideCount := AValue;
|
---|
220 | Invalidate;
|
---|
221 | end;
|
---|
222 |
|
---|
223 | procedure TBGRAShape.SetUseBorderGradient(const AValue: boolean);
|
---|
224 | begin
|
---|
225 | if FUseBorderGradient = AValue then
|
---|
226 | exit;
|
---|
227 | FUseBorderGradient := AValue;
|
---|
228 | Invalidate;
|
---|
229 | end;
|
---|
230 |
|
---|
231 | procedure TBGRAShape.SetUseFillGradient(const AValue: boolean);
|
---|
232 | begin
|
---|
233 | if FUseFillGradient = AValue then
|
---|
234 | exit;
|
---|
235 | FUseFillGradient := AValue;
|
---|
236 | Invalidate;
|
---|
237 | end;
|
---|
238 |
|
---|
239 | procedure TBGRAShape.SetUseRatioXY(const AValue: boolean);
|
---|
240 | begin
|
---|
241 | if FUseRatioXY = AValue then
|
---|
242 | exit;
|
---|
243 | FUseRatioXY := AValue;
|
---|
244 | Invalidate;
|
---|
245 | end;
|
---|
246 |
|
---|
247 | procedure TBGRAShape.Paint;
|
---|
248 | var
|
---|
249 | cx, cy, rx, ry, curRatio, a: single;
|
---|
250 | coords: array of TPointF;
|
---|
251 | minCoord, maxCoord: TPointF;
|
---|
252 | i: integer;
|
---|
253 | borderGrad, fillGrad: TBGRACustomScanner;
|
---|
254 | begin
|
---|
255 | FBGRA.FillTransparent;
|
---|
256 | FBGRA.PenStyle := FBorderStyle;
|
---|
257 | with FBGRA.Canvas2D do
|
---|
258 | begin
|
---|
259 | lineJoin := 'round';
|
---|
260 | if FUseBorderGradient then
|
---|
261 | begin
|
---|
262 | borderGrad := CreateGradient(FBorderGradient, Classes.rect(0, 0, Width, Height));
|
---|
263 | strokeStyle(borderGrad);
|
---|
264 | end
|
---|
265 | else
|
---|
266 | begin
|
---|
267 | borderGrad := nil;
|
---|
268 | strokeStyle(ColorToBGRA(ColorToRGB(FBorderColor), FBorderOpacity));
|
---|
269 | end;
|
---|
270 | lineStyle(FBGRA.CustomPenStyle);
|
---|
271 | lineWidth := FBorderWidth;
|
---|
272 | if FUseFillGradient then
|
---|
273 | begin
|
---|
274 | fillGrad := CreateGradient(FFillGradient, Classes.rect(0, 0, Width, Height));
|
---|
275 | fillStyle(fillGrad);
|
---|
276 | end
|
---|
277 | else
|
---|
278 | begin
|
---|
279 | fillGrad := nil;
|
---|
280 | fillStyle(ColorToBGRA(ColorToRGB(FFillColor), FFillOpacity));
|
---|
281 | end;
|
---|
282 | cx := Width / 2;
|
---|
283 | cy := Height / 2;
|
---|
284 | rx := (Width - FBorderWidth) / 2;
|
---|
285 | ry := (Height - FBorderWidth) / 2;
|
---|
286 | if FUseRatioXY and (ry <> 0) and (FRatioXY <> 0) then
|
---|
287 | begin
|
---|
288 | curRatio := rx / ry;
|
---|
289 | if FRatioXY > curRatio then
|
---|
290 | ry := ry / (FRatioXY / curRatio)
|
---|
291 | else
|
---|
292 | rx := rx / (curRatio / FRatioXY);
|
---|
293 | end;
|
---|
294 | if FShapeType = stRegularPolygon then
|
---|
295 | begin
|
---|
296 | setlength(coords, FSideCount);
|
---|
297 | for i := 0 to high(coords) do
|
---|
298 | begin
|
---|
299 | a := (i / FSideCount + FAngle / 360) * 2 * Pi;
|
---|
300 | coords[i] := PointF(sin(a), -cos(a));
|
---|
301 | end;
|
---|
302 | minCoord := coords[0];
|
---|
303 | maxCoord := coords[0];
|
---|
304 | for i := 1 to high(coords) do
|
---|
305 | begin
|
---|
306 | if coords[i].x < minCoord.x then
|
---|
307 | minCoord.x := coords[i].x;
|
---|
308 | if coords[i].y < minCoord.y then
|
---|
309 | minCoord.y := coords[i].y;
|
---|
310 | if coords[i].x > maxCoord.x then
|
---|
311 | maxCoord.x := coords[i].x;
|
---|
312 | if coords[i].y > maxCoord.y then
|
---|
313 | maxCoord.y := coords[i].y;
|
---|
314 | end;
|
---|
315 | for i := 0 to high(coords) do
|
---|
316 | begin
|
---|
317 | with (coords[i] - minCoord) do
|
---|
318 | coords[i] := PointF((x / (maxCoord.x - minCoord.x) - 0.5) *
|
---|
319 | 2 * rx + cx, (y / (maxCoord.y - minCoord.y) - 0.5) * 2 * ry + cy);
|
---|
320 | end;
|
---|
321 | beginPath;
|
---|
322 | for i := 0 to high(coords) do
|
---|
323 | begin
|
---|
324 | lineTo((coords[i] + coords[(i + 1) mod length(coords)]) * (1 / 2));
|
---|
325 | arcTo(coords[(i + 1) mod length(coords)], coords[(i + 2) mod
|
---|
326 | length(coords)], FRoundRadius);
|
---|
327 | end;
|
---|
328 | closePath;
|
---|
329 | end
|
---|
330 | else
|
---|
331 | begin
|
---|
332 | save;
|
---|
333 | translate(cx, cy);
|
---|
334 | scale(rx, ry);
|
---|
335 | beginPath;
|
---|
336 | arc(0, 0, 1, 0, 2 * Pi);
|
---|
337 | restore;
|
---|
338 | end;
|
---|
339 |
|
---|
340 | fill;
|
---|
341 | if FBorderWidth <> 0 then
|
---|
342 | stroke;
|
---|
343 |
|
---|
344 | fillStyle(BGRAWhite);
|
---|
345 | strokeStyle(BGRABlack);
|
---|
346 |
|
---|
347 | fillGrad.Free;
|
---|
348 | borderGrad.Free;
|
---|
349 | end;
|
---|
350 | FBGRA.Draw(Self.Canvas, 0, 0, False);
|
---|
351 | end;
|
---|
352 |
|
---|
353 | procedure TBGRAShape.Resize;
|
---|
354 | begin
|
---|
355 | if FBGRA <> nil then
|
---|
356 | FBGRA.SetSize(Width, Height);
|
---|
357 | inherited Resize;
|
---|
358 | end;
|
---|
359 |
|
---|
360 | constructor TBGRAShape.Create(AOwner: TComponent);
|
---|
361 | begin
|
---|
362 | inherited Create(AOwner);
|
---|
363 | with GetControlClassDefaultSize do
|
---|
364 | SetInitialBounds(0, 0, CX, CY);
|
---|
365 | FBGRA := TBGRABitmap.Create(Width, Height, BGRAPixelTransparent);
|
---|
366 |
|
---|
367 | FBorderColor := clWindowText;
|
---|
368 | FBorderOpacity := 255;
|
---|
369 | FBorderWidth := 1;
|
---|
370 | FBorderStyle := psSolid;
|
---|
371 | FBorderGradient := TBCGradient.Create(Self);
|
---|
372 | FBorderGradient.Point2XPercent := 100;
|
---|
373 | FBorderGradient.StartColor := clWhite;
|
---|
374 | FBorderGradient.EndColor := clBlack;
|
---|
375 |
|
---|
376 | FFillColor := clWindow;
|
---|
377 | FFillOpacity := 255;
|
---|
378 | FFillGradient := TBCGradient.Create(Self);
|
---|
379 |
|
---|
380 | FRoundRadius := 0;
|
---|
381 | FSideCount := 4;
|
---|
382 | FRatioXY := 1;
|
---|
383 | FUseRatioXY := False;
|
---|
384 | end;
|
---|
385 |
|
---|
386 | destructor TBGRAShape.Destroy;
|
---|
387 | begin
|
---|
388 | FBGRA.Free;
|
---|
389 | FFillGradient.Free;
|
---|
390 | FBorderGradient.Free;
|
---|
391 | inherited Destroy;
|
---|
392 | end;
|
---|
393 |
|
---|
394 | end.
|
---|