1 unit CustomDrawn_Android;
2 
3 {$mode objfpc}{$H+}
4 { $define CD_UseImageResources}
5 
6 interface
7 
8 uses
9   // RTL
10   Classes, SysUtils, Types, Math,
11   // fpimage
12   fpcanvas, fpimgcanv, fpimage,
13   // LCL -> Use only TForm, TWinControl, TCanvas and TLazIntfImage
14   Graphics, Controls, LCLType, LCLIntf, IntfGraphics, LResources, Forms,
15   //
16   customdrawndrawers, customdrawn_common;
17 
18 type
19 
20   { TCDDrawerAndroid }
21 
22   TCDDrawerAndroid = class(TCDDrawerCommon)
23   private
24     //bmpCheckbox, bmpCheckboxChecked: TBitmap;
25     // Alternative checkbox drawing, not currently utilized
26     procedure DrawCheckBoxBitmap(ADest: TFPCustomCanvas; ADestPos: TPoint; AState: TCDControlState; ASize: Integer; ABackgroundColor: TFPColor);
27     // Makes pixels in each corner transparent for a rounded effect
28     procedure DrawTransparentRoundCorners(ADest: TFPCustomCanvas; ADestPos: TPoint; ASize: TSize; AColor: TFPColor);
29     // Draws a vertical line with different first and last pixels
30     procedure DrawVerticalLineWithFirstLast(ADest: TFPCustomCanvas;
31       X, Y1, Y2: Integer; AColorTop, AColorMiddle, AColorEnd: TFPColor);
32     // Draws a line alternating between two colors
33     procedure DrawAndroidAlternatedHorzLine(ADest: TCanvas; X1, X2,
34       Y: Integer; AColor1, AColor2: TColor);
35     // Draws 2 mixed gradients which alternate between one another on each pixel
36     procedure DrawAndroidMixedVertGradientFill(ADest: TCanvas; ARect: TRect;
37       AStart1, AStop1, AStart2, AStop2: TColor);
38     // Fills a rectangular area alternating between two pixels
39     procedure DrawAndroidMixedFill(ADest: TCanvas; ARect: TRect; AColor1, AColor2: TColor);
40     // Draws a circle with a border and a gradient inside it
41     procedure DrawAndroidGradientCircle(ADest: TCanvas; ADestPos: TPoint; ASize: TSize; ABorderColor, ATopColor, ABottomColor: TColor);
42   public
43     procedure CreateResources; override;
44     procedure LoadResources; override;
45     procedure FreeResources; override;
46     //procedure LoadFallbackPaletteColors; override;
GetDrawStylenull47     function GetDrawStyle: TCDDrawStyle; override;
48     // General
GetMeasuresnull49     function GetMeasures(AMeasureID: Integer): Integer; override;
50 {    function GetMeasuresEx(ADest: TCanvas; AMeasureID: Integer;
51       AState: TCDControlState; AStateEx: TCDControlStateEx): Integer; virtual; abstract;
52     procedure CalculatePreferredSize(ADest: TCanvas; AControlId: TCDControlID;
53       AState: TCDControlState; AStateEx: TCDControlStateEx;
54       var PreferredWidth, PreferredHeight: integer; WithThemeSpace: Boolean); virtual; abstract;
55     function GetColor(AColorID: Integer): TColor; virtual; abstract;
56     function GetClientArea(ADest: TCanvas; ASize: TSize; AControlId: TCDControlID;
57       AState: TCDControlState; AStateEx: TCDControlStateEx): TRect; virtual; abstract;}
58     // General drawing routines
59     {procedure DrawFocusRect(ADest: TCanvas; ADestPos: TPoint; ASize: TSize); override;
60     procedure DrawRaisedFrame(ADest: TCanvas; ADestPos: TPoint; ASize: TSize); override;
61     procedure DrawSunkenFrame(ADest: TCanvas; ADestPos: TPoint; ASize: TSize); override;
62     procedure DrawShallowSunkenFrame(ADest: TCanvas; ADestPos: TPoint; ASize: TSize); override;}
63     procedure DrawTickmark(ADest: TFPCustomCanvas; ADestPos: TPoint; AState: TCDControlState); override;
64     {procedure DrawSlider(ADest: TCanvas; ADestPos: TPoint; ASize: TSize; AState: TCDControlState); override;
65     procedure DrawCompactArrow(ADest: TCanvas; ADestPos: TPoint; ADirection: TCDControlState); override;}
66     // ===================================
67     // Standard Tab
68     // ===================================
69     // TCDButton
70     procedure DrawButton(ADest: TFPCustomCanvas; ADestPos: TPoint; ASize: TSize;
71       AState: TCDControlState; AStateEx: TCDButtonStateEx); override;
72     // TCDEdit
73     procedure DrawEditBackground(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
74       AState: TCDControlState; AStateEx: TCDEditStateEx); override;
75     procedure DrawEditFrame(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
76       AState: TCDControlState; AStateEx: TCDEditStateEx); override;
77     // TCDCheckBox
78     procedure DrawCheckBoxSquare(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
79       AState: TCDControlState; AStateEx: TCDControlStateEx); override;
80     // TCDRadioButton
81     procedure DrawRadioButtonCircle(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
82       AState: TCDControlState; AStateEx: TCDControlStateEx); override;
83   end;
84 
85 implementation
86 
87 const
88   ANDROID_DPI = 'vldpi';
89 
90   // Actually Android buttons are much more complex then this,
91   // but this approximation works well
92   ANDROID_BUTTON_CORNERS = $006B696B;
93 
94   ANDROID_BUTTON_FIRST_LINE_A = $00F7F3F7;
95   ANDROID_BUTTON_FIRST_LINE_B = $00EFF3EF;
96   ANDROID_BUTTON_SECOND_LINE_A = $00EFF3EF;
97   ANDROID_BUTTON_SECOND_LINE_B = $00F7F3F7;
98   ANDROID_BUTTON_THIRD_LINE_A = $00EFEFEF;
99   ANDROID_BUTTON_THIRD_LINE_B = $00F7F3F7;
100 
101   ANDROID_BUTTON_TOP_GRADIENT_A = $00EFEFEF;
102   ANDROID_BUTTON_TOP_GRADIENT_B = $00EFEBEF;
103   ANDROID_BUTTON_MIDDLE_GRADIENT_A = $00CBCECB;
104   ANDROID_BUTTON_MIDDLE_GRADIENT_B = $00CECFCE;
105   ANDROID_BUTTON_BOTTOM_GRADIENT_A = $00BDBABD;
106   ANDROID_BUTTON_BOTTOM_GRADIENT_B = $00BABDBA;
107 
108   ANDROID_BUTTON_PREPRELAST_LINE_A = $00C6C3C6;
109   ANDROID_BUTTON_PREPRELAST_LINE_B = $00C6C3C6;
110   ANDROID_BUTTON_PRELAST_LINE_A = $00C6CBC6;
111   ANDROID_BUTTON_PRELAST_LINE_B = $00CECBCE;
112   ANDROID_BUTTON_LAST_LINE_A = $00D6D3D6;
113   ANDROID_BUTTON_LAST_LINE_B = $00D6D7D6;
114 
115   // Sunken variants
116 
117   ANDROID_BUTTON_SUNKEN_FIRST_LINE_A = $0066F366;
118   ANDROID_BUTTON_SUNKEN_FIRST_LINE_B = $0066F366;
119   ANDROID_BUTTON_SUNKEN_SECOND_LINE_A = $0066F366;
120   ANDROID_BUTTON_SUNKEN_SECOND_LINE_B = $0066F366;
121   ANDROID_BUTTON_SUNKEN_THIRD_LINE_A = $0066EF66;
122   ANDROID_BUTTON_SUNKEN_THIRD_LINE_B = $0066F366;
123 
124   ANDROID_BUTTON_SUNKEN_TOP_GRADIENT_A = $0066EF66;
125   ANDROID_BUTTON_SUNKEN_TOP_GRADIENT_B = $0066EB66;
126   ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_A = $0033CE33;
127   ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_B = $0033CF33;
128   ANDROID_BUTTON_SUNKEN_BOTTOM_GRADIENT_A = $0000BA00;
129   ANDROID_BUTTON_SUNKEN_BOTTOM_GRADIENT_B = $0000BD00;
130 
131   ANDROID_BUTTON_SUNKEN_PREPRELAST_LINE_A = $0000C300;
132   ANDROID_BUTTON_SUNKEN_PREPRELAST_LINE_B = $0000C300;
133   ANDROID_BUTTON_SUNKEN_PRELAST_LINE_A = $0000CB00;
134   ANDROID_BUTTON_SUNKEN_PRELAST_LINE_B = $0000CB00;
135   ANDROID_BUTTON_SUNKEN_LAST_LINE_A = $0000D300;
136   ANDROID_BUTTON_SUNKEN_LAST_LINE_B = $0000D700;
137 
138   // Checkbox
139 
140 var
141   ANDROID_CHECKBOX_A: array[0..29] of TColor =
142     ($F5F5F5, $EBF0EC, $EBF0EC, $EBEBEB, $EBEBEB,
143      $E1E6E2, $EBE6EA, $E1E1E1, $E1E1E1, $D6D0D7,
144      $E1DDE0, $CDCECD, $D6D3D5, $CDCECD, $CDCECD,
145      $C3C4C3, $CCC9CC, $C3C0C2, $C3C4C3, $BABFBB,
146      $C3C0C2, $BABFBB, $BABBBA, $AFB0AF, $AFACAF,
147      $AFACAF, $AFACAF, $AFB0AF, $BABDBA, $C3C4C3);
148   ANDROID_CHECKBOX_B: array[0..29] of TColor =
149     ($EBF0EC, $F5F0F4, $EBEBEB, $EBE6EA, $E1E6E2,
150      $EBE6EA, $E1E1E1, $D6DCD7, $D6DCD7, $D6DCD7,
151      $D6D7D6, $D5D3D6, $CDCECD, $CCC9CC, $C3C4C3,
152      $C3C4C3, $C3C0C2, $C3C0C2, $BABFBB, $BABBBA,
153      $BABBBA, $B9B6B9, $AFB6B1, $AFB0AF, $AFB0AF,
154      $AFB0AF, $AFB0AF, $AFB0AF, $BABDBA, $CCC9CC);
155 
156 const
157   ANDROID_CHECKBOX_CORNER_DARK_GRAY = $585A58;
158   ANDROID_CHECKBOX_CORNER_GRAY = $8A8C8A;
159 
160 {procedure TCDButtonDrawerAndroid.DrawToIntfImage(ADest: TFPImageCanvas;
161   CDButton: TCDButton);
162 begin
163 
164 end;
165 
166 procedure TCDButtonDrawerAndroid.DrawToCanvas(ADest: TCanvas; CDButton: TCDButton);
167 var
168   //TmpB: TBitmap;
169   Str: string;
170 begin
171   // Button shape -> This crashes in Gtk2
172 (*  TmpB.Canvas.Brush.Color := CDButton.Color;
173   TmpB.Canvas.Brush.Style := bsSolid;
174   TmpB.Canvas.RoundRect(0, 0, TmpB.Width, TmpB.Height, 8, 8);
175   CDButton.SetShape(TmpB);
176   ADest.Draw(0, 0, TmpB);
177   TmpB.Free;
178   *)
179 
180   ADest.Brush.Color := CDButton.Parent.Color;
181   ADest.Brush.Style := bsSolid;
182   ADest.Pen.Color := ADest.Brush.Color;
183   ADest.RecTangle(0, 0, CDButton.Width, CDButton.Height);
184 
185   // Button image
186   if CDButton.IsDown then
187     DrawCDButtonDown(ADest, CDButton.GetRGBBackgroundColor)
188   else if CDButton.Focused then
189     DrawAndroidButton(ADest, GetAColor(CDButton.Color, 98))
190   else
191     DrawAndroidButton(ADest, GetAColor(CDButton.Color, 96));
192 
193   // Button text
194   ADest.Font.Assign(CDButton.Font);
195   ADest.Brush.Style := bsClear;
196   ADest.Pen.Style := psSolid;
197   Str := CDButton.Caption;
198   ADest.TextOut((CDButton.Width - ADest.TextWidth(Str)) div 2,
199     (CDButton.Height - ADest.TextHeight(Str)) div 2, Str);
200 end;
201 
202 initialization
203   RegisterButtonDrawer(TCDButtonDrawerAndroid.Create, dsAndroid);}
204 
205 { TCDDrawerAndroid }
206 
207 procedure TCDDrawerAndroid.DrawCheckBoxBitmap(ADest: TFPCustomCanvas; ADestPos: TPoint; AState: TCDControlState; ASize: Integer; ABackgroundColor: TFPColor);
208 var
209   i, scaledI: Integer;
210   lDest: TCanvas;
211   lValue5, lValue7, lValue12, lValue17, lValue18, lValueSum24: Integer;
212 begin
213   lDest := TCanvas(ADest);
214   lValue5 := DPIAdjustment(5);
215   lValue7 := DPIAdjustment(7);
216   lValue12 := DPIAdjustment(12);
217   lValue18 := DPIAdjustment(18);
218   lValue17 := DPIAdjustment(17);
219   lValueSum24 := lValue7+lValue17;
220 
221   // Background
222   for i := 0 to ASize-1 do
223   begin
224     scaledI := Round(i * 30 / ASize);
225     DrawAndroidAlternatedHorzLine(lDest, 0, ASize-1, i, ANDROID_CHECKBOX_A[scaledI], ANDROID_CHECKBOX_B[scaledI]);
226   end;
227 
228 {  // Corners >>> The corners look bad if the background isn't black
229   ADest.Colors[ADestPos.X+0, ADestPos.Y+0] := colBlack;
230   ADest.Colors[ADestPos.X+1, ADestPos.Y+0] := colBlack;
231   ADest.Colors[ADestPos.X+0, ADestPos.Y+1] := colBlack;
232   lDest.Pixels[ADestPos.X+0, ADestPos.Y+2] := ANDROID_CHECKBOX_CORNER_DARK_GRAY;
233   lDest.Pixels[ADestPos.X+2, ADestPos.Y+0] := ANDROID_CHECKBOX_CORNER_DARK_GRAY;
234   lDest.Pixels[ADestPos.X+1, ADestPos.Y+1] := ANDROID_CHECKBOX_CORNER_GRAY;
235   //
236   ADest.Colors[ADestPos.X+ASize-1, ADestPos.Y+0] := colBlack;
237   ADest.Colors[ADestPos.X+ASize-2, ADestPos.Y+0] := colBlack;
238   ADest.Colors[ADestPos.X+ASize-1, ADestPos.Y+1] := colBlack;
239   lDest.Pixels[ADestPos.X+ASize-1, ADestPos.Y+2] := ANDROID_CHECKBOX_CORNER_DARK_GRAY;
240   lDest.Pixels[ADestPos.X+ASize-3, ADestPos.Y+0] := ANDROID_CHECKBOX_CORNER_DARK_GRAY;
241   lDest.Pixels[ADestPos.X+ASize-4, ADestPos.Y+1] := ANDROID_CHECKBOX_CORNER_GRAY;
242   //
243   ADest.Colors[ADestPos.X+0, ADestPos.Y+ASize-1] := colBlack;
244   ADest.Colors[ADestPos.X+1, ADestPos.Y+ASize-1] := colBlack;
245   ADest.Colors[ADestPos.X+0, ADestPos.Y+ASize-2] := colBlack;
246   lDest.Pixels[ADestPos.X+0, ADestPos.Y+ASize-3] := ANDROID_CHECKBOX_CORNER_DARK_GRAY;
247   lDest.Pixels[ADestPos.X+2, ADestPos.Y+ASize-1] := ANDROID_CHECKBOX_CORNER_DARK_GRAY;
248   lDest.Pixels[ADestPos.X+1, ADestPos.Y+ASize-2] := ANDROID_CHECKBOX_CORNER_GRAY;
249   //
250   ADest.Colors[ADestPos.X+ASize-1, ADestPos.Y+ASize-1] := colBlack;
251   ADest.Colors[ADestPos.X+ASize-2, ADestPos.Y+ASize-1] := colBlack;
252   ADest.Colors[ADestPos.X+ASize-1, ADestPos.Y+ASize-2] := colBlack;
253   lDest.Pixels[ADestPos.X+ASize-1, ADestPos.Y+ASize-3] := ANDROID_CHECKBOX_CORNER_DARK_GRAY;
254   lDest.Pixels[ADestPos.X+ASize-3, ADestPos.Y+ASize-1] := ANDROID_CHECKBOX_CORNER_DARK_GRAY;
255   lDest.Pixels[ADestPos.X+ASize-2, ADestPos.Y+ASize-2] := ANDROID_CHECKBOX_CORNER_GRAY;  }
256 
257   // Tickmark
258   if csfOff in AState then
259   begin
260     // first 6 descending lines
261     for i := 0 to lValue5 do
262       DrawVerticalLineWithFirstLast(ADest, lValue7+i, lValue12+i, lValue18+i,
263         TColorToFPColor($828081), TColorToFPColor($AFB0AF), TColorToFPColor($9D9E9D));
264     // now 11 ascending lines
265     for i := lValue5+1 to lValue17 do
266       DrawVerticalLineWithFirstLast(ADest, lValue7+i, lValue12+lValue5*2-i, lValue18+lValue5*2-i,
267         TColorToFPColor($939193), TColorToFPColor($AFB0AF), TColorToFPColor($9D9E9D));
268     // left part adjusts
269     lDest.Pixels[lValue7, lValue12] := $A6A7A6;
270     lDest.Pixels[lValue7-1, lValue12+1] := $828482;
271     lDest.Pixels[lValue7-2, lValue12+2] := $949193;
272     lDest.Pixels[lValue7-2, lValue12+3] := $9D9E9D;
273     lDest.Pixels[lValue7-2, lValue12+4] := $A6A7A6;
274     lDest.Pixels[lValue7-1, lValue12+2] := $A6A3A5;
275     lDest.Pixels[lValue7-1, lValue12+3] := $AFACAF;
276     lDest.Pixels[lValue7-1, lValue12+4] := $A6A7A6;
277     lDest.Pixels[lValue7-1, lValue12+5] := $9DA29E;
278     for i := 1 to lValue18 - lValue12 - 6 do
279     begin
280       lDest.Pixels[lValue7-2, lValue12+4+i] := $A6A7A6;
281       lDest.Pixels[lValue7-1, lValue12+5+i] := $9DA29E;
282     end;
283     // right part adjusts
284     lDest.Pixels[lValueSum24, lValue12-6] := $9D9A9C;
285     lDest.Pixels[lValueSum24, lValue12-5] := $AFBDAF;
286     lDest.Pixels[lValueSum24, lValue12-4] := $BABBBA;
287     lDest.Pixels[lValueSum24, lValue12-3] := $BABBBA;
288     lDest.Pixels[lValueSum24, lValue12-2] := $B9B6B9;
289     lDest.Pixels[lValueSum24, lValue12-1] := $9D9E9D;
290     lDest.Pixels[lValueSum24+1,  lValue12-6] := $AFB0AF;
291     lDest.Pixels[lValueSum24+1,  lValue12-5] := $A6A7A6;
292     lDest.Pixels[lValueSum24+1,  lValue12-4] := $B9B6B9;
293     lDest.Pixels[lValueSum24+1,  lValue12-3] := $BABBBA;
294     lDest.Pixels[lValueSum24+1,  lValue12-2] := $9D9E9D;
295     for i := 1 to lValue18 - lValue12 - 6 do
296     begin
297       lDest.Pixels[lValueSum24,  lValue12-6-i] := $9D9A9C;
298       lDest.Pixels[lValueSum24+1,  lValue12-6-i] := $AFB0AF;
299     end;
300   end
301   else
302   begin
303     // first 6 descending lines
304     for i := 0 to lValue5 do
305       DrawVerticalLineWithFirstLast(ADest, lValue7+i, lValue12+i, lValue18+i,
306         TColorToFPColor($007500), TColorToFPColor($00D300), TColorToFPColor($089A08));
307     // now 11 ascending lines
308     for i := lValue5+1 to lValue17 do
309       DrawVerticalLineWithFirstLast(ADest, lValue7+i, lValue12+lValue5*2-i, lValue18+lValue5*2-i,
310         TColorToFPColor($009200), TColorToFPColor($00D300), TColorToFPColor($089A08));
311     // left part adjusts
312     lDest.Pixels[lValue7, lValue12] := $849E84;
313     lDest.Pixels[lValue7-1, lValue12+1] := $187518;
314     lDest.Pixels[lValue7-2, lValue12+2] := $188A18;
315     lDest.Pixels[lValue7-2, lValue12+3] := $109E10;
316     lDest.Pixels[lValue7-2, lValue12+4] := $73A273;
317     lDest.Pixels[lValue7-1, lValue12+2] := $00A600;
318     lDest.Pixels[lValue7-1, lValue12+3] := $00BE00;
319     lDest.Pixels[lValue7-1, lValue12+4] := $00B200;
320     lDest.Pixels[lValue7-1, lValue12+5] := $4A9E4A;
321     for i := 1 to lValue18 - lValue12 - 6 do
322     begin
323       lDest.Pixels[lValue7-2, lValue12+4+i] := $73A273;
324       lDest.Pixels[lValue7-1, lValue12+5+i] := $4A9E4A;
325     end;
326     // right part adjusts
327     lDest.Pixels[lValueSum24, lValue12-6] := $427D42;
328     lDest.Pixels[lValueSum24, lValue12-5] := $00A200;
329     lDest.Pixels[lValueSum24, lValue12-4] := $00C700;
330     lDest.Pixels[lValueSum24, lValue12-3] := $00B200;
331     lDest.Pixels[lValueSum24, lValue12-2] := $31A231;
332     lDest.Pixels[lValueSum24, lValue12-1] := $089A08;
333     lDest.Pixels[lValueSum24+1,  lValue12-6] := $739E73;
334     lDest.Pixels[lValueSum24+1,  lValue12-5] := $009200;
335     lDest.Pixels[lValueSum24+1,  lValue12-4] := $00AA00;
336     lDest.Pixels[lValueSum24+1,  lValue12-3] := $4AA64A;
337     lDest.Pixels[lValueSum24+1,  lValue12-2] := $089A08;
338     for i := 1 to lValue18 - lValue12 - 6 do
339     begin
340       lDest.Pixels[lValueSum24,  lValue12-6-i] := $427D42;
341       lDest.Pixels[lValueSum24+1,  lValue12-6-i] := $739E73;
342     end;
343   end;
344 
345   DrawTransparentRoundCorners(ADest, ADestPos, Size(ASize, ASize), ABackgroundColor);
346 end;
347 
348 procedure TCDDrawerAndroid.DrawTransparentRoundCorners(ADest: TFPCustomCanvas;
349   ADestPos: TPoint; ASize: TSize; AColor: TFPColor);
350 begin
351   ADest.Colors[ADestPos.X+0, ADestPos.Y+0] := AColor;
352   ADest.Colors[ADestPos.X+1, ADestPos.Y+0] := AColor;
353   ADest.Colors[ADestPos.X+0, ADestPos.Y+1] := AColor;
354   ADest.Colors[ADestPos.X+ASize.cx-1, ADestPos.Y+0] := AColor;
355   ADest.Colors[ADestPos.X+ASize.cx-2, ADestPos.Y+0] := AColor;
356   ADest.Colors[ADestPos.X+ASize.cx-1, ADestPos.Y+1] := AColor;
357   ADest.Colors[ADestPos.X+0, ADestPos.Y+ASize.cy-1] := AColor;
358   ADest.Colors[ADestPos.X+1, ADestPos.Y+ASize.cy-1] := AColor;
359   ADest.Colors[ADestPos.X+0, ADestPos.Y+ASize.cy-2] := AColor;
360   ADest.Colors[ADestPos.X+ASize.cx-1, ADestPos.Y+ASize.cy-1] := AColor;
361   ADest.Colors[ADestPos.X+ASize.cx-2, ADestPos.Y+ASize.cy-1] := AColor;
362   ADest.Colors[ADestPos.X+ASize.cx-1, ADestPos.Y+ASize.cy-2] := AColor;
363 end;
364 
365 procedure TCDDrawerAndroid.DrawVerticalLineWithFirstLast(
366   ADest: TFPCustomCanvas; X, Y1, Y2: Integer; AColorTop, AColorMiddle,
367   AColorEnd: TFPColor);
368 begin
369   ADest.Colors[X, Y1] := AColorTop;
370   ADest.Pen.FPColor := AColorMiddle;
371   ADest.Pen.Style := psSolid;
372   ADest.Line(X, Y1+1, X, Y2);
373   ADest.Colors[X, Y2] := AColorEnd;
374 end;
375 
376 procedure TCDDrawerAndroid.DrawAndroidAlternatedHorzLine(ADest: TCanvas;
377   X1, X2, Y: Integer; AColor1, AColor2: TColor);
378 var
379   i: Integer;
380 begin
381   for i := X1 to X2-1 do
382   begin
383     if i mod 2 = 0 then ADest.Pixels[i, Y] := AColor1
384     else ADest.Pixels[i, Y] := AColor2;
385   end;
386 end;
387 
388 procedure TCDDrawerAndroid.DrawAndroidMixedVertGradientFill(ADest: TCanvas;
389   ARect: TRect; AStart1, AStop1, AStart2, AStop2: TColor);
390 var
391   RStart1, RStop1, RStart2, RStop2: Byte;
392   GStart1, GStop1, GStart2, GStop2: Byte;
393   BStart1, BStop1, BStart2, BStop2: Byte;
394   RDiff1, GDiff1, BDiff1: Integer;
395   RDiff2, GDiff2, BDiff2: Integer;
396   Count, I: Integer;
397   lColor1, lColor2: TColor;
398 begin
399   if IsRectEmpty(ARect) then Exit;
400 
401   RedGreenBlue(ColorToRGB(AStart1), RStart1, GStart1, BStart1);
402   RedGreenBlue(ColorToRGB(AStop1),  RStop1,  GStop1,  BStop1);
403   RedGreenBlue(ColorToRGB(AStart2), RStart2, GStart2, BStart2);
404   RedGreenBlue(ColorToRGB(AStop2),  RStop2,  GStop2,  BStop2);
405 
406   RDiff1 := RStop1 - RStart1;
407   GDiff1 := GStop1 - GStart1;
408   BDiff1 := BStop1 - BStart1;
409 
410   RDiff2 := RStop2 - RStart2;
411   GDiff2 := GStop2 - GStart2;
412   BDiff2 := BStop2 - BStart2;
413 
414   Count := ARect.Bottom - ARect.Top;
415 
416   for I := 0 to Count-1 do
417   begin
418     lColor1 := RGBToColor(RStart1 + (i * RDiff1) div Count,
419                             GStart1 + (i * GDiff1) div Count,
420                             BStart1 + (i * BDiff1) div Count);
421     lColor2 := RGBToColor(RStart2 + (i * RDiff2) div Count,
422                             GStart2 + (i * GDiff2) div Count,
423                             BStart2 + (i * BDiff2) div Count);
424 
425     // draw left to right, because LineTo does not draw last pixel
426     DrawAndroidAlternatedHorzLine(ADest, ARect.Left, ARect.Right, ARect.Top+I, lColor1, lColor2);
427   end;
428 end;
429 
430 procedure TCDDrawerAndroid.DrawAndroidMixedFill(ADest: TCanvas; ARect: TRect;
431   AColor1, AColor2: TColor);
432 var
433   I: Integer;
434   lColor1, lColor2: TColor;
435 begin
436   for I := 0 to (ARect.Bottom - ARect.Top)-1 do
437   begin
438     if i mod 2 = 0 then
439     begin
440       lColor1 := AColor1;
441       lColor2 := AColor2;
442     end
443     else
444     begin
445       lColor1 := AColor2;
446       lColor2 := AColor1;
447     end;
448     // draw left to right, because LineTo does not draw last pixel
449     DrawAndroidAlternatedHorzLine(ADest, ARect.Left, ARect.Right, ARect.Top+I, lColor1, lColor2);
450   end;
451 end;
452 
453 procedure TCDDrawerAndroid.DrawAndroidGradientCircle(ADest: TCanvas;
454   ADestPos: TPoint; ASize: TSize; ABorderColor, ATopColor, ABottomColor: TColor);
455 var
456   i, x, y, center_x, center_y, radius, Count: Integer;
457   RStart1, RStop1: Byte;
458   GStart1, GStop1: Byte;
459   BStart1, BStop1: Byte;
460   RDiff1, GDiff1, BDiff1: Integer;
461   lColor: TColor;
462 begin
463   center_x := ADestPos.X + ASize.cx div 2;
464   center_y := ADestPos.Y + ASize.cy div 2;
465   radius := ASize.cx div 2;
466   Count := ASize.cx;
467 
468   RedGreenBlue(ColorToRGB(ATopColor), RStart1, GStart1, BStart1);
469   RedGreenBlue(ColorToRGB(ABottomColor),  RStop1,  GStop1,  BStop1);
470 
471   RDiff1 := RStop1 - RStart1;
472   GDiff1 := GStop1 - GStart1;
473   BDiff1 := BStop1 - BStart1;
474 
475   // First the inside part
476   for x := ADestPos.X to ADestPos.X+ASize.CX-1 do
477     for y := ADestPos.Y to ADestPos.Y+ASize.CY-1 do
478     begin
479       if Sqr(x-center_x) + Sqr(y - center_y) < Sqr(radius) then
480       begin
481         i := Y - ADestPos.Y;
482         lColor := RGBToColor(RStart1 + (i * RDiff1) div Count,
483                              GStart1 + (i * GDiff1) div Count,
484                              BStart1 + (i * BDiff1) div Count);
485         ADest.Pixels[x, y] := lColor;
486       end;
487     end;
488 
489   // Now the border
490   ADest.Pen.Style := psSolid;
491   ADest.Pen.Color := ABorderColor;
492   ADest.Brush.Style := bsClear;
493   ADest.Ellipse(ADestPos.X, ADestPos.Y, ADestPos.X+ASize.CX, ADestPos.Y+ASize.CY);
494 end;
495 
496 procedure TCDDrawerAndroid.CreateResources;
497 begin
498 {  bmpCheckbox := TBitmap.Create;
499   bmpCheckboxChecked := TBitmap.Create;}
500 end;
501 
502 procedure TCDDrawerAndroid.LoadResources;
503 begin
504 (*  {$ifdef CD_UseImageResources}
505   bmpCheckbox.LoadFromLazarusResource('android_checkbox');
506   bmpCheckboxChecked.LoadFromLazarusResource('android_checkbox_checked');
507   {$else}
508   bmpCheckbox.Width := 30;
509   bmpCheckbox.Height := 30;
510   bmpCheckboxChecked.Width := 30;
511   bmpCheckboxChecked.Height := 30;
512   DrawCheckBoxBitmap(bmpCheckbox.Canvas, Point(0, 0), [csfOff], 30);
513   DrawCheckBoxBitmap(bmpCheckboxChecked.Canvas, Point(0, 0), [csfOn], 30);
514   {$endif}
515 
516   // DPI adjustment
517   lDPI := Max(96, Screen.PixelsPerInch);
518   ScaleRasterImage(bmpCheckbox, 160, lDPI);
519   ScaleRasterImage(bmpCheckboxChecked, 160, lDPI);*)
520 end;
521 
522 procedure TCDDrawerAndroid.FreeResources;
523 begin
524 {  bmpCheckbox.Free;
525   bmpCheckboxChecked.Free;}
526 end;
527 
TCDDrawerAndroid.GetDrawStylenull528 function TCDDrawerAndroid.GetDrawStyle: TCDDrawStyle;
529 begin
530   Result := dsAndroid;
531 end;
532 
GetMeasuresnull533 function TCDDrawerAndroid.GetMeasures(AMeasureID: Integer): Integer;
534 begin
535   Result := 0;
536   case AMeasureID of
537 {  TCDEDIT_LEFT_TEXT_SPACING: Result := 4;
538   TCDEDIT_RIGHT_TEXT_SPACING: Result := 3;
539   TCDEDIT_TOP_TEXT_SPACING: Result := 3;
540   TCDEDIT_BOTTOM_TEXT_SPACING: Result := 3;}
541   //
542   TCDCHECKBOX_SQUARE_HALF_HEIGHT: Floor(GetMeasures(TCDCHECKBOX_SQUARE_HEIGHT)/2);
543   TCDCHECKBOX_SQUARE_HEIGHT: Result := DPIAdjustment(30);
544   //
545   TCDRADIOBUTTON_CIRCLE_HEIGHT: Result := DPIAdjustment(20); // Must be dividable by 4
546   //
547   TCDCOMBOBOX_DEFAULT_HEIGHT: Result := 50;
548   //
549 {  TCDSCROLLBAR_BUTTON_WIDTH: Result := 17;
550   TCDSCROLLBAR_LEFT_SPACING: Result := 17;
551   TCDSCROLLBAR_RIGHT_SPACING: Result := 17;
552   TCDSCROLLBAR_LEFT_BUTTON_POS: Result := 0;
553   TCDSCROLLBAR_RIGHT_BUTTON_POS: Result := -17;
554   //
555   TCDTRACKBAR_LEFT_SPACING: Result := 9;
556   TCDTRACKBAR_RIGHT_SPACING: Result := 9;
557   TCDTRACKBAR_TOP_SPACING: Result := 5;
558   TCDTRACKBAR_FRAME_HEIGHT: Result := 17;
559   //
560   TCDLISTVIEW_COLUMN_LEFT_SPACING:  Result := 10;
561   TCDLISTVIEW_COLUMN_RIGHT_SPACING: Result := 10;
562   TCDLISTVIEW_COLUMN_TEXT_LEFT_SPACING:  Result := 5;
563   TCDLISTVIEW_LINE_TOP_SPACING: Result := 3;
564   TCDLISTVIEW_LINE_BOTTOM_SPACING: Result := 3;}
565   else
566     Result := inherited GetMeasures(AMeasureID);
567   end;
568 end;
569 
570 procedure TCDDrawerAndroid.DrawTickmark(ADest: TFPCustomCanvas; ADestPos: TPoint; AState: TCDControlState);
571 begin
572 
573 end;
574 
575 procedure TCDDrawerAndroid.DrawButton(ADest: TFPCustomCanvas; ADestPos: TPoint; ASize: TSize;
576   AState: TCDControlState; AStateEx: TCDButtonStateEx);
577 var
578   lDest: TCanvas absolute ADest;
579   Str: string;
580   lGlyphLeftSpacing: Integer = 0;
581   lTextOutPos: TPoint;
582   lGlyphCaptionHeight: Integer;
583   lRect: TRect;
584 begin
585   if not (ADest is TCanvas) then Exit; // ToDo
586 
587 {  // Darker corners >>> Don't draw them, they look bad in a light background
588   lColor := ANDROID_BUTTON_CORNERS;
589   lDest.Pixels[1, 1] := lColor;
590   lDest.Pixels[2, 0] := lColor;
591   lDest.Pixels[0, 2] := lColor;
592   lDest.Pixels[ASize.cx-3, 0] := lColor;
593   lDest.Pixels[ASize.cx-2, 1] := lColor;
594   lDest.Pixels[ASize.cx-1, 2] := lColor;
595   lDest.Pixels[0, ASize.cy-3] := lColor;
596   lDest.Pixels[1, ASize.cy-2] := lColor;
597   lDest.Pixels[2, ASize.cy-1] := lColor;
598   lDest.Pixels[ASize.cx-1, ASize.cy-3] := lColor;
599   lDest.Pixels[ASize.cx-2, ASize.cy-2] := lColor;
600   lDest.Pixels[ASize.cx-3, ASize.cy-1] := lColor; }
601 
602   // Button image
603   if csfSunken in AState then
604   begin
605     // Top lines
606     DrawAndroidAlternatedHorzLine(lDest, 0, ASize.cx, 0, ANDROID_BUTTON_SUNKEN_FIRST_LINE_A, ANDROID_BUTTON_SUNKEN_FIRST_LINE_B);
607     DrawAndroidAlternatedHorzLine(lDest, 0, ASize.cx, 1, ANDROID_BUTTON_SUNKEN_SECOND_LINE_A, ANDROID_BUTTON_SUNKEN_SECOND_LINE_B);
608     DrawAndroidAlternatedHorzLine(lDest, 0, ASize.cx, 2, ANDROID_BUTTON_SUNKEN_THIRD_LINE_A, ANDROID_BUTTON_SUNKEN_THIRD_LINE_B);
609 
610     // The central gradient
611     lRect := Bounds(0, 3, ASize.cx, (ASize.cy-6) div 3+1);
612     DrawAndroidMixedVertGradientFill(lDest, lRect, ANDROID_BUTTON_SUNKEN_TOP_GRADIENT_A,
613       ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_A, ANDROID_BUTTON_SUNKEN_TOP_GRADIENT_B, ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_B);
614     lRect := Bounds(0, 3+(ASize.cy-6) div 3, ASize.cx, (ASize.cy-6) div 3+1);
615     DrawAndroidMixedFill(lDest, lRect, ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_A, ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_B);
616     lRect := Bounds(0, 3+2*(ASize.cy-6) div 3, ASize.cx, (ASize.cy-6) div 3+1);
617     DrawAndroidMixedVertGradientFill(lDest, lRect, ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_A,
618       ANDROID_BUTTON_SUNKEN_BOTTOM_GRADIENT_A, ANDROID_BUTTON_SUNKEN_MIDDLE_GRADIENT_B, ANDROID_BUTTON_SUNKEN_BOTTOM_GRADIENT_B);
619 
620     // Bottom lines
621     DrawAndroidAlternatedHorzLine(lDest, 0, ASize.cx, ASize.cy-3, ANDROID_BUTTON_SUNKEN_PREPRELAST_LINE_A, ANDROID_BUTTON_SUNKEN_PREPRELAST_LINE_B);
622     DrawAndroidAlternatedHorzLine(lDest, 0, ASize.cx, ASize.cy-2, ANDROID_BUTTON_SUNKEN_PRELAST_LINE_A, ANDROID_BUTTON_SUNKEN_PRELAST_LINE_B);
623     DrawAndroidAlternatedHorzLine(lDest, 0, ASize.cx, ASize.cy-1, ANDROID_BUTTON_SUNKEN_LAST_LINE_A, ANDROID_BUTTON_SUNKEN_LAST_LINE_B);
624   end
625   else
626   begin
627     // Top lines
628     DrawAndroidAlternatedHorzLine(lDest, 0, ASize.cx, 0, ANDROID_BUTTON_FIRST_LINE_A, ANDROID_BUTTON_FIRST_LINE_B);
629     DrawAndroidAlternatedHorzLine(lDest, 0, ASize.cx, 1, ANDROID_BUTTON_SECOND_LINE_A, ANDROID_BUTTON_SECOND_LINE_B);
630     DrawAndroidAlternatedHorzLine(lDest, 0, ASize.cx, 2, ANDROID_BUTTON_THIRD_LINE_A, ANDROID_BUTTON_THIRD_LINE_B);
631 
632     // The central gradient
633     lRect := Bounds(0, 3, ASize.cx, (ASize.cy-6) div 3+1);
634     DrawAndroidMixedVertGradientFill(lDest, lRect, ANDROID_BUTTON_TOP_GRADIENT_A,
635       ANDROID_BUTTON_MIDDLE_GRADIENT_A, ANDROID_BUTTON_TOP_GRADIENT_B, ANDROID_BUTTON_MIDDLE_GRADIENT_B);
636     lRect := Bounds(0, 3+(ASize.cy-6) div 3, ASize.cx, (ASize.cy-6) div 3+1);
637     DrawAndroidMixedFill(lDest, lRect, ANDROID_BUTTON_MIDDLE_GRADIENT_A, ANDROID_BUTTON_MIDDLE_GRADIENT_B);
638     lRect := Bounds(0, 3+2*(ASize.cy-6) div 3, ASize.cx, (ASize.cy-6) div 3+1);
639     DrawAndroidMixedVertGradientFill(lDest, lRect, ANDROID_BUTTON_MIDDLE_GRADIENT_A,
640       ANDROID_BUTTON_BOTTOM_GRADIENT_A, ANDROID_BUTTON_MIDDLE_GRADIENT_B, ANDROID_BUTTON_BOTTOM_GRADIENT_B);
641 
642     // Bottom lines
643     DrawAndroidAlternatedHorzLine(lDest, 0, ASize.cx, ASize.cy-3, ANDROID_BUTTON_PREPRELAST_LINE_A, ANDROID_BUTTON_PREPRELAST_LINE_B);
644     DrawAndroidAlternatedHorzLine(lDest, 0, ASize.cx, ASize.cy-2, ANDROID_BUTTON_PRELAST_LINE_A, ANDROID_BUTTON_PRELAST_LINE_B);
645     DrawAndroidAlternatedHorzLine(lDest, 0, ASize.cx, ASize.cy-1, ANDROID_BUTTON_LAST_LINE_A, ANDROID_BUTTON_LAST_LINE_B);
646   end;
647 
648   // Background corners
649   DrawTransparentRoundCorners(ADest, Point(0, 0), ASize, AStateEx.FPParentRGBColor);
650 
651   // The full focus rect is too invasive for Android, just make a underline font style instead
652   //if csfHasFocus in AState then
653   //  DrawFocusRect(lDest, Point(5, 5), Size(ASize.cx-10, ASize.cy-10));
654 
655   // Position calculations
656   ADest.Font.Assign(AStateEx.Font);
657   if csfHasFocus in AState then
658     ADest.Font.Underline := True;
659   Str := AStateEx.Caption;
660   lGlyphCaptionHeight := Max(lDest.TextHeight(Str), AStateEx.Glyph.Height);
661   lTextOutPos.X := (ASize.cx - lDest.TextWidth(Str) - AStateEx.Glyph.Width) div 2;
662   lTextOutPos.Y := (ASize.cy - lGlyphCaptionHeight) div 2;
663   lTextOutPos.X := Max(lTextOutPos.X, 5);
664   lTextOutPos.Y := Max(lTextOutPos.Y, 5);
665 
666   // Button glyph
667   if not AStateEx.Glyph.Empty then
668   begin
669     lDest.Draw(lTextOutPos.X, lTextOutPos.Y, AStateEx.Glyph);
670     lGlyphLeftSpacing := AStateEx.Glyph.Width+5;
671   end;
672 
673   // Button text
674   lTextOutPos.X := lTextOutPos.X + lGlyphLeftSpacing;
675   lTextOutPos.Y := (ASize.cy - lDest.TextHeight(Str)) div 2;
676   ADest.Brush.Style := bsClear;
677   ADest.Pen.Style := psSolid;
678   if csfSunken in AState then
679   begin
680     Inc(lTextOutPos.X);
681     Inc(lTextOutPos.Y);
682   end;
683   lDest.TextOut(lTextOutPos.X, lTextOutPos.Y, Str)
684 end;
685 
686 procedure TCDDrawerAndroid.DrawEditBackground(ADest: TCanvas; ADestPos: TPoint;
687   ASize: TSize; AState: TCDControlState; AStateEx: TCDEditStateEx);
688 var
689   lRect: TRect;
690 begin
691   // The first half is a gradient
692   lRect := Bounds(3, 3, ASize.cx-5, (ASize.cy-5) div 2);
693   ADest.GradientFill(lRect, $D8DAD6, $F3F6F4, gdVertical);
694   // The second is a plain color
695   lRect := Bounds(3, 3+(ASize.cy-6) div 2, ASize.cx-6, (ASize.cy-5) div 2);
696   ADest.Brush.Color := $F3F6F4;
697   ADest.Brush.Style := bsSolid;
698   ADest.FillRect(lRect);
699 end;
700 
701 procedure TCDDrawerAndroid.DrawEditFrame(ADest: TCanvas; ADestPos: TPoint;
702   ASize: TSize; AState: TCDControlState; AStateEx: TCDEditStateEx);
703 begin
704   ADest.Pen.Style := psSolid;
705   if csfHasFocus in AState then
706   begin
707     // Top lines
708     ADest.Pen.Color := $6BB0FF;
709     ADest.Line(2, 0, ASize.cx-1, 0);
710     ADest.Pen.Color := $3E9FFE;
711     ADest.Line(1, 1, ASize.cx, 1);
712     ADest.Pen.Color := $2897FD;
713     ADest.Line(0, 2, ASize.cx+1, 2);
714     // Left&Right
715     ADest.Pen.Color := $007FFE;
716     ADest.Line(0, 3, 0, ASize.CY-2);
717     ADest.Line(1, 3, 1, ASize.CY-2);
718     ADest.Line(ASize.cx-1, 3, ASize.cx-1, ASize.CY-2);
719     ADest.Line(ASize.cx-2, 3, ASize.cx-2, ASize.CY-2);
720     ADest.Pen.Color := $96B1CA;
721     ADest.Line(2, 3, 2, ASize.CY-2);
722     ADest.Line(ASize.cx-3, 3, ASize.cx-3, ASize.CY-2);
723     // Bottom
724     ADest.Pen.Color := $0075FD;
725     ADest.Line(0, ASize.cy-3, ASize.cx-1, ASize.cy-3);
726     ADest.Pen.Color := $0079F6;
727     ADest.Line(1, ASize.cy-2, ASize.cx-2, ASize.cy-2);
728     ADest.Pen.Color := $007FFE;
729     ADest.Line(2, ASize.cy-1, ASize.cx-3, ASize.cy-1);
730   end
731   else
732   begin
733     // Top lines
734     ADest.Pen.Color := $737674;
735     ADest.Line(2, 0, ASize.cx-1, 0);
736     ADest.Pen.Color := $B6B9B7;
737     ADest.Line(1, 1, ASize.cx, 1);
738     ADest.Pen.Color := $C3C6C4;
739     ADest.Line(0, 2, ASize.cx+1, 2);
740     // Left&Right
741     ADest.Pen.Color := $565956;
742     ADest.Line(0, 3, 0, ASize.CY-2);
743     ADest.Line(ASize.cx-1, 3, ASize.cx-1, ASize.CY-2);
744     ADest.Pen.Color := $D1D4D1;
745     ADest.Line(1, 3, 1, ASize.CY-2);
746     ADest.Line(ASize.cx-2, 3, ASize.cx-2, ASize.CY-2);
747     ADest.Pen.Color := $DCE0DC;
748     ADest.Line(2, 3, 2, ASize.CY-2);
749     ADest.Line(ASize.cx-3, 3, ASize.cx-3, ASize.CY-2);
750     // Bottom
751     ADest.Pen.Color := $D4D7D5;
752     ADest.Line(0, ASize.cy-3, ASize.cx-1, ASize.cy-3);
753     ADest.Pen.Color := $D4D7D5;// is actually $FCFFFD but looks strange
754     ADest.Line(1, ASize.cy-2, ASize.cx-2, ASize.cy-2);
755     ADest.Pen.Color := $3B3E3C;
756     ADest.Line(2, ASize.cy-1, ASize.cx-3, ASize.cy-1);
757   end;
758 
759   // Transparent corners
760   DrawTransparentRoundCorners(ADest, ADestPos, ASize, AStateEx.FPParentRGBColor);
761 end;
762 
763 procedure TCDDrawerAndroid.DrawCheckBoxSquare(ADest: TCanvas; ADestPos: TPoint;
764   ASize: TSize; AState: TCDControlState; AStateEx: TCDControlStateEx);
765 var
766   lCheckboxSquare: Integer;
767 begin
768   lCheckboxSquare := GetMeasures(TCDCHECKBOX_SQUARE_HEIGHT);
769 
770   //if csfOn in AState then ADest.Draw(0, 0, bmpCheckboxChecked)
771   //else ADest.Draw(0, 0, bmpCheckbox);
772 
773   DrawCheckBoxBitmap(ADest, ADestPos, AState, lCheckboxSquare, AStateEx.FPParentRGBColor);
774 
775   // Transparent corners
776   DrawTransparentRoundCorners(ADest, ADestPos,
777     Size(lCheckboxSquare, lCheckboxSquare), AStateEx.FPParentRGBColor);
778 end;
779 
780 procedure TCDDrawerAndroid.DrawRadioButtonCircle(ADest: TCanvas;
781   ADestPos: TPoint; ASize: TSize; AState: TCDControlState;
782   AStateEx: TCDControlStateEx);
783 var
784   lSize: TSize;
785 begin
786   lSize.cx := GetMeasures(TCDRADIOBUTTON_CIRCLE_HEIGHT);
787   lSize.cy := lSize.cx;
788   // external circle
789   DrawAndroidGradientCircle(ADest, ADestPos, lSize, $848484, $EFEFEF, $BDBDBD);
790   // internal circle
791   if csfOn in AState then
792     DrawAndroidGradientCircle(ADest, Point(ADestPos.X+lSize.cx div 4, ADestPos.y+lSize.cy div 4),
793       Size(lSize.cx div 2, lSize.cy div 2), $317931, $21DB10, $00BE00)
794   else
795     DrawAndroidGradientCircle(ADest, Point(ADestPos.X+lSize.cx div 4, ADestPos.y+lSize.cy div 4),
796       Size(lSize.cx div 2, lSize.cy div 2), $9C9A9C, $CECECE, $BDBDBD);
797 end;
798 
799 initialization
800   {$ifdef CD_UseImageResources}
801   {$include customdrawnimages/android.lrs}
802   {$endif}
803   RegisterDrawer(TCDDrawerAndroid.Create, dsAndroid);
804 end.
805 
806