1 unit CustomDrawn_Common;
2 
3 {$mode objfpc}{$H+}
4 
5 interface
6 
7 uses
8   // RTL / FCL
9   Classes, SysUtils, Types, Math, fpcanvas, fpimage,
10   // LazUtils
11   lazutf8,
12   // LCL -> Use only TForm, TWinControl, TCanvas and TLazIntfImage
13   Graphics, Controls, LCLType,
14   // Others only for types
15   StdCtrls, ComCtrls, Forms,
16   //
17   customdrawndrawers, ExtCtrls;
18 
19 type
20 
21   { TCDDrawerCommon }
22 
23   TCDDrawerCommon = class(TCDDrawer)
24   public
PalDefaultUsesNativePalettenull25     function  PalDefaultUsesNativePalette: Boolean; override;
26     procedure LoadFallbackPaletteColors; override;
27     // General
GetMeasuresnull28     function GetMeasures(AMeasureID: Integer): Integer; override;
GetMeasuresExnull29     function GetMeasuresEx(ADest: TCanvas; AMeasureID: Integer;
30       AState: TCDControlState; AStateEx: TCDControlStateEx): Integer; override;
31     procedure CalculatePreferredSize(ADest: TCanvas; AControlId: TCDControlID;
32       AState: TCDControlState; AStateEx: TCDControlStateEx;
33       var PreferredWidth, PreferredHeight: integer; WithThemeSpace, AAllowUseOfMeasuresEx: Boolean); override;
GetColornull34     function GetColor(AColorID: Integer): TColor; override;
GetClientAreanull35     function GetClientArea(ADest: TCanvas; ASize: TSize; AControlId: TCDControlID;
36       AState: TCDControlState; AStateEx: TCDControlStateEx): TRect; override;
DPIAdjustmentnull37     function DPIAdjustment(const AValue: Integer): Integer;
38     // General drawing routines
39     procedure DrawFocusRect(ADest: TFPCustomCanvas; ADestPos: TPoint; ASize: TSize); override;
40     procedure DrawRaisedFrame(ADest: TCanvas; ADestPos: TPoint; ASize: TSize); override;
41     procedure DrawFrame3D(ADest: TFPCustomCanvas; ADestPos: TPoint; ASize: TSize;
42       const FrameWidth : integer; const Style : TBevelCut); override;
43     procedure DrawSunkenFrame(ADest: TCanvas; ADestPos: TPoint; ASize: TSize); override;
44     procedure DrawShallowSunkenFrame(ADest: TCanvas; ADestPos: TPoint; ASize: TSize); override;
45     procedure DrawTickmark(ADest: TFPCustomCanvas; ADestPos: TPoint; AState: TCDControlState); override;
46     procedure DrawSlider(ADest: TCanvas; ADestPos: TPoint; ASize: TSize; AState: TCDControlState); override;
47     procedure DrawArrow(ADest: TCanvas; ADestPos: TPoint; ADirection: TCDControlState; ASize: Integer = 7); override;
48     // Extra buttons drawing routines
49     procedure DrawSmallCloseButton(ADest: TCanvas; ADestPos: TPoint); override;
50     procedure DrawButtonWithArrow(ADest: TCanvas; ADestPos: TPoint; ASize: TSize; AState: TCDControlState); override;
51     // TCDControl
52     procedure DrawControl(ADest: TCanvas; ASize: TSize;
53       AState: TCDControlState; AStateEx: TCDControlStateEx); override;
54     // ===================================
55     // Standard Tab
56     // ===================================
57     // TCDButton
58     procedure DrawButton(ADest: TFPCustomCanvas; ADestPos: TPoint; ASize: TSize;
59       AState: TCDControlState; AStateEx: TCDButtonStateEx); override;
60     // TCDEdit
61     procedure DrawEditBackground(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
62       AState: TCDControlState; AStateEx: TCDEditStateEx); override;
63     procedure DrawEditFrame(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
64       AState: TCDControlState; AStateEx: TCDEditStateEx); override;
65     procedure DrawCaret(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
66       AState: TCDControlState; AStateEx: TCDEditStateEx); override;
67     procedure DrawEdit(ADest: TCanvas; ASize: TSize;
68       AState: TCDControlState; AStateEx: TCDEditStateEx); override;
69     // TCDCheckBox
70     procedure DrawCheckBoxSquare(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
71       AState: TCDControlState; AStateEx: TCDControlStateEx); override;
72     procedure DrawCheckBox(ADest: TCanvas; ASize: TSize;
73       AState: TCDControlState; AStateEx: TCDControlStateEx); override;
74     // TCDRadioButton
75     procedure DrawRadioButtonCircle(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
76       AState: TCDControlState; AStateEx: TCDControlStateEx); override;
77     procedure DrawRadioButton(ADest: TCanvas; ASize: TSize;
78       AState: TCDControlState; AStateEx: TCDControlStateEx); override;
79     // TCDComboBox
80     procedure DrawComboBox(ADest: TCanvas; ASize: TSize;
81       AState: TCDControlState; AStateEx: TCDEditStateEx); override;
82     // TCDScrollBar
83     procedure DrawScrollBar(ADest: TCanvas; ASize: TSize;
84       AState: TCDControlState; AStateEx: TCDPositionedCStateEx); override;
85     // TCDGroupBox
86     procedure DrawGroupBox(ADest: TFPCustomCanvas; ADestPos: TPoint; ASize: TSize;
87       AState: TCDControlState; AStateEx: TCDControlStateEx); override;
88     // TCDPanel
89     procedure DrawPanel(ADest: TCanvas; ASize: TSize;
90       AState: TCDControlState; AStateEx: TCDPanelStateEx); override;
91     // ===================================
92     // Additional Tab
93     // ===================================
94     procedure DrawStaticText(ADest: TCanvas; ASize: TSize;
95       AState: TCDControlState; AStateEx: TCDControlStateEx); override;
96     // ===================================
97     // Common Controls Tab
98     // ===================================
99     // TCDTrackBar
100     procedure DrawTrackBar(ADest: TCanvas; ASize: TSize;
101       AState: TCDControlState; AStateEx: TCDPositionedCStateEx); override;
102     // TCDProgressBar
103     procedure DrawProgressBar(ADest: TCanvas; ASize: TSize;
104       AState: TCDControlState; AStateEx: TCDProgressBarStateEx); override;
105     // TCDListView
106     procedure DrawListView(ADest: TCanvas; ASize: TSize;
107       AState: TCDControlState; AStateEx: TCDListViewStateEx); override;
108     procedure DrawReportListView(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
109       AState: TCDControlState; AStateEx: TCDListViewStateEx); override;
110     procedure DrawReportListViewItem(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
111       ACurItem: TCDListItems; AState: TCDControlState; AStateEx: TCDListViewStateEx); override;
112     // TCDToolBar
113     procedure DrawToolBar(ADest: TCanvas; ASize: TSize;
114       AState: TCDControlState; AStateEx: TCDToolBarStateEx); override;
115     procedure DrawToolBarItem(ADest: TCanvas; ASize: TSize;
116       ACurItem: TCDToolBarItem; AX, AY: Integer;
117       AState: TCDControlState; AStateEx: TCDToolBarStateEx); override;
118     // TCDCustomTabControl
119     procedure DrawCTabControl(ADest: TCanvas; ASize: TSize;
120       AState: TCDControlState; AStateEx: TCDCTabControlStateEx); override;
121     procedure DrawCTabControlFrame(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
122       AState: TCDControlState; AStateEx: TCDCTabControlStateEx); override;
123     procedure DrawTabSheet(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
124       AState: TCDControlState; AStateEx: TCDCTabControlStateEx); override;
125     procedure DrawTabs(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
126       AState: TCDControlState; AStateEx: TCDCTabControlStateEx); override;
127     procedure DrawTab(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
128       AState: TCDControlState; AStateEx: TCDCTabControlStateEx); override;
129     // ===================================
130     // Misc Tab
131     // ===================================
132     procedure DrawSpinEdit(ADest: TCanvas; ADestPos: TPoint; ASize: TSize;
133       AState: TCDControlState; AStateEx: TCDSpinStateEx); override;
134   end;
135 
136 implementation
137 
138 const
139   WIN2000_FRAME_WHITE = clWhite;
140   WIN2000_FRAME_LIGHT_GRAY = $00E2EFF1;
141   WIN2000_FRAME_GRAY = $0099A8AC;
142   WIN2000_FRAME_DARK_GRAY = $00646F71;
143 
144   WIN2000_DISABLED_TEXT = WIN2000_FRAME_GRAY;
145 
146   WIN2000_SELECTION_BACKGROUND = $00C56A31;
147 
148   WIN2000_SCROLLBAR_BACKGROUND = $00ECF4F6;
149   WIN2000_LIGHTGRAY_BACKGROUND = $00ECF4F6;
150 
151   WIN2000_PROGRESSBAR_BLUE = $00C56A31;
152 
153   WIN2000_BTNFACE = $00D8E9EC;
154 
155   WIN2000_FORM    = WIN2000_BTNFACE;
156 
157 { TCDDrawerCommon }
158 
PalDefaultUsesNativePalettenull159 function TCDDrawerCommon.PalDefaultUsesNativePalette: Boolean;
160 begin
161   {$ifdef MSWindows}
162   Result := True;
163   {$else}
164   Result := False;
165   {$endif}
166 end;
167 
168 procedure TCDDrawerCommon.LoadFallbackPaletteColors;
169 begin
170   Palette.ScrollBar := $C8D0D4;
171   Palette.Background := $984E00;
172   Palette.ActiveCaption := $E35400;
173   Palette.InactiveCaption := $DF967A;
174   Palette.Menu := $FFFFFF;
175   Palette.Window := clWhite; // The inside of a Edit control, for example
176   Palette.WindowFrame := $0;
177   Palette.MenuText := $0;
178   Palette.WindowText := $0;
179   Palette.CaptionText := $FFFFFF;
180   Palette.ActiveBorder := $C8D0D4;
181   Palette.InactiveBorder := $C8D0D4;
182   Palette.AppWorkspace := $808080;
183   Palette.Highlight := $C56A31;
184   Palette.HighlightText := $FFFFFF;
185   Palette.BtnFace := WIN2000_BTNFACE;
186   Palette.BtnShadow := $99A8AC;
187   Palette.GrayText := $99A8AC;
188   Palette.BtnText := $0;
189   Palette.InactiveCaptionText := $F8E4D8;
190   Palette.BtnHighlight := $FFFFFF;
191   Palette.color3DDkShadow := $646F71;
192   Palette.color3DLight := $E2EFF1;
193   Palette.InfoText := $0;
194   Palette.InfoBk := $E1FFFF;
195     //
196   Palette.HotLight := $800000;
197   Palette.GradientActiveCaption := $FF953D;
198   Palette.GradientInactiveCaption := $EBB99D;
199   Palette.MenuHighlight := $C56A31;
200   Palette.MenuBar := $D8E9EC;
201   Palette.Form := WIN2000_FORM;
202 end;
203 
GetMeasuresnull204 function TCDDrawerCommon.GetMeasures(AMeasureID: Integer): Integer;
205 begin
206   case AMeasureID of
207   TCDEDIT_LEFT_TEXT_SPACING: Result := 6;
208   TCDEDIT_RIGHT_TEXT_SPACING: Result := 3;
209   TCDEDIT_TOP_TEXT_SPACING: Result := 3;
210   TCDEDIT_BOTTOM_TEXT_SPACING: Result := 3;
211   //
212   TCDCHECKBOX_SQUARE_HALF_HEIGHT: Result := Floor(GetMeasures(TCDCHECKBOX_SQUARE_HEIGHT)/2);
213   TCDCHECKBOX_SQUARE_HEIGHT: Result := DPIAdjustment(15);
214   //
215   TCDCOMBOBOX_DEFAULT_HEIGHT: Result := 21;
216   //
217   TCDRADIOBUTTON_CIRCLE_HEIGHT: Result := 15;
218   //
219   TCDSCROLLBAR_BUTTON_WIDTH: Result := 17;
220   TCDSCROLLBAR_LEFT_SPACING: Result := 17;
221   TCDSCROLLBAR_RIGHT_SPACING: Result := 17;
222   TCDSCROLLBAR_LEFT_BUTTON_POS: Result := 0;
223   TCDSCROLLBAR_RIGHT_BUTTON_POS: Result := -17;
224   //
225   TCDTRACKBAR_LEFT_SPACING: Result := 9;
226   TCDTRACKBAR_RIGHT_SPACING: Result := 9;
227   TCDTRACKBAR_TOP_SPACING: Result := 5;
228   TCDTRACKBAR_FRAME_HEIGHT: Result := DPIAdjustment(17);
229   //
230   TCDLISTVIEW_COLUMN_LEFT_SPACING:  Result := 10;
231   TCDLISTVIEW_COLUMN_RIGHT_SPACING: Result := 10;
232   TCDLISTVIEW_COLUMN_TEXT_LEFT_SPACING:  Result := 5;
233   TCDLISTVIEW_LINE_TOP_SPACING: Result := 3;
234   TCDLISTVIEW_LINE_BOTTOM_SPACING: Result := 3;
235   //
236   TCDTOOLBAR_ITEM_SPACING: Result := 2;
237   TCDTOOLBAR_ITEM_ARROW_WIDTH: Result := 7;
238   TCDTOOLBAR_ITEM_BUTTON_DEFAULT_WIDTH: Result := 23;
239   TCDTOOLBAR_ITEM_ARROW_RESERVED_WIDTH: Result := 35 - 23;
240   TCDTOOLBAR_ITEM_SEPARATOR_DEFAULT_WIDTH: Result := 8;
241   TCDTOOLBAR_DEFAULT_HEIGHT: Result := 26;
242   //
243   TCDCTABCONTROL_CLOSE_TAB_BUTTON_WIDTH: Result := 10;
244   TCDCTABCONTROL_CLOSE_TAB_BUTTON_EXTRA_SPACING: Result := 10;
245   else
246     Result := 0;
247   end;
248 end;
249 
TCDDrawerCommon.GetMeasuresExnull250 function TCDDrawerCommon.GetMeasuresEx(ADest: TCanvas; AMeasureID: Integer;
251   AState: TCDControlState; AStateEx: TCDControlStateEx): Integer;
252 const
253   TCDTabControl_Common_TabCaptionExtraWidth = 20;
254 var
255   ATabsStateEx: TCDCTabControlStateEx absolute AStateEx;
256   lCaption: String;
257   lTabWidth, i, t: Integer;
258   IsPainting: Boolean = False;
259 begin
260   ADest.Font.Assign(AStateEx.Font);
261 
262   case AMeasureID of
263   TCDCONTROL_CAPTION_WIDTH:  Result := ADest.TextWidth(AStateEx.Caption);
264   TCDCONTROL_CAPTION_HEIGHT: Result := ADest.TextHeight(cddTestStr);
265   TCDCTABCONTROL_TAB_HEIGHT: Result := ADest.TextHeight(cddTestStr)+10;
266   TCDCTABCONTROL_TAB_WIDTH:
267   begin
268     if ATabsStateEx.CurTabIndex < ATabsStateEx.TabCount then
269     begin
270       lCaption := ATabsStateEx.Tabs.Strings[ATabsStateEx.CurTabIndex];
271       Result := ADest.TextWidth(lCaption) + TCDTabControl_Common_TabCaptionExtraWidth;
272       if (nboShowCloseButtons in ATabsStateEx.Options) then
273         Result := Result + GetMeasures(TCDCTABCONTROL_CLOSE_TAB_BUTTON_WIDTH)
274           + GetMeasures(TCDCTABCONTROL_CLOSE_TAB_BUTTON_EXTRA_SPACING);
275     end
276     // in any other case we are referring to the aditional + button for adding a new tab
277     else
278       Result := ADest.TextWidth('+') + TCDTabControl_Common_TabCaptionExtraWidth;
279   end;
280   TCDCTABCONTROL_TAB_LEFT_POS:
281   begin
282     Result := 0;
283     for i := 0 to ATabsStateEx.CurTabIndex-1 do
284     begin
285       if i = ATabsStateEx.LeftmostTabVisibleIndex then IsPainting := True;
286 
287       if IsPainting then
288       begin
289         t := ATabsStateEx.CurTabIndex;
290         ATabsStateEx.CurTabIndex := i;
291         Result := Result + GetMeasuresEx(ADest, TCDCTABCONTROL_TAB_WIDTH, AState, AStateEx);
292         ATabsStateEx.CurTabIndex := t;
293       end;
294     end;
295   end;
296   TCDCTABCONTROL_CLOSE_BUTTON_POS_X:
297   begin
298     lTabWidth := GetMeasuresEx(ADest, TCDCTABCONTROL_TAB_WIDTH, AState, AStateEx);
299     Result := GetMeasuresEx(ADest, TCDCTABCONTROL_TAB_LEFT_POS, AState, AStateEx)
300       +lTabWidth
301       -GetMeasures(TCDCTABCONTROL_CLOSE_TAB_BUTTON_WIDTH)
302       -GetMeasures(TCDCTABCONTROL_CLOSE_TAB_BUTTON_EXTRA_SPACING);
303   end;
304   TCDCTABCONTROL_CLOSE_BUTTON_POS_Y:
305   begin
306     if ATabsStateEx.TabIndex = ATabsStateEx.CurTabIndex then Result := 8
307     else Result := 10;
308   end;
309   else
310     Result := 0;
311   end;
312 end;
313 
314 procedure TCDDrawerCommon.CalculatePreferredSize(ADest: TCanvas;
315   AControlId: TCDControlID; AState: TCDControlState;
316   AStateEx: TCDControlStateEx; var PreferredWidth, PreferredHeight: integer;
317   WithThemeSpace, AAllowUseOfMeasuresEx: Boolean);
318 begin
319   PreferredWidth := 0;
320   PreferredHeight := 0;
321 
322   case AControlId of
323   // In the LCL TEdit AutoSizes only its Height, so follow this here
324   cidEdit: PreferredHeight := GetMeasuresEx(ADest, TCDCONTROL_CAPTION_HEIGHT, AState, AStateEx)+8;
325   cidCheckBox, cidRadioButton:
326   begin
327     if AStateEx.AutoSize and AAllowUseOfMeasuresEx then
328     begin
329       PreferredWidth := GetMeasures(TCDCHECKBOX_SQUARE_HEIGHT);
330       PreferredWidth := PreferredWidth
331         + GetMeasuresEx(ADest, TCDCONTROL_CAPTION_WIDTH, AState, AStateEx) + 6;
332     end;
333 
334     PreferredHeight := GetMeasures(TCDCHECKBOX_SQUARE_HEIGHT);
335     if AAllowUseOfMeasuresEx then
336       PreferredHeight := Max(PreferredHeight,
337         GetMeasuresEx(ADest, TCDCONTROL_CAPTION_HEIGHT, AState, AStateEx));
338   end;
339   // In the LCL TComboBox AutoSizes only its Height, so follow this here
340   cidComboBox:
341   begin
342     PreferredHeight := GetMeasures(TCDCOMBOBOX_DEFAULT_HEIGHT);
343     if AAllowUseOfMeasuresEx then
344       PreferredHeight := Max(PreferredHeight,
345         GetMeasuresEx(ADest, TCDCONTROL_CAPTION_HEIGHT, AState, AStateEx));
346   end;
347   end;
348 end;
349 
GetColornull350 function TCDDrawerCommon.GetColor(AColorID: Integer): TColor;
351 begin
352   case AColorId of
353   TCDEDIT_BACKGROUND_COLOR:    Result := clWhite;
354   TCDEDIT_TEXT_COLOR:          Result := clBlack;
355   TCDEDIT_SELECTED_BACKGROUND_COLOR: Result := clBlue;
356   TCDEDIT_SELECTED_TEXT_COLOR: Result := clWhite;
357   TCDBUTTON_DEFAULT_COLOR:     Result := $00F1F5F5;
358   else
359     Result := clBlack;
360   end;
361 end;
362 
TCDDrawerCommon.GetClientAreanull363 function TCDDrawerCommon.GetClientArea(ADest: TCanvas; ASize: TSize;
364   AControlId: TCDControlID; AState: TCDControlState; AStateEx: TCDControlStateEx
365   ): TRect;
366 begin
367   Result := Bounds(0, 0, ASize.cx, ASize.cy);
368 
369   case AControlId of
370   cidCTabControl:
371   begin
372     Result.Top := GetMeasuresEx(ADest, TCDCTABCONTROL_TAB_HEIGHT, AState, AStateEx) + 2;
373     Result.Left := 2;
374     Result.Right := Result.Right - 2;
375     Result.Bottom := Result.Bottom - 2;
376   end;
377   end;
378 end;
379 
DPIAdjustmentnull380 function TCDDrawerCommon.DPIAdjustment(const AValue: Integer): Integer;
381 begin
382   if Screen.PixelsPerInch <= 125 then Result := AValue
383   else Result := Round(AValue * Screen.PixelsPerInch / 125);
384 end;
385 
386 procedure TCDDrawerCommon.DrawFocusRect(ADest: TFPCustomCanvas; ADestPos: TPoint;
387   ASize: TSize);
388 begin
389   ADest.Pen.FPColor := colWhite;
390   ADest.Pen.Style := psSolid;
391   ADest.Brush.Style := bsClear;
392   ADest.Rectangle(ADestPos.X, ADestPos.Y, ADestPos.X + ASize.CX, ADestPos.Y + ASize.CY);
393   ADest.Pen.FPColor := colBlack;
394   ADest.Pen.Style := psDot;
395   ADest.Rectangle(ADestPos.X, ADestPos.Y, ADestPos.X + ASize.CX, ADestPos.Y + ASize.CY);
396 end;
397 
398 procedure TCDDrawerCommon.DrawRaisedFrame(ADest: TCanvas; ADestPos: TPoint;
399   ASize: TSize);
400 begin
401   // white lines in the left and top
402   ADest.Pen.Style := psSolid;
403   ADest.Brush.Style := bsClear;
404   ADest.Pen.Color := WIN2000_FRAME_WHITE;
405   ADest.MoveTo(ADestPos.X, ADestPos.Y+ASize.cy-1);
406   ADest.LineTo(ADestPos.X, ADestPos.Y);
407   ADest.LineTo(ADestPos.X+ASize.cx-1, ADestPos.Y);
408   // Grey line on the inside left and top
409   ADest.Pen.Color := WIN2000_FRAME_LIGHT_GRAY;
410   ADest.MoveTo(ADestPos.X+1, ADestPos.Y+ASize.cy-2);
411   ADest.LineTo(ADestPos.X+1, ADestPos.Y+1);
412   ADest.LineTo(ADestPos.X+ASize.cx-1, ADestPos.Y+1);
413   // Dark grey line on the right and bottom
414   ADest.Pen.Color := WIN2000_FRAME_DARK_GRAY;
415   ADest.MoveTo(ADestPos.X,            ADestPos.Y+ASize.cy-1);
416   ADest.LineTo(ADestPos.X+ASize.cx-1, ADestPos.Y+ASize.cy-1);
417   ADest.LineTo(ADestPos.X+ASize.cx-1, ADestPos.Y);
418   // Grey line on the inside right and bottom
419   ADest.Pen.Color := WIN2000_FRAME_GRAY;
420   ADest.MoveTo(ADestPos.X+1,          ADestPos.Y+ASize.cy-2);
421   ADest.LineTo(ADestPos.X+ASize.cx-2, ADestPos.Y+ASize.cy-2);
422   ADest.LineTo(ADestPos.X+ASize.cx-2, ADestPos.Y-1);
423 end;
424 
425 procedure TCDDrawerCommon.DrawFrame3D(ADest: TFPCustomCanvas; ADestPos: TPoint; ASize: TSize;
426     const FrameWidth : integer; const Style : TBevelCut);
427 var
428   i: Integer;
429   ARect: TRect;
430 begin
431   ARect := Bounds(ADestPos.X, ADestPos.Y, ASize.cx, ASize.cy);
432   for i := 0 to FrameWidth-1 do
433   begin
434     case Style of
435       bvLowered:
436       begin
437         // white lines in the left and top
438         ADest.Pen.Style := psSolid;
439         ADest.Brush.Style := bsClear;
440         ADest.Pen.FPColor := TColorToFPColor(WIN2000_FRAME_GRAY);
441         ADest.MoveTo(ARect.Left,  ARect.Bottom);
442         ADest.LineTo(ARect.Left,  ARect.Top);
443         ADest.LineTo(ARect.Right, ARect.Top);
444         // Dark grey line on the right and bottom
445         ADest.Pen.FPColor := TColorToFPColor(WIN2000_FRAME_WHITE);
446         ADest.MoveTo(ARect.Left,  ARect.Bottom);
447         ADest.LineTo(ARect.Right, ARect.Bottom);
448         ADest.LineTo(ARect.Right, ARect.Top);
449       end;
450       bvRaised:
451       begin
452         // white lines in the left and top
453         ADest.Pen.Style := psSolid;
454         ADest.Brush.Style := bsClear;
455         ADest.Pen.FPColor := TColorToFPColor(WIN2000_FRAME_WHITE);
456         ADest.MoveTo(ARect.Left,  ARect.Bottom);
457         ADest.LineTo(ARect.Left,  ARect.Top);
458         ADest.LineTo(ARect.Right, ARect.Top);
459         // Dark grey line on the right and bottom
460         ADest.Pen.FPColor := TColorToFPColor(WIN2000_FRAME_GRAY);
461         ADest.MoveTo(ARect.Left,  ARect.Bottom);
462         ADest.LineTo(ARect.Right, ARect.Bottom);
463         ADest.LineTo(ARect.Right, ARect.Top);
464       end;
465       bvSpace:
466       begin
467       end;
468     end;
469 
470     InflateRect(ARect, -1, -1);
471   end;
472 end;
473 
474 procedure TCDDrawerCommon.DrawSunkenFrame(ADest: TCanvas; ADestPos: TPoint;
475   ASize: TSize);
476 begin
477   // The Frame, except the lower-bottom which is white anyway
478   // outter top-right
479   ADest.Pen.Style := psSolid;
480   ADest.Pen.Color := WIN2000_FRAME_GRAY;
481   ADest.MoveTo(ADestPos.X,            ADestPos.Y+ASize.cy-1);
482   ADest.LineTo(ADestPos.X,            ADestPos.Y);
483   ADest.LineTo(ADestPos.X+ASize.cx-1, ADestPos.Y);
484   // inner top-right
485   ADest.Pen.Color := WIN2000_FRAME_DARK_GRAY;
486   ADest.MoveTo(ADestPos.X+1,          ADestPos.Y+ASize.cy-2);
487   ADest.LineTo(ADestPos.X+1,          ADestPos.Y+1);
488   ADest.LineTo(ADestPos.X+ASize.cx-2, ADestPos.Y+1);
489   // inner bottom-right
490   ADest.Pen.Color := WIN2000_FRAME_LIGHT_GRAY;
491   ADest.MoveTo(ADestPos.X+1,          ADestPos.Y+ASize.cy-2);
492   ADest.LineTo(ADestPos.X+ASize.cx-2, ADestPos.Y+ASize.cy-2);
493   ADest.LineTo(ADestPos.X+ASize.cx-2, ADestPos.Y);
494   // outter bottom-right
495   ADest.Pen.Color := WIN2000_FRAME_WHITE;
496   ADest.MoveTo(ADestPos.X+1,          ADestPos.Y+ASize.cy-1);
497   ADest.LineTo(ADestPos.X+ASize.cx-1, ADestPos.Y+ASize.cy-1);
498   ADest.LineTo(ADestPos.X+ASize.cx-1, ADestPos.Y);
499 end;
500 
501 procedure TCDDrawerCommon.DrawShallowSunkenFrame(ADest: TCanvas;
502   ADestPos: TPoint; ASize: TSize);
503 begin
504   // Inside area, there is no background because the control occupies the entire area
505   ADest.Pen.Style := psSolid;
506   ADest.Pen.Color := WIN2000_FRAME_GRAY;
507   ADest.MoveTo(ADestPos.X, ADestPos.Y + ASize.cy);
508   ADest.LineTo(ADestPos.X, ADestPos.Y);
509   ADest.LineTo(ADestPos.X + ASize.cx, ADestPos.Y);
510   ADest.Pen.Color := WIN2000_FRAME_WHITE;
511   ADest.MoveTo(ADestPos.X, ADestPos.Y + ASize.cy-1);
512   ADest.LineTo(ADestPos.X + ASize.cx-1, ADestPos.Y + ASize.cy-1);
513   ADest.LineTo(ADestPos.X + ASize.cx-1, ADestPos.Y-1);
514 end;
515 
516 procedure TCDDrawerCommon.DrawTickmark(ADest: TFPCustomCanvas; ADestPos: TPoint; AState: TCDControlState);
517 var
518   i: Integer;
519   lSpacing5, lFirstLinesEnd, lSecondLinesEnd: Integer;
520 begin
521   if csfPartiallyOn in AState then
522     ADest.Pen.FPColor := TColorToFPColor(WIN2000_FRAME_GRAY)
523   else
524     ADest.Pen.FPColor := colBlack;
525   ADest.Pen.Style := psSolid;
526 
527   if Screen.PixelsPerInch <= 125 then
528   begin
529     // 4 lines going down and to the right
530     for i := 0 to 3 do
531       ADest.Line(ADestPos.X+1+i, ADestPos.Y+2+i, ADestPos.X+1+i, ADestPos.Y+5+i);
532     // Now 5 lines going up and to the right
533     for i := 4 to 8 do
534      ADest.Line(ADestPos.X+1+i, ADestPos.Y+2+6-i, ADestPos.X+1+i, ADestPos.Y+5+6-i);
535     Exit;
536   end;
537 
538   lSpacing5 := DPIAdjustment(5);
539   lFirstLinesEnd := DPIAdjustment(4)-1;
540   lSecondLinesEnd := DPIAdjustment(9)-1;
541 
542   // 4 lines going down and to the right
543   for i := 0 to lFirstLinesEnd do
544     ADest.Line(ADestPos.X+2+i, ADestPos.Y+2+i, ADestPos.X+2+i, ADestPos.Y+lSpacing5+i);
545   // Now 5 lines going up and to the right
546   for i := lFirstLinesEnd+1 to lSecondLinesEnd do
547     ADest.Line(ADestPos.X+2+i, ADestPos.Y+2+lFirstLinesEnd*2-i, ADestPos.X+2+i, ADestPos.Y+2+lFirstLinesEnd*2+lSpacing5-i);
548 end;
549 
550 procedure TCDDrawerCommon.DrawSlider(ADest: TCanvas; ADestPos: TPoint;
551   ASize: TSize; AState: TCDControlState);
552 var
553   lPoints: array[0..4] of TPoint;
554   lSliderBottom: Integer;
555   lSpacing5, lSpacing10: Integer;
556 begin
557   lSpacing5 := (ASize.cx-1)div 2;
558   lSpacing10 := (ASize.cx-1);
559 
560   ADest.Brush.Color := Palette.BtnFace;
561   ADest.Brush.Style := bsSolid;
562   ADest.Pen.Color := WIN2000_FRAME_WHITE;
563 
564   if csfHorizontal in AState then
565   begin
566     lSliderBottom := ADestPos.Y+ASize.CY;
567     // outter white frame
568     lPoints[0] := Point(ADestPos.X+lSpacing5, lSliderBottom);
569     lPoints[1] := Point(ADestPos.X, lSliderBottom-lSpacing5);
570     lPoints[2] := Point(ADestPos.X, ADestPos.Y);
571     lPoints[3] := Point(ADestPos.X+lSpacing10, ADestPos.Y);
572     lPoints[4] := Point(ADestPos.X+lSpacing10, lSliderBottom-lSpacing5);
573     ADest.Polygon(lPoints);
574     // left-top inner frame
575     ADest.Pen.Color := WIN2000_FRAME_LIGHT_GRAY;
576     ADest.MoveTo(ADestPos.X+lSpacing5, lSliderBottom-1);
577     ADest.LineTo(ADestPos.X+1, lSliderBottom-lSpacing5);
578     ADest.LineTo(ADestPos.X+1, ADestPos.Y+1);
579     ADest.LineTo(ADestPos.X+lSpacing10-1, ADestPos.Y+1);
580     // right inner frame
581     ADest.Pen.Color := WIN2000_FRAME_GRAY;
582     ADest.MoveTo(ADestPos.X+lSpacing5, lSliderBottom-1);
583     ADest.LineTo(ADestPos.X+lSpacing10-1, lSliderBottom-lSpacing5);
584     ADest.LineTo(ADestPos.X+lSpacing10-1, ADestPos.Y);
585     // right outter frame
586     ADest.Pen.Color := WIN2000_FRAME_DARK_GRAY;
587     ADest.MoveTo(ADestPos.X+lSpacing5, lSliderBottom);
588     ADest.LineTo(ADestPos.X+lSpacing10, lSliderBottom-lSpacing5);
589     ADest.LineTo(ADestPos.X+lSpacing10, ADestPos.Y-1);
590   end
591   else
592   begin
593     lSliderBottom := ADestPos.Y+ASize.CY;
594     // outter white frame
595     lPoints[0] := Point(lSliderBottom, ADestPos.X+lSpacing5);
596     lPoints[1] := Point(lSliderBottom-lSpacing5, ADestPos.X);
597     lPoints[2] := Point(ADestPos.Y, ADestPos.X);
598     lPoints[3] := Point(ADestPos.Y, ADestPos.X+lSpacing10);
599     lPoints[4] := Point(lSliderBottom-lSpacing5, ADestPos.X+lSpacing10);
600     ADest.Polygon(lPoints);
601     // left-top inner frame
602     ADest.Pen.Color := WIN2000_FRAME_LIGHT_GRAY;
603     ADest.MoveTo(lSliderBottom-1, ADestPos.X+lSpacing5);
604     ADest.LineTo(lSliderBottom-lSpacing5, ADestPos.X+1);
605     ADest.LineTo(ADestPos.Y+1, ADestPos.X+1);
606     ADest.LineTo(ADestPos.Y+1, ADestPos.X+lSpacing10-1);
607     // right inner frame
608     ADest.Pen.Color := WIN2000_FRAME_GRAY;
609     ADest.MoveTo(lSliderBottom-1, ADestPos.X+lSpacing5);
610     ADest.LineTo(lSliderBottom-lSpacing5, ADestPos.X+lSpacing10-1);
611     ADest.LineTo(ADestPos.Y, ADestPos.X+lSpacing10-1);
612     // right outter frame
613     ADest.Pen.Color := WIN2000_FRAME_DARK_GRAY;
614     ADest.MoveTo(lSliderBottom, ADestPos.X+lSpacing5);
615     ADest.LineTo(lSliderBottom-lSpacing5, ADestPos.X+lSpacing10);
616     ADest.LineTo(ADestPos.Y-1, ADestPos.X+lSpacing10);
617   end;
618 end;
619 
620 procedure TCDDrawerCommon.DrawArrow(ADest: TCanvas; ADestPos: TPoint;
621   ADirection: TCDControlState; ASize: Integer = 7);
622 var
623   lPoints: array[0..2] of TPoint;
624   lPos: TPoint;
625   lSize, lSizeHalf: Integer;
626 begin
627   lPos := ADestPos;
628   lSize := ASize - 1;
629   lSizeHalf := ASize div 2;
630   // Move the arrow a little bit when a sunken state is passed
631   if csfSunken in ADirection then lPos := Point(lPos.X+1, lPos.Y+1);
632 
633   if csfLeftArrow in ADirection then
634   begin
635     lPoints[0] := Point(lPos.X,           lPos.Y+lSizeHalf);// left point
636     lPoints[1] := Point(lPos.X+lSizeHalf, lPos.Y+lSize);// lower point
637     lPoints[2] := Point(lPos.X+lSizeHalf, lPos.Y);  // upper point
638   end
639   else if csfRightArrow in ADirection then
640   begin
641     lPoints[0] := Point(lPos.X+1,           lPos.Y);  // upper point
642     lPoints[1] := Point(lPos.X+1,           lPos.Y+lSize);// lower point
643     lPoints[2] := Point(lPos.X+1+lSizeHalf, lPos.Y+lSizeHalf);// right point
644   end
645   else if csfUpArrow in ADirection then
646   begin
647     lPoints[0] := Point(lPos.X+lSizeHalf, lPos.Y);  // upper point
648     lPoints[1] := Point(lPos.X,           lPos.Y+lSizeHalf);// left point
649     lPoints[2] := Point(lPos.X+lSize,     lPos.Y+lSizeHalf);// right point
650   end
651   else // downArrow
652   begin
653     lPoints[0] := Point(lPos.X,           lPos.Y+1);// left point
654     lPoints[1] := Point(lPos.X+lSize,     lPos.Y+1);// right point
655     lPoints[2] := Point(lPos.X+lSizeHalf, lPos.Y+1+lSizeHalf);// lower point
656   end;
657   ADest.Brush.Style := bsSolid;
658   ADest.Brush.Color := clBlack;
659   ADest.Pen.Style := psSolid;
660   ADest.Pen.Color := clBlack;
661   ADest.Polygon(lPoints);
662 end;
663 
664 procedure TCDDrawerCommon.DrawSmallCloseButton(ADest: TCanvas; ADestPos: TPoint);
665 begin
666   ADest.Pen.Style := psSolid;
667   ADest.Pen.Color := clGray;
668   ADest.Pen.Width := 4;
669   ADest.Line(ADestPos.X, ADestPos.Y, ADestPos.X+10, ADestPos.Y+10);
670   ADest.Line(ADestPos.X+9, ADestPos.Y, ADestPos.X-1, ADestPos.Y+10);
671   ADest.Pen.Width := 1;
672 end;
673 
674 procedure TCDDrawerCommon.DrawButtonWithArrow(ADest: TCanvas; ADestPos: TPoint;
675   ASize: TSize; AState: TCDControlState);
676 begin
677   // First the background color
678   ADest.Brush.Color := WIN2000_BTNFACE;
679   ADest.Brush.Style := bsSolid;
680   ADest.FillRect(Bounds(ADestPos.X, ADestPos.Y, ASize.CX, ASize.CY));
681 
682   // Now the button frame
683   if csfSunken in AState then DrawSunkenFrame(ADest, ADestPos, ASize)
684   else DrawRaisedFrame(ADest, ADestPos, ASize);
685 
686   // Now the arrow
687   DrawArrow(ADest, Point(ADestPos.X + ASize.CY div 4, ADestPos.Y + ASize.CY * 3 div 8), AState, ASize.CY div 2);
688 end;
689 
690 procedure TCDDrawerCommon.DrawControl(ADest: TCanvas;
691   ASize: TSize; AState: TCDControlState; AStateEx: TCDControlStateEx);
692 var
693   lColor: TColor;
694 begin
695   // Background
696   lColor := AStateEx.RGBColor;
697   ADest.Brush.Color := lColor;
698   ADest.Brush.Style := bsSolid;
699   ADest.Pen.Style := psSolid;
700   ADest.Pen.Color := lColor;
701   ADest.FillRect(0, 0, ASize.cx, ASize.cy);
702 end;
703 
704 procedure TCDDrawerCommon.DrawButton(ADest: TFPCustomCanvas;
705   ADestPos: TPoint; ASize: TSize; AState: TCDControlState; AStateEx: TCDButtonStateEx);
706 var
707   Str: string;
708   lGlyphLeftSpacing: Integer = 0;
709   lGlyphExtra: Integer = 0;
710   lTextOutPos: TPoint;
711   lGlyphCaptionHeight: Integer;
712 begin
713   // background
714   ADest.Brush.Style := bsSolid;
715   ADest.Brush.FPColor := AStateEx.FPRGBColor;
716   ADest.Pen.FPColor := colWhite;
717   ADest.Pen.Style := psSolid;
718   ADest.Rectangle(0, 0, ASize.cx - 1, ASize.cy - 1);
719   ADest.Pen.FPColor := colWhite;
720   ADest.Line(0, 0, ASize.cx - 1, 0);
721   ADest.Line(0, 0, 0, ASize.cy - 1);
722   ADest.Pen.FPColor := colGray;
723   ADest.Line(0, ASize.cy - 1, ASize.cx - 1, ASize.cy - 1);
724   ADest.Line(ASize.cx - 1, ASize.cy - 1, ASize.cx - 1, -1);
725   ADest.Pen.FPColor := TColorToFPColor($0099A8AC);
726   ADest.Line(1, ASize.cy - 2, ASize.cx - 2, ASize.cy - 2);
727   ADest.Line(ASize.cx - 2, ASize.cy - 2, ASize.cx - 2, 0);
728   ADest.Pen.FPColor := TColorToFPColor($00E2EFF1);
729   ADest.Line(1, 1, ASize.cx - 2, 1);
730   ADest.Line(1, 1, 1, ASize.cy - 2);
731 
732   // Button image
733   if csfSunken in AState then
734   begin
735     ADest.Brush.Style := bsSolid;
736     ADest.Brush.FPColor := AStateEx.FPRGBColor;
737     ADest.Pen.FPColor := colWhite;
738     ADest.Pen.Style := psSolid;
739     ADest.Rectangle(0, 0, ASize.cx - 1, ASize.cy - 1);
740     ADest.Pen.FPColor := colGray;
741     ADest.Line(0, 0, ASize.cx - 1, 0);
742     ADest.Line(0, 0, 0, ASize.cy - 1);
743     ADest.Pen.FPColor := colWhite;
744     ADest.Line(0, ASize.cy - 1, ASize.cx - 1, ASize.cy - 1);
745     ADest.Line(ASize.cx - 1, ASize.cy - 1, ASize.cx - 1, -1);
746     ADest.Pen.FPColor := TColorToFPColor($00E2EFF1);
747     ADest.Line(1, ASize.cy - 2, ASize.cx - 2, ASize.cy - 2);
748     ADest.Line(ASize.cx - 2, ASize.cy - 2, ASize.cx - 2, 0);
749     ADest.Pen.FPColor := TColorToFPColor($0099A8AC);
750     ADest.Line(1, 1, ASize.cx - 2, 1);
751     ADest.Line(1, 1, 1, ASize.cy - 2);
752   end
753   else if csfHasFocus in AState then
754   begin
755     if ADest is TCanvas then
756       DrawFocusRect(TCanvas(ADest), Point(3, 3), Size(ASize.cx - 7, ASize.cy - 7));
757   end;
758 
759   // Position calculations
760   if ADest is TCanvas then
761   begin
762     ADest.Font.Assign(AStateEx.Font);
763     Str := AStateEx.Caption;
764     lGlyphCaptionHeight := Max(TCanvas(ADest).TextHeight(Str), AStateEx.Glyph.Height);
765     lTextOutPos.X := (ASize.cx - TCanvas(ADest).TextWidth(Str) - AStateEx.Glyph.Width) div 2;
766     lTextOutPos.Y := (ASize.cy - lGlyphCaptionHeight) div 2;
767     lTextOutPos.X := Max(lTextOutPos.X, 5);
768     lTextOutPos.Y := Max(lTextOutPos.Y, 5);
769 
770     // Button glyph
771     if not AStateEx.Glyph.Empty then
772     begin
773       if csfSunken in AState then lGlyphExtra := 1;
774       TCanvas(ADest).Draw(lTextOutPos.X + lGlyphExtra, lTextOutPos.Y + lGlyphExtra, AStateEx.Glyph);
775       lGlyphLeftSpacing := AStateEx.Glyph.Width+5;
776     end;
777 
778     // Button text
779     lTextOutPos.X := lTextOutPos.X + lGlyphLeftSpacing;
780     lTextOutPos.Y := (ASize.cy - TCanvas(ADest).TextHeight(Str)) div 2;
781     ADest.Brush.Style := bsClear;
782     ADest.Pen.Style := psSolid;
783     if csfEnabled in AState then
784     begin
785       if csfSunken in AState then
786       begin
787         Inc(lTextOutPos.X);
788         Inc(lTextOutPos.Y);
789       end;
790       ADest.TextOut(lTextOutPos.X, lTextOutPos.Y, Str)
791     end
792     else
793     begin
794       // The disabled text is composed by a white shadow under it and a grey text
795       TCanvas(ADest).Font.Color := clWhite;
796       Inc(lTextOutPos.X);
797       Inc(lTextOutPos.Y);
798       TCanvas(ADest).TextOut(lTextOutPos.X, lTextOutPos.Y, Str);
799       //
800       TCanvas(ADest).Font.Color := WIN2000_DISABLED_TEXT;
801       Dec(lTextOutPos.X);
802       Dec(lTextOutPos.Y);
803       ADest.TextOut(lTextOutPos.X, lTextOutPos.Y, Str);
804     end;
805   end;
806 end;
807 
808 procedure TCDDrawerCommon.DrawEditBackground(ADest: TCanvas;
809   ADestPos: TPoint; ASize: TSize; AState: TCDControlState;
810   AStateEx: TCDEditStateEx);
811 begin
812   // The background
813   ADest.Brush.Color := clWhite;
814   ADest.Brush.Style := bsSolid;
815   ADest.Pen.Color := WIN2000_FRAME_WHITE;
816   ADest.Pen.Style := psSolid;
817   ADest.Rectangle(0, 0, ASize.cx, ASize.cy);
818 end;
819 
820 procedure TCDDrawerCommon.DrawEditFrame(ADest: TCanvas; ADestPos: TPoint;
821   ASize: TSize; AState: TCDControlState; AStateEx: TCDEditStateEx);
822 begin
823   // The Frame, except the lower-bottom which is white anyway
824   // outter top-right
825   ADest.Pen.Style := psSolid;
826   ADest.Pen.Color := WIN2000_FRAME_GRAY;
827   ADest.MoveTo(0, ASize.cy-1);
828   ADest.LineTo(0, 0);
829   ADest.LineTo(ASize.cx-1, 0);
830   // inner top-right
831   ADest.Pen.Color := WIN2000_FRAME_DARK_GRAY;
832   ADest.MoveTo(1, ASize.cy-2);
833   ADest.LineTo(1, 1);
834   ADest.LineTo(ASize.cx-2, 1);
835   // inner bottom-right
836   ADest.Pen.Color := WIN2000_FRAME_LIGHT_GRAY;
837   ADest.MoveTo(1, ASize.cy-2);
838   ADest.LineTo(ASize.cx-2, ASize.cy-2);
839   ADest.LineTo(ASize.cx-2, 0);
840 end;
841 
842 procedure TCDDrawerCommon.DrawCaret(ADest: TCanvas; ADestPos: TPoint;
843   ASize: TSize; AState: TCDControlState; AStateEx: TCDEditStateEx);
844 var
845   lTextTopSpacing, lCaptionHeight, lLineHeight, lLineTop: Integer;
846   lControlText, lTmpText: string;
847   lTextBottomSpacing, lCaretPixelPos: Integer;
848 begin
849   if not AStateEx.CaretIsVisible then Exit;
850 
851   if AStateEx.Lines.Count = 0 then lControlText := ''
852   else lControlText := AStateEx.Lines.Strings[AStateEx.CaretPos.Y];
853   lCaptionHeight := GetMeasuresEx(ADest, TCDCONTROL_CAPTION_HEIGHT, AState, AStateEx);
854   lTextBottomSpacing := GetMeasures(TCDEDIT_BOTTOM_TEXT_SPACING);
855   lTextTopSpacing := GetMeasures(TCDEDIT_TOP_TEXT_SPACING);
856   lLineHeight := ADest.TextHeight(cddTestStr)+2;
857   lLineHeight := Min(ASize.cy-lTextBottomSpacing, lLineHeight);
858   lLineTop := lTextTopSpacing + AStateEx.CaretPos.Y * lLineHeight;
859 
860   lTmpText := UTF8Copy(lControlText, AStateEx.VisibleTextStart.X, AStateEx.CaretPos.X-AStateEx.VisibleTextStart.X+1);
861   lTmpText :=  VisibleText(lTmpText, AStateEx.PasswordChar);
862   lCaretPixelPos := ADest.TextWidth(lTmpText) + GetMeasures(TCDEDIT_LEFT_TEXT_SPACING)
863     + AStateEx.LeftTextMargin;
864   ADest.Pen.Color := clBlack;
865   ADest.Pen.Style := psSolid;
866   ADest.Line(lCaretPixelPos, lLineTop, lCaretPixelPos, lLineTop+lCaptionHeight);
867 end;
868 
869 procedure TCDDrawerCommon.DrawEdit(ADest: TCanvas;
870   ASize: TSize; AState: TCDControlState; AStateEx: TCDEditStateEx);
871 var
872   lVisibleText, lControlText: TCaption;
873   lSelLeftPos, lSelLeftPixelPos, lSelLength, lSelRightPos: Integer;
874   lTextWidth, lLineHeight, lLineTop: Integer;
875   lControlTextLen: PtrInt;
876   lTextLeftSpacing, lTextTopSpacing, lTextBottomSpacing: Integer;
877   lTextColor: TColor;
878   i, lVisibleLinesCount: Integer;
879 begin
880   // Background
881   DrawEditBackground(ADest, Point(0, 0), ASize, AState, AStateEx);
882 
883   // General text configurations which apply to all lines
884   // Configure the text color
885   if csfEnabled in AState then
886     lTextColor := AStateEx.Font.Color
887   else
888     lTextColor := WIN2000_DISABLED_TEXT;
889 
890   ADest.Brush.Style := bsClear;
891   ADest.Font.Assign(AStateEx.Font);
892   ADest.Font.Color := lTextColor;
893   lTextLeftSpacing := GetMeasures(TCDEDIT_LEFT_TEXT_SPACING);
894   //lTextRightSpacing := GetMeasures(TCDEDIT_RIGHT_TEXT_SPACING);
895   lTextTopSpacing := GetMeasures(TCDEDIT_TOP_TEXT_SPACING);
896   lTextBottomSpacing := GetMeasures(TCDEDIT_BOTTOM_TEXT_SPACING);
897 
898   lLineHeight := ADest.TextHeight(cddTestStr)+2;
899   lLineHeight := Min(ASize.cy-lTextBottomSpacing, lLineHeight);
900 
901   // Fill this to be used in other parts
902   AStateEx.LineHeight := lLineHeight;
903   AStateEx.FullyVisibleLinesCount := ASize.cy - lTextTopSpacing - lTextBottomSpacing;
904   AStateEx.FullyVisibleLinesCount := AStateEx.FullyVisibleLinesCount div lLineHeight;
905   AStateEx.FullyVisibleLinesCount := Min(AStateEx.FullyVisibleLinesCount, AStateEx.Lines.Count);
906 
907   // Calculate how many lines to draw
908   if AStateEx.Multiline then
909     lVisibleLinesCount := AStateEx.FullyVisibleLinesCount + 1
910   else
911     lVisibleLinesCount := 1;
912   lVisibleLinesCount := Min(lVisibleLinesCount, AStateEx.Lines.Count);
913 
914   // Now draw each line
915   for i := 0 to lVisibleLinesCount - 1 do
916   begin
917     lControlText := AStateEx.Lines.Strings[AStateEx.VisibleTextStart.Y+i];
918     lControlText :=  VisibleText(lControlText, AStateEx.PasswordChar);
919     lControlTextLen := UTF8Length(lControlText);
920     lLineTop := lTextTopSpacing + i * lLineHeight;
921 
922     // The text
923     ADest.Pen.Style := psClear;
924     ADest.Brush.Style := bsClear;
925     // ToDo: Implement multi-line selection
926     if (AStateEx.SelLength = 0) or (AStateEx.SelStart.Y <> AStateEx.VisibleTextStart.Y+i) then
927     begin
928       lVisibleText := UTF8Copy(lControlText, AStateEx.VisibleTextStart.X, lControlTextLen);
929       ADest.TextOut(lTextLeftSpacing, lLineTop, lVisibleText);
930     end
931     // Text and Selection
932     else
933     begin
934       lSelLeftPos := AStateEx.SelStart.X;
935       if AStateEx.SelLength < 0 then lSelLeftPos := lSelLeftPos + AStateEx.SelLength;
936 
937       lSelRightPos := AStateEx.SelStart.X;
938       if AStateEx.SelLength > 0 then lSelRightPos := lSelRightPos + AStateEx.SelLength;
939 
940       lSelLength := AStateEx.SelLength;
941       if lSelLength < 0 then lSelLength := lSelLength * -1;
942 
943       // Text left of the selection
944       lVisibleText := UTF8Copy(lControlText, AStateEx.VisibleTextStart.X, lSelLeftPos-AStateEx.VisibleTextStart.X+1);
945       ADest.TextOut(lTextLeftSpacing, lLineTop, lVisibleText);
946       lSelLeftPixelPos := ADest.TextWidth(lVisibleText)+lTextLeftSpacing;
947 
948       // The selection background
949       lVisibleText := UTF8Copy(lControlText, lSelLeftPos+1, lSelLength);
950       lTextWidth := ADest.TextWidth(lVisibleText);
951       ADest.Brush.Color := WIN2000_SELECTION_BACKGROUND;
952       ADest.Brush.Style := bsSolid;
953       ADest.Rectangle(Bounds(lSelLeftPixelPos, lLineTop, lTextWidth, lLineHeight));
954       ADest.Brush.Style := bsClear;
955 
956       // The selection text
957       ADest.Font.Color := clWhite;
958       ADest.TextOut(lSelLeftPixelPos, lLineTop, lVisibleText);
959       lSelLeftPixelPos := lSelLeftPixelPos + lTextWidth;
960 
961       // Text right of the selection
962       ADest.Brush.Color := clWhite;
963       ADest.Font.Color := lTextColor;
964       lVisibleText := UTF8Copy(lControlText, lSelLeftPos+lSelLength+1, lControlTextLen);
965       ADest.TextOut(lSelLeftPixelPos, lLineTop, lVisibleText);
966     end;
967   end;
968 
969   // And the caret
970   DrawCaret(ADest, Point(0, 0), ASize, AState, AStateEx);
971 
972   // In the end the frame, because it must be on top of everything
973   DrawEditFrame(ADest, Point(0, 0), ASize, AState, AStateEx);
974 end;
975 
976 procedure TCDDrawerCommon.DrawCheckBoxSquare(ADest: TCanvas; ADestPos: TPoint;
977   ASize: TSize; AState: TCDControlState; AStateEx: TCDControlStateEx);
978 var
979   lHalf, lSquareHalf, lSquareHeight: Integer;
980 begin
981   lHalf := ASize.cy div 2;
982   lSquareHalf := GetMeasures(TCDCHECKBOX_SQUARE_HALF_HEIGHT);
983   lSquareHeight := GetMeasures(TCDCHECKBOX_SQUARE_HEIGHT);
984 
985   // the square background
986   ADest.Pen.Style := psClear;
987   ADest.Brush.Style := bsSolid;
988   if csfPartiallyOn in AState then ADest.Brush.Color := WIN2000_LIGHTGRAY_BACKGROUND
989   else ADest.Brush.Color := Palette.Window;
990   ADest.Rectangle(Bounds(1, lHalf - lSquareHalf, lSquareHeight, lSquareHeight));
991 
992   // the square frame
993   DrawSunkenFrame(ADest, Point(1, lHalf - lSquareHalf),
994     Size(lSquareHeight, lSquareHeight));
995 
996 {  // The selection inside the square
997   ADest.Brush.Style := bsClear;
998   ADest.Pen.Color := RGBToColor($31, $C6, $D6);
999   ADest.Pen.Style := psSolid;
1000   if csfHasFocus in AState then
1001   begin
1002     ADest.Rectangle(
1003       2,
1004       lHalf - lSquareHalf+1,
1005       lSquareHeight,
1006       lHalf + lSquareHalf-1);
1007   end;}
1008 end;
1009 
1010 procedure TCDDrawerCommon.DrawCheckBox(ADest: TCanvas;
1011   ASize: TSize; AState: TCDControlState; AStateEx: TCDControlStateEx);
1012 var
1013   lColor: TColor;
1014   lSquareHeight, lValue3: Integer;
1015   lTextHeight, lTextY: Integer;
1016 begin
1017   lSquareHeight := GetMeasures(TCDCHECKBOX_SQUARE_HEIGHT);
1018   lValue3 := DPIAdjustment(3);
1019 
1020   // Background
1021   lColor := AStateEx.ParentRGBColor;
1022   ADest.Brush.Color := lColor;
1023   ADest.Brush.Style := bsSolid;
1024   ADest.Pen.Style := psClear;
1025   ADest.FillRect(0, 0, ASize.cx, ASize.cy);
1026 
1027   // The checkbox item itself
1028   DrawCheckBoxSquare(ADest, Point(0, 0), ASize, AState, AStateEx);
1029 
1030   // The Tickmark
1031   if (csfOn in AState) or (csfPartiallyOn in AState) then
1032     DrawTickmark(ADest, Point(lValue3, ASize.cy div 2 - GetMeasures(TCDCHECKBOX_SQUARE_HALF_HEIGHT)+lValue3), AState);
1033 
1034   // The text selection
1035   if csfHasFocus in AState then
1036     DrawFocusRect(ADest, Point(lSquareHeight+4, 0),
1037       Size(ASize.cx-lSquareHeight-4, ASize.cy));
1038 
1039   // Now the text
1040   ADest.Brush.Style := bsClear;
1041   ADest.Pen.Style := psClear;
1042   ADest.Font.Assign(AStateEx.Font);
1043   lTextHeight := ADest.TextHeight(cddTestStr);
1044   // put the text in the center
1045   if lSquareHeight > lTextHeight then lTextY := (lSquareHeight - ADest.TextHeight(cddTestStr)) div 2
1046   else lTextY := 0;
1047   lTextY := Max(0, lTextY - 1);
1048 
1049   ADest.TextOut(lSquareHeight+5, lTextY, AStateEx.Caption);
1050 end;
1051 
1052 procedure TCDDrawerCommon.DrawRadioButtonCircle(ADest: TCanvas;
1053   ADestPos: TPoint; ASize: TSize; AState: TCDControlState;
1054   AStateEx: TCDControlStateEx);
1055 var
1056   lCircleThird, lCircleHeight: Integer;
1057 begin
1058   //lHalf := ASize.cy div 2;
1059   lCircleHeight := GetMeasures(TCDRADIOBUTTON_CIRCLE_HEIGHT);
1060   lCircleThird := lCircleHeight div 3;
1061 
1062   // the circle background
1063   ADest.Pen.Style := psClear;
1064   ADest.Brush.Style := bsSolid;
1065   ADest.Brush.Color := Palette.Window; // or WIN2000_FRAME_WHITE ?
1066   ADest.Rectangle(Bounds(ADestPos.X, ADestPos.Y+lCircleThird-1, lCircleHeight-2, lCircleThird));
1067   ADest.Rectangle(Bounds(ADestPos.X+lCircleThird-1, ADestPos.Y, lCircleThird, lCircleHeight-2));
1068 
1069   // The circle itself
1070   ADest.Pen.Style := psSolid;
1071   // Gray area
1072   ADest.Pixels[ADestPos.X+4, ADestPos.Y] := WIN2000_FRAME_GRAY;
1073   ADest.Pixels[ADestPos.X+5, ADestPos.Y] := WIN2000_FRAME_GRAY;
1074   ADest.Pixels[ADestPos.X+6, ADestPos.Y] := WIN2000_FRAME_GRAY;
1075   ADest.Pixels[ADestPos.X+7, ADestPos.Y] := WIN2000_FRAME_GRAY;
1076   ADest.Pixels[ADestPos.X+8, ADestPos.Y+1] := WIN2000_FRAME_GRAY;
1077   ADest.Pixels[ADestPos.X+9, ADestPos.Y+1] := WIN2000_FRAME_GRAY;
1078   ADest.Pixels[ADestPos.X+3, ADestPos.Y+1] := WIN2000_FRAME_GRAY;
1079   ADest.Pixels[ADestPos.X+2, ADestPos.Y+1] := WIN2000_FRAME_GRAY;
1080   ADest.Pixels[ADestPos.X+1, ADestPos.Y+2] := WIN2000_FRAME_GRAY;
1081   ADest.Pixels[ADestPos.X+1, ADestPos.Y+3] := WIN2000_FRAME_GRAY;
1082   ADest.Pixels[ADestPos.X, ADestPos.Y+4] := WIN2000_FRAME_GRAY;
1083   ADest.Pixels[ADestPos.X, ADestPos.Y+5] := WIN2000_FRAME_GRAY;
1084   ADest.Pixels[ADestPos.X, ADestPos.Y+6] := WIN2000_FRAME_GRAY;
1085   ADest.Pixels[ADestPos.X, ADestPos.Y+7] := WIN2000_FRAME_GRAY;
1086   ADest.Pixels[ADestPos.X+1, ADestPos.Y+8] := WIN2000_FRAME_GRAY;
1087   ADest.Pixels[ADestPos.X+1, ADestPos.Y+9] := WIN2000_FRAME_GRAY;
1088   // Dark area
1089   ADest.Pixels[ADestPos.X+4, ADestPos.Y+1] := WIN2000_FRAME_DARK_GRAY;
1090   ADest.Pixels[ADestPos.X+5, ADestPos.Y+1] := WIN2000_FRAME_DARK_GRAY;
1091   ADest.Pixels[ADestPos.X+6, ADestPos.Y+1] := WIN2000_FRAME_DARK_GRAY;
1092   ADest.Pixels[ADestPos.X+7, ADestPos.Y+1] := WIN2000_FRAME_DARK_GRAY;
1093   ADest.Pixels[ADestPos.X+8, ADestPos.Y+2] := WIN2000_FRAME_DARK_GRAY;
1094   ADest.Pixels[ADestPos.X+9, ADestPos.Y+2] := WIN2000_FRAME_DARK_GRAY;
1095   ADest.Pixels[ADestPos.X+3, ADestPos.Y+2] := WIN2000_FRAME_DARK_GRAY;
1096   ADest.Pixels[ADestPos.X+2, ADestPos.Y+2] := WIN2000_FRAME_DARK_GRAY;
1097   ADest.Pixels[ADestPos.X+2, ADestPos.Y+3] := WIN2000_FRAME_DARK_GRAY;
1098   ADest.Pixels[ADestPos.X+1, ADestPos.Y+4] := WIN2000_FRAME_DARK_GRAY;
1099   ADest.Pixels[ADestPos.X+1, ADestPos.Y+5] := WIN2000_FRAME_DARK_GRAY;
1100   ADest.Pixels[ADestPos.X+1, ADestPos.Y+6] := WIN2000_FRAME_DARK_GRAY;
1101   ADest.Pixels[ADestPos.X+1, ADestPos.Y+7] := WIN2000_FRAME_DARK_GRAY;
1102   ADest.Pixels[ADestPos.X+2, ADestPos.Y+8] := WIN2000_FRAME_DARK_GRAY;
1103   // Light area
1104   ADest.Pixels[ADestPos.X+9, ADestPos.Y+3] := WIN2000_FRAME_LIGHT_GRAY;
1105   ADest.Pixels[ADestPos.X+10, ADestPos.Y+4] := WIN2000_FRAME_LIGHT_GRAY;
1106   ADest.Pixels[ADestPos.X+10, ADestPos.Y+5] := WIN2000_FRAME_LIGHT_GRAY;
1107   ADest.Pixels[ADestPos.X+10, ADestPos.Y+6] := WIN2000_FRAME_LIGHT_GRAY;
1108   ADest.Pixels[ADestPos.X+10, ADestPos.Y+7] := WIN2000_FRAME_LIGHT_GRAY;
1109   ADest.Pixels[ADestPos.X+9, ADestPos.Y+8] := WIN2000_FRAME_LIGHT_GRAY;
1110   ADest.Pixels[ADestPos.X+9, ADestPos.Y+9] := WIN2000_FRAME_LIGHT_GRAY;
1111   ADest.Pixels[ADestPos.X+8, ADestPos.Y+9] := WIN2000_FRAME_LIGHT_GRAY;
1112   ADest.Pixels[ADestPos.X+7, ADestPos.Y+10] := WIN2000_FRAME_LIGHT_GRAY;
1113   ADest.Pixels[ADestPos.X+6, ADestPos.Y+10] := WIN2000_FRAME_LIGHT_GRAY;
1114   ADest.Pixels[ADestPos.X+5, ADestPos.Y+10] := WIN2000_FRAME_LIGHT_GRAY;
1115   ADest.Pixels[ADestPos.X+4, ADestPos.Y+10] := WIN2000_FRAME_LIGHT_GRAY;
1116   ADest.Pixels[ADestPos.X+3, ADestPos.Y+9] := WIN2000_FRAME_LIGHT_GRAY;
1117   ADest.Pixels[ADestPos.X+2, ADestPos.Y+9] := WIN2000_FRAME_LIGHT_GRAY;
1118   // white area
1119   ADest.Pixels[ADestPos.X+10, ADestPos.Y+2] := WIN2000_FRAME_WHITE;
1120   ADest.Pixels[ADestPos.X+10, ADestPos.Y+3] := WIN2000_FRAME_WHITE;
1121   ADest.Pixels[ADestPos.X+10, ADestPos.Y+8] := WIN2000_FRAME_WHITE;
1122   ADest.Pixels[ADestPos.X+10, ADestPos.Y+9] := WIN2000_FRAME_WHITE;
1123   ADest.Pixels[ADestPos.X+9, ADestPos.Y+10] := WIN2000_FRAME_WHITE;
1124   ADest.Pixels[ADestPos.X+8, ADestPos.Y+10] := WIN2000_FRAME_WHITE;
1125   ADest.Pixels[ADestPos.X+3, ADestPos.Y+10] := WIN2000_FRAME_WHITE;
1126   ADest.Pixels[ADestPos.X+2, ADestPos.Y+10] := WIN2000_FRAME_WHITE;
1127   ADest.Pixels[ADestPos.X+3, ADestPos.Y+3] := WIN2000_FRAME_WHITE;
1128   ADest.Pixels[ADestPos.X+3, ADestPos.Y+8] := WIN2000_FRAME_WHITE;
1129   ADest.Pixels[ADestPos.X+8, ADestPos.Y+3] := WIN2000_FRAME_WHITE;
1130   ADest.Pixels[ADestPos.X+8, ADestPos.Y+8] := WIN2000_FRAME_WHITE;
1131 
1132   // The Tickmark
1133   if csfOn in AState then
1134   begin
1135     ADest.Pen.Style := psSolid;
1136     ADest.Pen.Color := clBlack;
1137     ADest.Rectangle(ADestPos.X+4, ADestPos.Y+5, ADestPos.X+8, ADestPos.Y+7);
1138     ADest.Rectangle(ADestPos.X+5, ADestPos.Y+4, ADestPos.X+7, ADestPos.Y+8);
1139   end;
1140 end;
1141 
1142 procedure TCDDrawerCommon.DrawRadioButton(ADest: TCanvas;
1143   ASize: TSize; AState: TCDControlState; AStateEx: TCDControlStateEx);
1144 var
1145   lColor: TColor;
1146   lCircleHeight: Integer;
1147   lTextHeight, lTextY: Integer;
1148 begin
1149   lCircleHeight := GetMeasures(TCDRADIOBUTTON_CIRCLE_HEIGHT);
1150 
1151   // Background
1152   lColor := AStateEx.ParentRGBColor;
1153   ADest.Brush.Color := lColor;
1154   ADest.Brush.Style := bsSolid;
1155   ADest.Pen.Style := psClear;
1156   ADest.FillRect(0, 0, ASize.cx, ASize.cy);
1157 
1158   // The radiobutton circle itself
1159   DrawRadioButtonCircle(ADest, Point(0, 0), ASize, AState, AStateEx);
1160 
1161   // The text selection
1162   if csfHasFocus in AState then
1163     DrawFocusRect(ADest, Point(lCircleHeight+3, 0),
1164       Size(ASize.cx-lCircleHeight-3, ASize.cy));
1165 
1166   // Now the text
1167   ADest.Brush.Style := bsClear;
1168   ADest.Font.Assign(AStateEx.Font);
1169   lTextHeight := ADest.TextHeight(cddTestStr);
1170   // put the text in the center
1171   if lCircleHeight > lTextHeight then lTextY := (lCircleHeight - ADest.TextHeight(cddTestStr)) div 2
1172   else lTextY := 0;
1173   lTextY := Max(0, lTextY - 1);
1174   ADest.TextOut(lCircleHeight+5, lTextY, AStateEx.Caption);
1175 end;
1176 
1177 procedure TCDDrawerCommon.DrawComboBox(ADest: TCanvas; ASize: TSize;
1178   AState: TCDControlState; AStateEx: TCDEditStateEx);
1179 begin
1180   // First the edit, with a margin on the right for the button
1181   AStateEx.RightTextMargin := ASize.CY;
1182   DrawEdit(ADest, ASize, AState, AStateEx);
1183 
1184   // Now the button
1185   DrawButtonWithArrow(ADest, Point(ASize.CX - ASize.CY, 0), Size(ASize.CY, ASize.CY),
1186     AStateEx.ExtraButtonState);
1187 end;
1188 
1189 procedure TCDDrawerCommon.DrawScrollBar(ADest: TCanvas;
1190   ASize: TSize; AState: TCDControlState; AStateEx: TCDPositionedCStateEx);
1191 var
1192   lPos: TPoint;
1193   lSize: TSize;
1194   lArrowState: TCDControlState;
1195 begin
1196   // Background
1197   ADest.Brush.Color := WIN2000_SCROLLBAR_BACKGROUND;
1198   ADest.Brush.Style := bsSolid;
1199   ADest.Pen.Style := psSolid;
1200   ADest.Pen.Color := WIN2000_SCROLLBAR_BACKGROUND;
1201   ADest.Rectangle(0, 0, ASize.cx, ASize.cy);
1202 
1203   // Left/Top button
1204   lPos := Point(0, 0);
1205 
1206   if csfHorizontal in AState then
1207     lSize := Size(GetMeasures(TCDSCROLLBAR_BUTTON_WIDTH), ASize.CY)
1208   else lSize := Size(ASize.CX, GetMeasures(TCDSCROLLBAR_BUTTON_WIDTH));
1209 
1210   ADest.Brush.Color := Palette.BtnFace;
1211   ADest.Brush.Style := bsSolid;
1212   ADest.Rectangle(Bounds(lPos.X, lPos.Y, lSize.cx, lSize.cy));
1213   if csfLeftArrow in AState then
1214   begin
1215     DrawSunkenFrame(ADest, lPos, lSize);
1216     lArrowState := [csfSunken];
1217   end
1218   else
1219   begin
1220     DrawRaisedFrame(ADest, lPos, lSize);
1221     lArrowState := [];
1222   end;
1223 
1224   if csfHorizontal in AState then
1225     DrawArrow(ADest, Point(lPos.X+5, lPos.Y+5), [csfLeftArrow]+lArrowState)
1226   else DrawArrow(ADest, Point(lPos.X+5, lPos.Y+5), [csfUpArrow]+lArrowState);
1227 
1228   // Right/Bottom button
1229   if csfHorizontal in AState then
1230     lPos.X := lPos.X+ASize.CX-GetMeasures(TCDSCROLLBAR_BUTTON_WIDTH)
1231   else
1232     lPos.Y := lPos.Y+ASize.CY-GetMeasures(TCDSCROLLBAR_BUTTON_WIDTH);
1233   ADest.Brush.Color := Palette.BtnFace;
1234   ADest.Brush.Style := bsSolid;
1235   ADest.Rectangle(Bounds(lPos.X, lPos.Y, lSize.cx, lSize.cy));
1236   if csfRightArrow in AState then
1237   begin
1238     DrawSunkenFrame(ADest, lPos, lSize);
1239     lArrowState := [csfSunken];
1240   end
1241   else
1242   begin
1243     DrawRaisedFrame(ADest, lPos, lSize);
1244     lArrowState := [];
1245   end;
1246 
1247   if csfHorizontal in AState then
1248     DrawArrow(ADest, Point(lPos.X+5, lPos.Y+5), [csfRightArrow] + lArrowState)
1249   else DrawArrow(ADest, Point(lPos.X+5, lPos.Y+5), [csfDownArrow] + lArrowState);
1250 
1251   // The slider
1252   lPos := Point(0, 0);
1253   if csfHorizontal in AState then
1254   begin
1255     if AStateEx.FloatPageSize > 0 then lSize.cx := Round(
1256       AStateEx.FloatPageSize * (ASize.cx - GetMeasures(TCDSCROLLBAR_BUTTON_WIDTH) * 2));
1257     if lSize.cx < 5 then lSize.cx := 5;
1258 
1259     lPos.X := Round(GetMeasures(TCDSCROLLBAR_BUTTON_WIDTH)
1260       + AStateEx.FloatPos * (ASize.cx - GetMeasures(TCDSCROLLBAR_BUTTON_WIDTH) * 2 - lSize.cx));
1261   end
1262   else
1263   begin
1264     if AStateEx.FloatPageSize > 0 then lSize.cy := Round(
1265       AStateEx.FloatPageSize * (ASize.cy - GetMeasures(TCDSCROLLBAR_BUTTON_WIDTH) * 2));
1266     if lSize.cy < 5 then lSize.cy := 5;
1267 
1268     lPos.Y := Round(GetMeasures(TCDSCROLLBAR_BUTTON_WIDTH)
1269       + AStateEx.FloatPos * (ASize.cy - GetMeasures(TCDSCROLLBAR_BUTTON_WIDTH) * 2 - lSize.cy));
1270   end;
1271   ADest.Brush.Color := Palette.BtnFace;
1272   ADest.Brush.Style := bsSolid;
1273   ADest.Rectangle(Bounds(lPos.X, lPos.Y, lSize.cx, lSize.cy));
1274   DrawRaisedFrame(ADest, lPos, lSize);
1275 end;
1276 
1277 procedure TCDDrawerCommon.DrawGroupBox(ADest: TFPCustomCanvas;
1278   ADestPos: TPoint; ASize: TSize; AState: TCDControlState; AStateEx: TCDControlStateEx);
1279 var
1280   FCaptionMiddle: integer = 0;
1281   lTextSize: TSize;
1282   lCaption: String;
1283 begin
1284   if ADest is TCanvas then FCaptionMiddle := (ADest as TCanvas).TextHeight(cddTestStr) div 2;
1285   if FCaptionMiddle = 0 then FCaptionMiddle := AStateEx.Font.Size div 2;
1286   if FCaptionMiddle = 0 then FCaptionMiddle := 5;
1287 
1288   // Background
1289   ADest.Brush.FPColor := AStateEx.FPParentRGBColor;
1290   ADest.Brush.Style := bsSolid;
1291   ADest.Pen.Style := psSolid;
1292   ADest.Pen.FPColor := AStateEx.FPParentRGBColor;
1293   ADest.Rectangle(0, 0, ASize.cx, ASize.cy);
1294 
1295   // frame
1296   ADest.Pen.FPColor := TColorToFPColor(WIN2000_FRAME_WHITE);
1297   ADest.Pen.Style := psSolid;
1298   ADest.Brush.Style := bsClear;
1299   ADest.Rectangle(Bounds(1, 1+FCaptionMiddle, ASize.cx-1, ASize.cy-1-FCaptionMiddle));
1300   ADest.Pen.FPColor := TColorToFPColor(WIN2000_FRAME_GRAY);
1301   ADest.Rectangle(Bounds(0, FCaptionMiddle, ASize.cx-1, ASize.cy-1-FCaptionMiddle));
1302   if ADest is TCanvas then
1303   begin
1304     (ADest as TCanvas).Pixels[0, ASize.cy-1] := WIN2000_FRAME_WHITE;
1305     (ADest as TCanvas).Pixels[ASize.cx-1, FCaptionMiddle] := WIN2000_FRAME_WHITE;
1306   end;
1307 
1308   // ToDo: Make the caption smaller if it is too big
1309   lCaption := AStateEx.Caption;
1310   if ADest is TCanvas then lTextSize := (ADest as TCanvas).TextExtent(lCaption)
1311   else lTextSize := Size(50, AStateEx.Font.Size);
1312 
1313   // fill the text background
1314   ADest.Brush.Style := bsSolid;
1315   ADest.Brush.FPColor := AStateEx.FPParentRGBColor;
1316   ADest.Pen.Style := psClear;
1317   ADest.Rectangle(Bounds(FCaptionMiddle, 0, lTextSize.cx+5, lTextSize.cy));
1318 
1319   // paint text
1320   ADest.Pen.Style := psClear;
1321   ADest.Brush.Style := bsClear;
1322   if ADest is TCanvas then ADest.TextOut(FCaptionMiddle+3, 0, lCaption);
1323 end;
1324 
1325 procedure TCDDrawerCommon.DrawPanel(ADest: TCanvas; ASize: TSize;
1326   AState: TCDControlState; AStateEx: TCDPanelStateEx);
1327 var
1328   NextRectFactor: Integer = 0;
1329   //TS : TTextStyle;
1330 begin
1331   // Background
1332   ADest.Brush.Color := Palette.BtnFace;
1333   ADest.Brush.Style := bsSolid;
1334   ADest.Pen.Style := psClear;
1335   ADest.FillRect(0, 0, ASize.cx, ASize.cy);
1336 
1337   // The outter frame
1338 
1339   // if BevelOuter is set then draw a frame with BevelWidth
1340   if (AStateEx.BevelOuter <> bvNone) then
1341   begin
1342     NextRectFactor := AStateEx.BevelWidth;
1343     DrawFrame3d(ADest, Point(0, 0), ASize, AStateEx.BevelWidth, AStateEx.BevelOuter); // Note: Frame3D inflates ARect
1344   end;
1345 
1346   ASize.cx := ASize.cx - NextRectFactor*2;
1347   ASize.cy := ASize.cy - NextRectFactor*2;
1348 
1349   // if BevelInner is set then skip the BorderWidth and draw a frame with BevelWidth
1350   if (AStateEx.BevelInner <> bvNone) then
1351     DrawFrame3d(ADest, Point(NextRectFactor, NextRectFactor), ASize, AStateEx.BevelWidth, AStateEx.BevelInner); // Note: Frame3D inflates ARect
1352 
1353   {if Caption <> '' then
1354   begin
1355     TS := Canvas.TextStyle;
1356     TS.Alignment := BidiFlipAlignment(Self.Alignment, UseRightToLeftAlignment);
1357     if BiDiMode<>bdLeftToRight then
1358       TS.RightToLeft:= True;
1359     TS.Layout:= tlCenter;
1360     TS.Opaque:= false;
1361     TS.Clipping:= false;
1362     TS.SystemFont:=Canvas.Font.IsDefault;
1363     if not Enabled then
1364     begin
1365       Canvas.Font.Color := clBtnHighlight;
1366       OffsetRect(ARect, 1, 1);
1367       Canvas.TextRect(ARect, ARect.Left, ARect.Top, Caption, TS);
1368       Canvas.Font.Color := clBtnShadow;
1369       OffsetRect(ARect, -1, -1);
1370     end
1371     else
1372       Canvas.Font.Color := Font.Color;
1373 
1374     Canvas.TextRect(ARect,ARect.Left,ARect.Top, Caption, TS);
1375   end;}
1376 end;
1377 
1378 procedure TCDDrawerCommon.DrawStaticText(ADest: TCanvas;
1379   ASize: TSize; AState: TCDControlState; AStateEx: TCDControlStateEx);
1380 var
1381   lColor: TColor;
1382 begin
1383   // Background
1384   lColor := AStateEx.ParentRGBColor;
1385   ADest.Brush.Color := lColor;
1386   ADest.Brush.Style := bsSolid;
1387   ADest.Pen.Style := psClear;
1388   ADest.FillRect(0, 0, ASize.cx, ASize.cy);
1389 
1390   // Now the text
1391   ADest.Brush.Style := bsClear;
1392   ADest.Font.Assign(AStateEx.Font);
1393   ADest.TextOut(0, 0, AStateEx.Caption);
1394 end;
1395 
1396 procedure TCDDrawerCommon.DrawTrackBar(ADest: TCanvas;
1397   ASize: TSize; AState: TCDControlState; AStateEx: TCDPositionedCStateEx);
1398 var
1399   StepsCount, i: Integer;
1400   lTickmarkLeft, lTickmarkTop: integer; // for drawing the decorative bars
1401   CDBarSpacing: Integer;
1402   pStepWidth, lTickmarkLeftFloat: Double;
1403   lPoint: TPoint;
1404   lSize, lMeasureSize: TSize;
1405   lValue5, lValue11: Integer;
1406 begin
1407   lValue5 := DPIAdjustment(5);
1408   lValue11 := DPIAdjustment(11);
1409   // The orientation i
1410   if csfHorizontal in AState then lMeasureSize := ASize
1411   else lMeasureSize := Size(ASize.CY, ASize.CX);
1412 
1413   CDBarSpacing := GetMeasures(TCDTRACKBAR_LEFT_SPACING) + GetMeasures(TCDTRACKBAR_RIGHT_SPACING);
1414 
1415   // Preparations
1416   StepsCount := AStateEx.PosCount;
1417   if StepsCount > 0 then pStepWidth := (lMeasureSize.cx - CDBarSpacing) / (StepsCount-1)
1418   else pStepWidth := 0.0;
1419 
1420   // Background
1421 
1422   ADest.Brush.Color := AStateEx.ParentRGBColor;
1423   ADest.Brush.Style := bsSolid;
1424   ADest.Pen.Style := psSolid;
1425   ADest.Pen.Color := AStateEx.ParentRGBColor;
1426   ADest.Rectangle(0, 0, ASize.cx, ASize.cy);
1427 
1428   // Draws the frame and its inner white area
1429   if csfHorizontal in AState then
1430   begin
1431     lPoint := Point(GetMeasures(TCDTRACKBAR_LEFT_SPACING),
1432        GetMeasures(TCDTRACKBAR_TOP_SPACING));
1433     lSize := Size(ASize.CX - CDBarSpacing, GetMeasures(TCDTRACKBAR_FRAME_HEIGHT));
1434   end
1435   else
1436   begin
1437     lPoint := Point(GetMeasures(TCDTRACKBAR_TOP_SPACING),
1438        GetMeasures(TCDTRACKBAR_LEFT_SPACING));
1439     lSize := Size(GetMeasures(TCDTRACKBAR_FRAME_HEIGHT), ASize.CY - CDBarSpacing);
1440   end;
1441   ADest.Brush.Color := Palette.Window;
1442   ADest.Pen.Style := psClear;
1443   ADest.Rectangle(Bounds(lPoint.X, lPoint.Y, lSize.cx, lSize.cy));
1444   DrawSunkenFrame(ADest, lPoint, lSize);
1445 
1446   // Draws the tickmarks and also the slider button
1447   lTickmarkLeft := GetMeasures(TCDTRACKBAR_LEFT_SPACING);
1448   lTickmarkLeftFloat := lTickmarkLeft;
1449   lTickmarkTop := GetMeasures(TCDTRACKBAR_TOP_SPACING) + GetMeasures(TCDTRACKBAR_FRAME_HEIGHT)+5;
1450   ADest.Pen.Style := psSolid;
1451   for i := 0 to StepsCount - 1 do
1452   begin
1453     ADest.Pen.Color := clBlack;
1454     if csfHorizontal in AState then
1455       ADest.Line(lTickmarkLeft, lTickmarkTop, lTickmarkLeft, lTickmarkTop+3)
1456     else
1457       ADest.Line(lTickmarkTop, lTickmarkLeft, lTickmarkTop+3, lTickmarkLeft);
1458 
1459     // Draw the slider
1460     if i = AStateEx.Position then
1461       DrawSlider(ADest,
1462         Point(lTickmarkLeft-lValue5, GetMeasures(TCDTRACKBAR_TOP_SPACING)-2),
1463         Size(lValue11, GetMeasures(TCDTRACKBAR_FRAME_HEIGHT)+lValue5), AState);
1464 
1465     lTickmarkLeftFloat := lTickmarkLeftFloat + pStepWidth;
1466     lTickmarkLeft := Round(lTickmarkLeftFloat);
1467   end;
1468 
1469   // Draw the focus
1470   if csfHasFocus in AState then
1471     DrawFocusRect(ADest,
1472       Point(1, 1),
1473       Size(ASize.CX - 2, ASize.CY - 2));
1474 end;
1475 
1476 // Felipe: Smooth=False is not supported for now
1477 procedure TCDDrawerCommon.DrawProgressBar(ADest: TCanvas;
1478   ASize: TSize; AState: TCDControlState; AStateEx: TCDProgressBarStateEx);
1479 var
1480   lProgPos, lProgMult: TPoint;
1481   lProgSize: TSize;
1482   lProgWidth: Integer;
1483 begin
1484   // Inside area, there is no background because the control occupies the entire area
1485   ADest.Brush.Color := WIN2000_BTNFACE;
1486   ADest.Brush.Style := bsSolid;
1487   ADest.Pen.Style := psClear;
1488   ADest.Rectangle(0, 0, ASize.cx, ASize.cy);
1489 
1490   // The Frame
1491   DrawShallowSunkenFrame(ADest, Point(0, 0), ASize);
1492 
1493   // Preparations to have 1 code for all orientations
1494   lProgSize := Size(ASize.cx-4, ASize.cy-4);
1495   if csfHorizontal in AState then
1496   begin
1497     lProgPos := Point(2, 2);
1498     lProgMult := Point(1, 0);
1499     lProgWidth := lProgSize.cx;
1500   end
1501   else if csfVertical in AState then
1502   begin
1503     lProgPos := Point(2, ASize.cy-2);
1504     lProgMult := Point(0, -1);
1505     lProgWidth := lProgSize.cy;
1506   end else if csfRightToLeft in AState then
1507   begin
1508     lProgPos := Point(ASize.cx-2, 2);
1509     lProgMult := Point(-1, 0);
1510     lProgWidth := lProgSize.cx;
1511   end
1512   else
1513   begin
1514     lProgPos := Point(2, 2);
1515     lProgMult := Point(0, 1);
1516     lProgWidth := lProgSize.cy;
1517   end;
1518   lProgWidth := Round(lProgWidth * AStateEx.PercentPosition);
1519 
1520   // Draws the filling
1521   ADest.Pen.Color := WIN2000_PROGRESSBAR_BLUE;
1522   ADest.Pen.Style := psSolid;
1523   ADest.Brush.Color := WIN2000_PROGRESSBAR_BLUE;
1524   ADest.Brush.Style := bsSolid;
1525   ADest.Rectangle(
1526     lProgPos.X,
1527     lProgPos.Y,
1528     lProgPos.X+lProgWidth*lProgMult.X+lProgSize.cx*Abs(lProgMult.Y),
1529     lProgPos.Y+lProgWidth*lProgMult.Y+lProgSize.cy*Abs(lProgMult.X));
1530 end;
1531 
1532 procedure TCDDrawerCommon.DrawListView(ADest: TCanvas;
1533   ASize: TSize; AState: TCDControlState; AStateEx: TCDListViewStateEx);
1534 begin
1535   // Inside area, there is no background because the control occupies the entire area
1536   ADest.Brush.Color := Palette.Window;
1537   ADest.Brush.Style := bsSolid;
1538   ADest.Pen.Style := psClear;
1539   ADest.Rectangle(0, 0, ASize.cx, ASize.cy);
1540 
1541   // The frame
1542   DrawSunkenFrame(ADest, Point(0, 0), ASize);
1543 
1544   // The contents depend on the view style
1545   case AStateEx.ViewStyle of
1546   vsReport: DrawReportListView(ADest, Point(0, 0), ASize, AState, AStateEx);
1547   end;
1548 end;
1549 
1550 procedure TCDDrawerCommon.DrawReportListView(ADest: TCanvas; ADestPos: TPoint;
1551   ASize: TSize; AState: TCDControlState; AStateEx: TCDListViewStateEx);
1552 var
1553   lColumn: TListColumn;
1554   i, j: Integer;
1555   lCurPos: TPoint;
1556   lItemSize: TSize;
1557   lItemCount: Integer;
1558   lCurItem: TCDListItems;
1559 begin
1560   lCurPos := Point(2, 2);
1561   lItemCount := AStateEx.Items.GetItemCount();
1562 
1563   // i is an column zero-based index
1564   for i := AStateEx.FirstVisibleColumn to AStateEx.Columns.Count-1 do
1565   begin
1566     lColumn := AStateEx.Columns[i];
1567     lCurPos.Y := 2;
1568 
1569     // get the column width
1570     if lColumn.AutoSize then
1571     begin
1572       lItemSize.cx := ADest.GetTextWidth(lColumn.Caption)
1573         + GetMeasures(TCDLISTVIEW_COLUMN_LEFT_SPACING)
1574         + GetMeasures(TCDLISTVIEW_COLUMN_RIGHT_SPACING);
1575       if (lColumn.MinWidth > 0) and (lItemSize.cx < lColumn.MinWidth) then lItemSize.cx := lColumn.MinWidth
1576       else if (lColumn.MaxWidth > 0) and (lItemSize.cx > lColumn.MaxWidth) then lItemSize.cx := lColumn.MaxWidth;
1577     end
1578     else lItemSize.cx := lColumn.Width;
1579 
1580     // line height measure
1581     lItemSize.cy := ADest.TextHeight(cddTestStr)
1582       + GetMeasures(TCDLISTVIEW_LINE_TOP_SPACING)
1583       + GetMeasures(TCDLISTVIEW_LINE_BOTTOM_SPACING);
1584 
1585     // Draw the column header
1586     if AStateEx.ShowColumnHeader then
1587     begin
1588       // Foreground
1589       ADest.Brush.Style := bsSolid;
1590       ADest.Brush.Color := Palette.BtnFace; // WIN2000_BTNFACE
1591       ADest.Pen.Style := psClear;
1592       ADest.FillRect(Bounds(lCurPos.X, lCurPos.Y, lItemSize.cx, lItemSize.cy));
1593 
1594       // Frame
1595       DrawRaisedFrame(ADest, lCurPos, lItemSize);
1596 
1597       // The caption
1598       ADest.Brush.Style := bsClear;
1599       ADest.Pen.Style := psClear;
1600       ADest.TextOut(
1601         lCurPos.X+GetMeasures(TCDLISTVIEW_COLUMN_TEXT_LEFT_SPACING),
1602         lCurPos.Y+GetMeasures(TCDLISTVIEW_LINE_TOP_SPACING),
1603         lColumn.Caption);
1604 
1605       Inc(lCurPos.Y, lItemSize.cy);
1606     end;
1607 
1608     // j is a zero-based index for lines, ignoring the header
1609     // Draw all items until we get out of the visible area
1610     for j := 0 to lItemCount-1 do
1611     begin
1612       lCurItem := nil;
1613       if i = 0 then lCurItem := AStateEx.Items.GetItem(j)
1614       else if AStateEx.Items.GetItem(j).GetItemCount >= i then
1615         lCurItem := AStateEx.Items.GetItem(j).GetItem(i-1);
1616 
1617       if lCurItem = nil then Continue;
1618 
1619       // Draw the item
1620       DrawReportListViewItem(ADest, lCurPos, lItemSize, lCurItem, AState, AStateEx);
1621 
1622       Inc(lCurPos.Y, lItemSize.CY);
1623     end;
1624 
1625     Inc(lCurPos.X, lItemSize.CX);
1626   end;
1627 end;
1628 
1629 procedure TCDDrawerCommon.DrawReportListViewItem(ADest: TCanvas;
1630   ADestPos: TPoint; ASize: TSize; ACurItem: TCDListItems; AState: TCDControlState;
1631   AStateEx: TCDListViewStateEx);
1632 begin
1633   ADest.Brush.Style := bsClear;
1634   ADest.Pen.Style := psClear;
1635   ADest.TextOut(
1636     ADestPos.X+GetMeasures(TCDLISTVIEW_COLUMN_TEXT_LEFT_SPACING),
1637     ADestPos.Y+GetMeasures(TCDLISTVIEW_LINE_TOP_SPACING),
1638     ACurItem.Caption);
1639 end;
1640 
1641 procedure TCDDrawerCommon.DrawToolBar(ADest: TCanvas; ASize: TSize;
1642   AState: TCDControlState; AStateEx: TCDToolBarStateEx);
1643 var
1644   lX, lY, lX2: Integer;
1645   lItemSize: TSize;
1646   i: Integer;
1647   lCurItem: TCDToolBarItem;
1648   lItemState: TCDControlState = [];
1649 begin
1650   // Background
1651   ADest.Pen.Style := psSolid;
1652   ADest.Pen.Color := AStateEx.ParentRGBColor;
1653   ADest.Brush.Style := bsSolid;
1654   ADest.Brush.Color := AStateEx.ParentRGBColor;
1655   ADest.Rectangle(0, 0, ASize.cx, ASize.cy);
1656 
1657   // Items
1658   lX := GetMeasures(TCDTOOLBAR_ITEM_SPACING);
1659   lY := GetMeasures(TCDTOOLBAR_ITEM_SPACING);
1660   lItemSize.CY := AStateEx.ToolBarHeight - GetMeasures(TCDTOOLBAR_ITEM_SPACING) * 2;
1661   for i := 0 to AStateEx.Items.Count-1 do
1662   begin
1663     lCurItem := TCDToolBarItem(AStateEx.Items[i]);
1664 
1665     // make space for the arrow if necessary
1666     if lCurItem.Kind = tikDropDownButton then
1667       lItemSize.CX := lCurItem.Width - GetMeasures(TCDTOOLBAR_ITEM_ARROW_RESERVED_WIDTH)
1668     else
1669       lItemSize.CX := lCurItem.Width;
1670 
1671     lCurItem.SubpartKind := tiskMain;
1672     DrawToolBarItem(ADest, lItemSize, lCurItem, lX, lY, lCurItem.State, AStateEx);
1673 
1674     if lCurItem.Kind = tikDropDownButton then
1675     begin
1676       lCurItem.SubpartKind := tiskArrow;
1677       lX2 := lX + lCurItem.Width - GetMeasures(TCDTOOLBAR_ITEM_ARROW_RESERVED_WIDTH);
1678       lItemSize.CX := GetMeasures(TCDTOOLBAR_ITEM_ARROW_RESERVED_WIDTH);
1679       DrawToolBarItem(ADest, lItemSize, lCurItem, lX2, lY, lCurItem.State, AStateEx);
1680     end;
1681 
1682     lX := lX + lCurItem.Width;
1683   end;
1684 end;
1685 
1686 procedure TCDDrawerCommon.DrawToolBarItem(ADest: TCanvas; ASize: TSize;
1687   ACurItem: TCDToolBarItem; AX, AY: Integer; AState: TCDControlState; AStateEx: TCDToolBarStateEx);
1688 var
1689   lX, lY1, lY2: Integer;
1690 
1691   procedure DrawToolBarItemBorder();
1692   begin
1693     ADest.Pen.Style := psSolid;
1694     ADest.Pen.Color := $AFAFAF;
1695     ADest.Brush.Style := bsClear;
1696     ADest.Rectangle(Bounds(AX, AY, ASize.cx, ASize.cy));
1697   end;
1698 
1699 begin
1700   // tikDivider is centralized, tikSeparator is left-aligned
1701   case ACurItem.Kind of
1702   tikSeparator, tikDivider:
1703   begin
1704     lX := AX;
1705     if ACurItem.Kind = tikDivider then
1706       lX := AX + ASize.CX div 2 - 1;
1707 
1708     lY1 := AY;
1709     lY2 := AY+ASize.CY;
1710 
1711     ADest.Pen.Style := psSolid;
1712     ADest.Pen.Color := $DCDEE1;
1713     ADest.Line(lX+1, lY1, lX+1, lY2);
1714     ADest.Line(lX+3, lY1, lX+3, lY2);
1715     ADest.Pen.Style := psSolid;
1716     ADest.Pen.Color := $93979E;
1717     ADest.Line(lX+2, lY1, lX+2, lY2);
1718   end;
1719   tikButton, tikCheckButton, tikDropDownButton:
1720   begin
1721     if ACurItem.SubpartKind = tiskArrow then
1722     begin
1723       // Centralize the arrow in the available space
1724       lX := AX + ASize.CX div 2 - GetMeasures(TCDTOOLBAR_ITEM_ARROW_WIDTH) div 2;
1725       lY1 := AY + ASize.CY div 2 - GetMeasures(TCDTOOLBAR_ITEM_ARROW_WIDTH) div 2;
1726       DrawArrow(ADest, Point(lX, lY1), [csfDownArrow], GetMeasures(TCDTOOLBAR_ITEM_ARROW_WIDTH));
1727       Exit;
1728     end;
1729 
1730     if csfSunken in AState then
1731     begin
1732       ADest.GradientFill(Bounds(AX, AY, ASize.CX, ASize.CY),
1733         $C4C4C4, $DBDBDB, gdVertical);
1734       DrawToolBarItemBorder();
1735     end
1736     else if csfMouseOver in AState then
1737     begin
1738       ADest.GradientFill(Bounds(AX, AY, ASize.CX, ASize.CY),
1739         $E3E3E3, $F7F7F7, gdVertical);
1740       DrawToolBarItemBorder();
1741     end;
1742   end;
1743   end;
1744 end;
1745 
1746 procedure TCDDrawerCommon.DrawCTabControl(ADest: TCanvas;
1747   ASize: TSize; AState: TCDControlState; AStateEx: TCDCTabControlStateEx);
1748 begin
1749   // Background
1750   ADest.Pen.Style := psSolid;
1751   ADest.Pen.Color := AStateEx.ParentRGBColor;
1752   ADest.Brush.Style := bsSolid;
1753   ADest.Brush.Color := AStateEx.ParentRGBColor;
1754   ADest.Rectangle(0, 0, ASize.cx, ASize.cy);
1755 
1756   // frame
1757   DrawCTabControlFrame(ADest, Point(0, 0), ASize, AState, AStateEx);
1758 
1759   // Tabs
1760   ADest.Font.Assign(AStateEx.Font);
1761   DrawTabs(ADest, Point(0, 0), ASize, AState, AStateEx);
1762 end;
1763 
1764 procedure TCDDrawerCommon.DrawCTabControlFrame(ADest: TCanvas;
1765   ADestPos: TPoint; ASize: TSize; AState: TCDControlState;
1766   AStateEx: TCDCTabControlStateEx);
1767 var
1768   CaptionHeight: Integer;
1769 begin
1770   if AStateEx.TabCount = 0 then CaptionHeight := 0
1771   else CaptionHeight := GetMeasuresEx(ADest, TCDCTABCONTROL_TAB_HEIGHT, AState, AStateEx);
1772 
1773   DrawRaisedFrame(ADest, Point(0, CaptionHeight), Size(ASize.cx, ASize.cy-CaptionHeight));
1774 end;
1775 
1776 procedure TCDDrawerCommon.DrawTabSheet(ADest: TCanvas; ADestPos: TPoint;
1777   ASize: TSize; AState: TCDControlState; AStateEx: TCDCTabControlStateEx);
1778 begin
1779   ADest.Brush.Color := AStateEx.RGBColor;
1780   ADest.Brush.Style := bsSolid;
1781   ADest.Pen.Style := psSolid;
1782   ADest.Pen.Color := AStateEx.RGBColor;
1783   ADest.Rectangle(0, 0, ASize.cx, ASize.cy);
1784 end;
1785 
1786 procedure TCDDrawerCommon.DrawTabs(ADest: TCanvas; ADestPos: TPoint;
1787   ASize: TSize; AState: TCDControlState; AStateEx: TCDCTabControlStateEx);
1788 var
1789   IsPainting: Boolean = False;
1790   lLastTabIndex, i: Integer;
1791 begin
1792   AStateEx.CurStartLeftPos := 0;
1793   if nboShowAddTabButton in AStateEx.Options then lLastTabIndex := AStateEx.Tabs.Count
1794   else lLastTabIndex := AStateEx.Tabs.Count - 1;
1795 
1796   for i := 0 to lLastTabIndex do
1797   begin
1798     if i = AStateEx.LeftmostTabVisibleIndex then
1799       IsPainting := True;
1800 
1801     if IsPainting then
1802     begin
1803       AStateEx.CurTabIndex := i;
1804       DrawTab(ADest, ADestPos, ASize, AState, AStateEx);
1805       AStateEx.CurStartLeftPos := AStateEx.CurStartLeftPos + GetMeasuresEx(ADest, TCDCTABCONTROL_TAB_WIDTH, AState, AStateEx);
1806     end;
1807   end;
1808 end;
1809 
1810 procedure TCDDrawerCommon.DrawTab(ADest: TCanvas; ADestPos: TPoint;
1811   ASize: TSize; AState: TCDControlState; AStateEx: TCDCTabControlStateEx);
1812 var
1813   IsSelected, IsAddButton: Boolean;
1814   lTabWidth, lTabHeight, lTabTopPos: Integer;
1815   Points: array of TPoint;
1816   lCaption: String;
1817   lTabHeightCorrection: Integer = 0;
1818   lTabRightBorderExtraHeight: Integer = 0;
1819   lCloseButtonPos: TPoint;
1820 begin
1821   IsSelected := AStateEx.TabIndex = AStateEx.CurTabIndex;
1822   IsAddButton := AStateEx.CurTabIndex = AStateEx.Tabs.Count;
1823 
1824   if not IsSelected then lTabHeightCorrection := 3;
1825   if IsSelected then lTabRightBorderExtraHeight := 1;
1826 
1827   lTabTopPos := lTabHeightCorrection;
1828   lTabHeight := GetMeasuresEx(ADest, TCDCTABCONTROL_TAB_HEIGHT, AState, AStateEx)-lTabHeightCorrection;
1829   lTabWidth := GetMeasuresEx(ADest, TCDCTABCONTROL_TAB_WIDTH, AState, AStateEx);
1830 
1831   // Fill the area inside the outer border
1832   // And at the same time fill the white border (part of it will be erased later)
1833   ADest.Pen.Style := psSolid;
1834   ADest.Pen.Color := WIN2000_FRAME_WHITE;
1835   ADest.Brush.Style := bsSolid;
1836   ADest.Brush.Color := AStateEx.RGBColor;
1837   SetLength(Points, 6);
1838   Points[0] := Point(AStateEx.CurStartLeftPos, lTabTopPos+lTabHeight);
1839   Points[1] := Point(AStateEx.CurStartLeftPos, lTabTopPos+2);
1840   Points[2] := Point(AStateEx.CurStartLeftPos+2, lTabTopPos);
1841   Points[3] := Point(AStateEx.CurStartLeftPos+lTabWidth-3, lTabTopPos);
1842   Points[4] := Point(AStateEx.CurStartLeftPos+lTabWidth-1, lTabTopPos+2);
1843   Points[5] := Point(AStateEx.CurStartLeftPos+lTabWidth-1, lTabTopPos+lTabHeight);
1844   ADest.Polygon(Points);
1845 
1846   // Draw the inner border of the top and right sides,
1847   ADest.Pen.Style := psSolid;
1848   ADest.Brush.Style := bsClear;
1849   ADest.Pen.Color := WIN2000_FRAME_LIGHT_GRAY;
1850   ADest.MoveTo(AStateEx.CurStartLeftPos+1, lTabTopPos+lTabHeight-1);
1851   ADest.LineTo(AStateEx.CurStartLeftPos+1, lTabTopPos+2);
1852   ADest.LineTo(AStateEx.CurStartLeftPos+2, lTabTopPos+1);
1853   ADest.LineTo(AStateEx.CurStartLeftPos+lTabWidth-3, lTabTopPos+1);
1854 
1855   // Draw the inner border of the right side
1856   ADest.Pen.Color := WIN2000_FRAME_GRAY;
1857   ADest.MoveTo(AStateEx.CurStartLeftPos+lTabWidth-2, lTabTopPos+2);
1858   ADest.LineTo(AStateEx.CurStartLeftPos+lTabWidth-2, lTabTopPos+lTabHeight+lTabRightBorderExtraHeight);
1859   // Draw the outter border of the right side
1860   ADest.Pen.Color := WIN2000_FRAME_DARK_GRAY;
1861   ADest.MoveTo(AStateEx.CurStartLeftPos+lTabWidth-1, lTabTopPos+2);
1862   ADest.LineTo(AStateEx.CurStartLeftPos+lTabWidth-1, lTabTopPos+lTabHeight+lTabRightBorderExtraHeight);
1863   ADest.Pixels[AStateEx.CurStartLeftPos+lTabWidth-2, lTabTopPos+1] := WIN2000_FRAME_DARK_GRAY;
1864 
1865   if IsSelected then
1866   begin
1867     // If it is selected, add a selection frame
1868     DrawFocusRect(ADest, Point(AStateEx.CurStartLeftPos+3, lTabTopPos+3),
1869       Size(lTabWidth-8, lTabHeight-6));
1870 
1871     // and Clear the bottom area if selected
1872     ADest.Pen.Style := psSolid;
1873     ADest.Pen.Color := AStateEx.RGBColor;
1874     ADest.Line(AStateEx.CurStartLeftPos+1,  lTabTopPos+lTabHeight,
1875       AStateEx.CurStartLeftPos+lTabWidth-2, lTabTopPos+lTabHeight);
1876     ADest.Line(AStateEx.CurStartLeftPos+1,  lTabTopPos+lTabHeight+1,
1877       AStateEx.CurStartLeftPos+lTabWidth-2, lTabTopPos+lTabHeight+1);
1878   end;
1879 
1880   // Now the text
1881   if IsAddButton then lCaption := '+'
1882   else lCaption := AStateEx.Tabs.Strings[AStateEx.CurTabIndex];
1883   ADest.TextOut(AStateEx.CurStartLeftPos+5, lTabTopPos+5, lCaption);
1884 
1885   // Now the close button
1886   if (not IsAddButton) and (nboShowCloseButtons in AStateEx.Options) then
1887   begin
1888     lCloseButtonPos.X := GetMeasuresEx(ADest, TCDCTABCONTROL_CLOSE_BUTTON_POS_X, AState, AStateEx);
1889     lCloseButtonPos.Y := GetMeasuresEx(ADest, TCDCTABCONTROL_CLOSE_BUTTON_POS_Y, AState, AStateEx);
1890     DrawSmallCloseButton(ADest, lCloseButtonPos);
1891   end;
1892 end;
1893 
1894 procedure TCDDrawerCommon.DrawSpinEdit(ADest: TCanvas; ADestPos: TPoint;
1895   ASize: TSize; AState: TCDControlState; AStateEx: TCDSpinStateEx);
1896 begin
1897 
1898 end;
1899 
1900 { TCDListViewDrawerCommon }
1901 
1902 initialization
1903   RegisterDrawer(TCDDrawerCommon.Create, dsCommon);
1904 end.
1905 
1906