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