1 | { General framework methods for rendering background, borders, text, etc.
|
---|
2 |
|
---|
3 | Copyright (C) 2012 Krzysztof Dibowski dibowski at interia.pl
|
---|
4 |
|
---|
5 | This library is free software; you can redistribute it and/or modify it
|
---|
6 | under the terms of the GNU Library General Public License as published by
|
---|
7 | the Free Software Foundation; either version 2 of the License, or (at your
|
---|
8 | option) any later version with the following modification:
|
---|
9 |
|
---|
10 | As a special exception, the copyright holders of this library give you
|
---|
11 | permission to link this library with independent modules to produce an
|
---|
12 | executable, regardless of the license terms of these independent modules,and
|
---|
13 | to copy and distribute the resulting executable under terms of your choice,
|
---|
14 | provided that you also meet, for each linked independent module, the terms
|
---|
15 | and conditions of the license of that module. An independent module is a
|
---|
16 | module which is not derived from or based on this library. If you modify
|
---|
17 | this library, you may extend this exception to your version of the library,
|
---|
18 | but you are not obligated to do so. If you do not wish to do so, delete this
|
---|
19 | exception statement from your version.
|
---|
20 |
|
---|
21 | This program is distributed in the hope that it will be useful, but WITHOUT
|
---|
22 | ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
---|
23 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
|
---|
24 | for more details.
|
---|
25 |
|
---|
26 | You should have received a copy of the GNU Library General Public License
|
---|
27 | along with this library; if not, write to the Free Software Foundation,
|
---|
28 | Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
---|
29 | }
|
---|
30 |
|
---|
31 | unit BCTools;
|
---|
32 |
|
---|
33 | {$mode objfpc}{$H+}
|
---|
34 |
|
---|
35 | interface
|
---|
36 |
|
---|
37 | uses
|
---|
38 | Classes, SysUtils, Graphics, BGRABitmap, BGRABitmapTypes, bctypes,
|
---|
39 | Controls, BGRAGradientScanner;
|
---|
40 |
|
---|
41 | // This method prepare BGRABitmap for rendering BCFont type
|
---|
42 | procedure AssignBCFont(AFont: TBCFont; out ATargetBGRA: TBGRABitmap);
|
---|
43 | // Calculate text height and width (doesn't include wordwrap - just single line)
|
---|
44 | procedure CalculateTextSize(const AText: String; AFont: TBCFont;
|
---|
45 | out ANewWidth, ANewHeight: integer);
|
---|
46 | // As long as there are differences between the size of the font, this method is useless
|
---|
47 | procedure CalculateTextRect(const AText: String; AFont: TBCFont; out ARect: TRect);
|
---|
48 | // This method correct TRect to border width. As far as border width is bigger,
|
---|
49 | // BGRA drawing rectangle with offset (half border width)
|
---|
50 | procedure CalculateBorderRect(ABorder: TBCBorder; var ARect: TRect);
|
---|
51 | // Create BGRA Gradient Scanner based on BCGradient properties
|
---|
52 | function CreateGradient(AGradient: TBCGradient; ARect: TRect): TBGRAGradientScanner;
|
---|
53 | // Render arrow (used by BCButton with DropDownMenu style)
|
---|
54 | procedure RenderArrow(out ATargetBGRA: TBGRABitmap; const ARect: TRect;
|
---|
55 | ASize: Integer; ADirection: TBCArrowDirection; AColor: TColor = clBlack;
|
---|
56 | AOpacity: Byte = 255);
|
---|
57 | // Render customizable backgroud (used e.g. by TBCButton, TBCPanel, TBCLabel)
|
---|
58 | procedure RenderBackground(const ARect: TRect; const ABackground: TBCBackground;
|
---|
59 | out ATargetBGRA: TBGRABitmap; ARounding: TBCRounding = nil);
|
---|
60 | // Render customizable border (used e.g. by TBCButton, TBCPanel, TBCLabel)
|
---|
61 | procedure RenderBorder(const ARect: TRect; const ABorder: TBCBorder;
|
---|
62 | out ATargetBGRA: TBGRABitmap; ARounding: TBCRounding = nil);
|
---|
63 | // Render BCFont (used e.g. by TBCButton, TBCPanel, TBCLabel)
|
---|
64 | procedure RenderText(const ARect: TRect; const AFont: TBCFont;
|
---|
65 | const AText: String; out ATargetBGRA: TBGRABitmap);
|
---|
66 | // Return LCL horizontal equivalent for BCAlignment
|
---|
67 | function BCAlign2HAlign(AAlign: TBCAlignment): TAlignment;
|
---|
68 | // Return LCL vertical equivalent for BCAlignment
|
---|
69 | function BCAlign2VAlign(AAlign: TBCAlignment): TTextLayout;
|
---|
70 |
|
---|
71 | implementation
|
---|
72 |
|
---|
73 | uses Types, BGRAPolygon, BGRAFillInfo, BGRAText, math, LCLType, LCLIntf;
|
---|
74 |
|
---|
75 | procedure CalculateTextRect(const AText: String; AFont: TBCFont; out ARect: TRect);
|
---|
76 | var
|
---|
77 | tmp: TBGRABitmap;
|
---|
78 | flags: LongInt;
|
---|
79 | begin
|
---|
80 | tmp := TBGRABitmap.Create(0,0);
|
---|
81 | AssignBCFont(AFont,tmp);
|
---|
82 | flags := 0;
|
---|
83 | case AFont.TextAlignment of
|
---|
84 | bcaCenter, bcaCenterBottom, bcaCenterTop: flags := flags or DT_CENTER;
|
---|
85 | bcaRightCenter, bcaRightBottom, bcaRightTop: flags := flags or DT_RIGHT;
|
---|
86 | end;
|
---|
87 | case AFont.TextAlignment of
|
---|
88 | bcaLeftTop, bcaCenterTop, bcaRightTop: flags := flags or DT_TOP;
|
---|
89 | bcaLeftCenter, bcaCenter, bcaRightCenter: flags := flags or DT_VCENTER;
|
---|
90 | bcaLeftBottom, bcaCenterBottom, bcaRightBottom: flags := flags or DT_BOTTOM;
|
---|
91 | end;
|
---|
92 | if AFont.EndEllipsis then
|
---|
93 | flags := flags or DT_END_ELLIPSIS;
|
---|
94 | // This condition is from TCanvas.TextRect
|
---|
95 | if AFont.WordBreak then
|
---|
96 | begin
|
---|
97 | flags := flags or DT_WORDBREAK;
|
---|
98 | if AFont.EndEllipsis then
|
---|
99 | flags := flags and not DT_END_ELLIPSIS;
|
---|
100 | end;
|
---|
101 | if AFont.SingleLine then
|
---|
102 | flags := flags or DT_SINGLELINE;
|
---|
103 |
|
---|
104 | flags := flags or DT_CALCRECT;
|
---|
105 |
|
---|
106 | LCLIntf.DrawText(tmp.Canvas.Handle, PChar(AText), Length(AText), ARect, flags);
|
---|
107 |
|
---|
108 | tmp.Free;
|
---|
109 | end;
|
---|
110 |
|
---|
111 | procedure CalculateBorderRect(ABorder: TBCBorder; var ARect: TRect);
|
---|
112 | begin
|
---|
113 | if ABorder = nil then Exit;
|
---|
114 | Inc(ARect.Left, Round(ABorder.Width / 2));
|
---|
115 | Inc(ARect.Top, Round(ABorder.Width / 2));
|
---|
116 | Dec(ARect.Right, Round(ABorder.Width / 2) + 1);
|
---|
117 | Dec(ARect.Bottom, Round(ABorder.Width / 2) + 1);
|
---|
118 | end;
|
---|
119 |
|
---|
120 | function CreateGradient(AGradient: TBCGradient; ARect: TRect): TBGRAGradientScanner;
|
---|
121 | begin
|
---|
122 | Result := TBGRAGradientScanner.Create(
|
---|
123 | ColorToBGRA(ColorToRGB(AGradient.StartColor), AGradient.StartColorOpacity),
|
---|
124 | ColorToBGRA(ColorToRGB(AGradient.EndColor), AGradient.EndColorOpacity),
|
---|
125 | AGradient.GradientType, PointF(ARect.Left + Round(
|
---|
126 | ((ARect.Right - ARect.Left) / 100) * AGradient.Point1XPercent),
|
---|
127 | ARect.Top + Round(((ARect.Bottom - ARect.Top) / 100) * AGradient.Point1YPercent)),
|
---|
128 | PointF(ARect.Left + Round(((ARect.Right - ARect.Left) / 100) *
|
---|
129 | AGradient.Point2XPercent), ARect.Top + Round(
|
---|
130 | ((ARect.Bottom - ARect.Top) / 100) * AGradient.Point2YPercent)),
|
---|
131 | AGradient.ColorCorrection, AGradient.Sinus);
|
---|
132 | end;
|
---|
133 |
|
---|
134 | procedure RenderBorder(const ARect: TRect; const ABorder: TBCBorder; out
|
---|
135 | ATargetBGRA: TBGRABitmap; ARounding: TBCRounding = nil);
|
---|
136 | var
|
---|
137 | fiLight: TFillBorderRoundRectInfo;
|
---|
138 | rx,ry: Byte;
|
---|
139 | ropt: TRoundRectangleOptions;
|
---|
140 | begin
|
---|
141 | if ABorder.Style=bboNone then Exit;
|
---|
142 |
|
---|
143 | if ARounding = nil then
|
---|
144 | begin
|
---|
145 | rx := 0;
|
---|
146 | ry := 0;
|
---|
147 | ropt := [];
|
---|
148 | end else
|
---|
149 | begin
|
---|
150 | rx := ARounding.RoundX;
|
---|
151 | ry := ARounding.RoundY;
|
---|
152 | ropt := ARounding.RoundOptions;
|
---|
153 | end;
|
---|
154 |
|
---|
155 | ATargetBGRA.RoundRectAntialias(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom,
|
---|
156 | rx, ry, ColorToBGRA(ColorToRGB(ABorder.Color),ABorder.ColorOpacity),
|
---|
157 | ABorder.Width, ropt);
|
---|
158 |
|
---|
159 | if ABorder.LightWidth > 0 then
|
---|
160 | begin
|
---|
161 | //compute light position
|
---|
162 | fiLight := TFillBorderRoundRectInfo.Create(
|
---|
163 | ARect.Left, ARect.Top, ARect.Right, ARect.Bottom, rx,
|
---|
164 | ry, ABorder.Width + ABorder.LightWidth, ropt);
|
---|
165 | //check if there is an inner position
|
---|
166 | if fiLight.InnerBorder <> nil then
|
---|
167 | with fiLight.InnerBorder do //fill with light
|
---|
168 | ATargetBGRA.RoundRectAntialias(topleft.x, topleft.y, bottomright.x,
|
---|
169 | bottomright.y, radiusx, radiusY,
|
---|
170 | ColorToBGRA(ColorToRGB(ABorder.LightColor), ABorder.LightOpacity),
|
---|
171 | ABorder.LightWidth, ropt);
|
---|
172 | fiLight.Free;
|
---|
173 | end;
|
---|
174 | end;
|
---|
175 |
|
---|
176 | procedure RenderText(const ARect: TRect; const AFont: TBCFont;
|
---|
177 | const AText: String; out ATargetBGRA: TBGRABitmap);
|
---|
178 | var
|
---|
179 | shd: TBGRABitmap;
|
---|
180 | hal: TAlignment;
|
---|
181 | val: TTextLayout;
|
---|
182 | st: TTextStyle;
|
---|
183 | begin
|
---|
184 | AssignBCFont(AFont,ATargetBGRA);
|
---|
185 |
|
---|
186 | hal := BCAlign2HAlign(AFont.TextAlignment);
|
---|
187 | val := BCAlign2VAlign(AFont.TextAlignment);
|
---|
188 |
|
---|
189 | FillChar(st, SizeOf(st),0);
|
---|
190 |
|
---|
191 | st.Wordbreak := AFont.WordBreak;
|
---|
192 | st.Alignment := hal;
|
---|
193 | st.Layout := val;
|
---|
194 | st.SingleLine := AFont.SingleLine;
|
---|
195 | st.EndEllipsis := AFont.EndEllipsis;
|
---|
196 |
|
---|
197 | if AFont.Shadow then
|
---|
198 | begin
|
---|
199 | shd := TBGRABitmap.Create(ATargetBGRA.Width,ATargetBGRA.Height,BGRAPixelTransparent);
|
---|
200 | shd.FontName := ATargetBGRA.FontName;
|
---|
201 | shd.FontStyle := ATargetBGRA.FontStyle;
|
---|
202 | shd.FontQuality := ATargetBGRA.FontQuality;
|
---|
203 | shd.FontHeight := ATargetBGRA.FontHeight;
|
---|
204 | shd.TextRect(ARect, ARect.Left, ARect.Top, AText, st, ColorToBGRA(ColorToRGB(AFont.ShadowColor),
|
---|
205 | AFont.ShadowColorOpacity));
|
---|
206 | BGRAReplace(shd, shd.FilterBlurRadial(AFont.ShadowRadius, rbFast));
|
---|
207 | ATargetBGRA.PutImage(AFont.ShadowOffsetX, AFont.ShadowOffsetY,
|
---|
208 | shd, dmDrawWithTransparency);
|
---|
209 | shd.Free;
|
---|
210 | end;
|
---|
211 |
|
---|
212 | ATargetBGRA.TextRect(ARect,ARect.Left,ARect.Top,AText,st,ColorToBGRA(ColorToRGB(AFont.Color)));
|
---|
213 |
|
---|
214 | end;
|
---|
215 |
|
---|
216 | function BCAlign2HAlign(AAlign: TBCAlignment): TAlignment;
|
---|
217 | begin
|
---|
218 | if AAlign in [bcaCenter, bcaCenterTop, bcaCenterBottom] then
|
---|
219 | Result := taCenter
|
---|
220 | else if AAlign in [bcaRightCenter, bcaRightTop, bcaRightBottom] then
|
---|
221 | Result := taRightJustify
|
---|
222 | else
|
---|
223 | Result := taLeftJustify;
|
---|
224 | end;
|
---|
225 |
|
---|
226 | function BCAlign2VAlign(AAlign: TBCAlignment): TTextLayout;
|
---|
227 | begin
|
---|
228 | if AAlign in [bcaCenter, bcaLeftCenter, bcaRightCenter] then
|
---|
229 | Result := tlCenter
|
---|
230 | else if AAlign in [bcaCenterBottom, bcaLeftBottom, bcaRightBottom] then
|
---|
231 | Result := tlBottom
|
---|
232 | else
|
---|
233 | Result := tlTop;
|
---|
234 | end;
|
---|
235 |
|
---|
236 | procedure AssignBCFont(AFont: TBCFont; out ATargetBGRA: TBGRABitmap);
|
---|
237 | var c: TBitmap;
|
---|
238 | begin
|
---|
239 | // Canvas is need for calculate font height
|
---|
240 | c := TBitmap.Create;
|
---|
241 | c.Canvas.Font.Name := AFont.Name;
|
---|
242 | c.Canvas.Font.Style := AFont.Style;
|
---|
243 | case AFont.FontQuality of
|
---|
244 | fqSystem: c.Canvas.Font.Quality := fqNonAntialiased;
|
---|
245 | fqFineAntialiasing: c.Canvas.Font.Quality := fqAntialiased;
|
---|
246 | fqFineClearTypeRGB: c.Canvas.Font.Quality := fqProof;
|
---|
247 | fqSystemClearType: c.Canvas.Font.Quality := fqCleartype;
|
---|
248 | end;
|
---|
249 | // FontAntialias is only backward compability for FontQuality property.
|
---|
250 | // FontQuality is published in TBCFont so we don't need FontAntialias anymore.
|
---|
251 | //ATargetBGRA.FontAntialias := AFont.FontAntialias;
|
---|
252 | ATargetBGRA.FontStyle := AFont.Style;
|
---|
253 |
|
---|
254 | // If font quality is system, then we can leave default values. LCL will
|
---|
255 | // handle everything (when name is "default" or height 0)
|
---|
256 | if AFont.FontQuality in [fqSystem,fqSystemClearType] then
|
---|
257 | begin
|
---|
258 | ATargetBGRA.FontName := AFont.Name;
|
---|
259 | ATargetBGRA.FontHeight := AFont.Height;
|
---|
260 | end
|
---|
261 | else
|
---|
262 | begin
|
---|
263 | // Getting real font name
|
---|
264 | if SameText(AFont.Name,'default')
|
---|
265 | then ATargetBGRA.FontName := GetFontData(c.Canvas.Font.Handle).Name
|
---|
266 | else ATargetBGRA.FontName := AFont.Name;
|
---|
267 |
|
---|
268 | // Calculate default height, because when font quality is <> fqSystemXXX
|
---|
269 | // then if height is 0 then it is 0 for real
|
---|
270 | if (AFont.Height=0) then
|
---|
271 | ATargetBGRA.FontHeight := -c.Canvas.TextHeight('Bgra')
|
---|
272 | else
|
---|
273 | ATargetBGRA.FontHeight := AFont.Height;
|
---|
274 | end;
|
---|
275 | ATargetBGRA.FontQuality := AFont.FontQuality;
|
---|
276 | c.Free;
|
---|
277 | end;
|
---|
278 |
|
---|
279 | procedure CalculateTextSize(const AText: String; AFont: TBCFont; out ANewWidth,
|
---|
280 | ANewHeight: integer);
|
---|
281 | var
|
---|
282 | s: TSize;
|
---|
283 | tmp: TBGRABitmap;
|
---|
284 | begin
|
---|
285 | if (AText = '') or (AFont = nil) then
|
---|
286 | begin
|
---|
287 | ANewWidth := 0;
|
---|
288 | ANewHeight := 0;
|
---|
289 | Exit;
|
---|
290 | end;
|
---|
291 |
|
---|
292 | {TODO: Check why BGRATextSize doesn't work. BGRABitmap call this method
|
---|
293 | and it work. Temporary I'm creating temp bitmap
|
---|
294 | }
|
---|
295 | {s := BGRAText.BGRATextSize(AFont,AFont.FontQuality,AText,FontAntialiasingLevel);
|
---|
296 | if (s.cy >= 24) and AFont.FontAntialias then
|
---|
297 | s := BGRAText.BGRATextSize(AFont,AFont.FontQuality,AText,4);}
|
---|
298 | tmp := TBGRABitmap.Create(0,0);
|
---|
299 | AssignBCFont(AFont, tmp);
|
---|
300 |
|
---|
301 | s := tmp.TextSize(AText);
|
---|
302 | tmp.Free;
|
---|
303 |
|
---|
304 | { shadow offset }
|
---|
305 | if AFont.Shadow then
|
---|
306 | begin
|
---|
307 | Inc(s.cx, 2 * Abs(AFont.ShadowOffsetX) + 2 * AFont.ShadowRadius);
|
---|
308 | Inc(s.cy, 2 * Abs(AFont.ShadowOffsetY) + 2 * AFont.ShadowRadius);
|
---|
309 | end;
|
---|
310 |
|
---|
311 | ANewWidth := s.cx;
|
---|
312 | ANewHeight := s.cy;
|
---|
313 | end;
|
---|
314 |
|
---|
315 | procedure RenderArrow(out ATargetBGRA: TBGRABitmap; const ARect: TRect;
|
---|
316 | ASize: Integer; ADirection: TBCArrowDirection; AColor: TColor; AOpacity: Byte);
|
---|
317 | var
|
---|
318 | p: ArrayOfTPointF;
|
---|
319 | n: byte;
|
---|
320 | temp: TBGRABitmap;
|
---|
321 | w: Integer;
|
---|
322 | begin
|
---|
323 | // We can't draw outside rect
|
---|
324 | w := Min(ASize, ARect.Right - ARect.Left);
|
---|
325 |
|
---|
326 | { Poly }
|
---|
327 | SetLength(p, 3);
|
---|
328 |
|
---|
329 | temp := TBGRABitmap.Create(w+1, w+1,BGRAPixelTransparent);
|
---|
330 |
|
---|
331 | case ADirection of
|
---|
332 | badDown:
|
---|
333 | begin;
|
---|
334 | p[0].x := 0;
|
---|
335 | p[0].y := 0;
|
---|
336 |
|
---|
337 | p[1].x := w;
|
---|
338 | p[1].y := 0;
|
---|
339 |
|
---|
340 | p[2].x := Round(w/2);
|
---|
341 | p[2].y := w;
|
---|
342 | end;
|
---|
343 | badUp:
|
---|
344 | begin
|
---|
345 | p[0].x := Round(w/2);
|
---|
346 | p[0].y := 0;
|
---|
347 |
|
---|
348 | p[1].x := 0;
|
---|
349 | p[1].y := w;
|
---|
350 |
|
---|
351 | p[2].x := w;
|
---|
352 | p[2].y := w;
|
---|
353 | end;
|
---|
354 | badLeft:
|
---|
355 | begin
|
---|
356 | p[0].x := 0;
|
---|
357 | p[0].y := Round(w/2);
|
---|
358 |
|
---|
359 | p[1].x := w;
|
---|
360 | p[1].y := 0;
|
---|
361 |
|
---|
362 | p[2].x := w;
|
---|
363 | p[2].y := w;
|
---|
364 | end;
|
---|
365 | badRight:
|
---|
366 | begin
|
---|
367 | p[0].x := w;
|
---|
368 | p[0].y := Round(w/2);
|
---|
369 |
|
---|
370 | p[1].x := 0;
|
---|
371 | p[1].y := 0;
|
---|
372 |
|
---|
373 | p[2].x := 0;
|
---|
374 | p[2].y := w;
|
---|
375 | end;
|
---|
376 | end;
|
---|
377 |
|
---|
378 | // Fill n times to get best quality
|
---|
379 | for n := 1 to 6 do
|
---|
380 | temp.FillPolyAntialias(p, ColorToBGRA(ColorToRGB(AColor),AOpacity));
|
---|
381 |
|
---|
382 | ATargetBGRA.PutImage(
|
---|
383 | ARect.Right-Round( ((ARect.Right-ARect.Left)/2) + (w/2) ),
|
---|
384 | ARect.Bottom-Round( ((ARect.Bottom-ARect.Top)/2) + (w/2) ),
|
---|
385 | temp,
|
---|
386 | dmDrawWithTransparency
|
---|
387 | );
|
---|
388 | temp.Free;
|
---|
389 | end;
|
---|
390 |
|
---|
391 | procedure RenderBackground(const ARect: TRect; const ABackground: TBCBackground; out
|
---|
392 | ATargetBGRA: TBGRABitmap; ARounding: TBCRounding = nil);
|
---|
393 | var
|
---|
394 | backcolor: TBGRAPixel;
|
---|
395 | multi: TBGRAMultishapeFiller;
|
---|
396 | back: TBGRABitmap;
|
---|
397 | grect1, grect2: TRect;
|
---|
398 | gra: TBGRAGradientScanner;
|
---|
399 | fiLight: TFillBorderRoundRectInfo;
|
---|
400 | rx,ry: Byte;
|
---|
401 | ropt: TRoundRectangleOptions;
|
---|
402 | begin
|
---|
403 |
|
---|
404 | if ARounding = nil then
|
---|
405 | begin
|
---|
406 | rx := 0;
|
---|
407 | ry := 0;
|
---|
408 | ropt := [];
|
---|
409 | end else
|
---|
410 | begin
|
---|
411 | rx := ARounding.RoundX;
|
---|
412 | ry := ARounding.RoundY;
|
---|
413 | ropt := ARounding.RoundOptions;
|
---|
414 | end;
|
---|
415 |
|
---|
416 | { Background color }
|
---|
417 | case ABackground.Style of
|
---|
418 | bbsClear: backcolor := BGRAPixelTransparent;
|
---|
419 | // TODO: Why if I use some system colors like clBtnFace, clActiveCaption etc.
|
---|
420 | // without ColorToRGB, I always get Black? Interface: QT
|
---|
421 | bbsColor: backcolor := ColorToBGRA(ColorToRGB(ABackground.Color), ABackground.ColorOpacity);
|
---|
422 | end;
|
---|
423 |
|
---|
424 | case ABackground.Style of
|
---|
425 | bbsClear, bbsColor:
|
---|
426 | { Solid background color }
|
---|
427 | ATargetBGRA.FillRoundRectAntialias(ARect.Left, ARect.Top, ARect.Right,
|
---|
428 | ARect.Bottom, rx, ry, backcolor, ropt);
|
---|
429 | bbsGradient:
|
---|
430 | begin
|
---|
431 | { Using multishape filler to merge background gradient and border }
|
---|
432 | multi := TBGRAMultishapeFiller.Create;
|
---|
433 | multi.PolygonOrder := poFirstOnTop; { Border will replace background }
|
---|
434 |
|
---|
435 | { Gradients }
|
---|
436 | back := TBGRABitmap.Create(ATargetBGRA.Width, ATargetBGRA.Height, BGRAPixelTransparent);
|
---|
437 | grect1 := ARect;
|
---|
438 | grect2 := ARect;
|
---|
439 | { Gradient 1 }
|
---|
440 | if ABackground.Gradient1EndPercent > 0 then
|
---|
441 | begin
|
---|
442 | grect1.Bottom := Round((grect1.Bottom / 100) * ABackground.Gradient1EndPercent);
|
---|
443 | gra := CreateGradient(ABackground.Gradient1, grect1);
|
---|
444 | back.FillRect(grect1.Left, grect1.Top, grect1.Right, grect1.Bottom,
|
---|
445 | gra, dmSet
|
---|
446 | );
|
---|
447 | gra.Free;
|
---|
448 | end;
|
---|
449 | { Gradient 2 }
|
---|
450 | if ABackground.Gradient1EndPercent < 100 then
|
---|
451 | begin
|
---|
452 | if grect1.Bottom < ARect.Bottom then
|
---|
453 | grect2.Top := grect1.Bottom - 1;
|
---|
454 | gra := CreateGradient(ABackground.Gradient2, grect2);
|
---|
455 | back.FillRect(grect2.Left, grect2.Top, grect2.Right, grect2.Bottom,
|
---|
456 | gra, dmSet
|
---|
457 | );
|
---|
458 | gra.Free;
|
---|
459 | end;
|
---|
460 |
|
---|
461 | multi.AddRoundRectangle(ARect.Left, ARect.Top, ARect.Right, ARect.Bottom,
|
---|
462 | rx, ry, back, ropt);
|
---|
463 |
|
---|
464 | multi.Draw(ATargetBGRA);
|
---|
465 | multi.Free;
|
---|
466 | back.Free;
|
---|
467 | end;
|
---|
468 | end;
|
---|
469 | end;
|
---|
470 |
|
---|
471 | end.
|
---|
472 |
|
---|