1 unit TAChartCombos;
2 
3 {$mode ObjFPC}{$H+}
4 
5 interface
6 
7 uses
8   SysUtils, Graphics, Classes, Controls, StdCtrls, TATypes, TAGraph;
9 
10 type
11   TChartComboMode = (ccmPointerStyle, ccmPenStyle, ccmPenWidth, ccmBrushStyle);
12 
13   TChartComboOptions = set of (
14     ccoNames,           // Show item names in combo
15     ccoPatternBrush,    // Include bsPattern item in brush style mode
16     ccoImageBrush,      // Include bsImage item in brush style mode
17     ccoPatternPen);     // Include psPattern item in pen style mode
18 
19 const
20   DEFAULT_POINTER_STYLE = psCircle;
21   DEFAULT_SYMBOL_WIDTH = 40;
22   DEFAULT_DROPDOWN_COUNT = 24;
23   DEFAULT_OPTIONS = [ccoNames, ccoPatternBrush, ccoPatternPen];
24 
25 type
26   TChartComboBox = class(TCustomComboBox)
27     private
28       FAlignment: TAlignment;
29       FBitmaps: array[TSeriesPointerStyle] of TBitmap;
30       FBrushBitmap: TBitmap;
31       FBrushColor: TColor;
32       FBrushStyle: TBrushStyle;
33       FPenPattern: TPenPattern;
34       FPenColor: TColor;
35       FPenStyle: TPenStyle;
36       FPenWidth: Integer;
37       FMaxPenWidth: Integer;
38       FPointerStyle: TSeriesPointerStyle;
39       FCosmetic: Boolean;
40       FLockItemIndex: Integer;
41       FMode: TChartComboMode;
42       FOptions: TChartComboOptions;
43       FSymbolWidth: Integer;
GetPenPatternnull44       function GetPenPattern: String;
GetSymbolWidthnull45       function GetSymbolWidth: Integer;
46       procedure SetAlignment(const AValue: TAlignment);
47       procedure SetBrushBitmap(const AValue: TBitmap);
48       procedure SetBrushColor(const AValue: TColor);
49       procedure SetCosmetic(const AValue: Boolean);
50       procedure SetMaxPenWidth(const AValue: Integer);
51       procedure SetMode(const AValue: TChartComboMode);
52       procedure SetOptions(const AValue: TChartComboOptions);
53       procedure SetPenColor(const AValue: TColor);
54       procedure SetPenPattern(const AValue: String); overload;
55       procedure SetSelectedBrushStyle(const AValue: TBrushStyle);
56       procedure SetSelectedPenStyle(const AValue: TPenStyle);
57       procedure SetSelectedPenWidth(const AValue: Integer);
58       procedure SetSelectedPointerStyle(const AValue: TSeriesPointerStyle);
59       procedure SetSymbolWidth(const AValue: Integer);
SymbolWidthStorednull60       function SymbolWidthStored: Boolean;
61     protected
62       procedure Change; override;
63       procedure CreateBitmaps(AWidth, AHeight: Integer);
64       procedure DestroyBitmaps;
65       procedure DoAutoAdjustLayout(const AMode: TLayoutAdjustmentPolicy;
66         const AXProportion, AYProportion: Double); override;
67       procedure DrawItem(AIndex: Integer; ARect: TRect; AState: TOwnerDrawState); override;
GetBrushStylenull68       function GetBrushStyle(const AIndex: Integer): TBrushStyle;
GetPenStylenull69       function GetPenStyle(const AIndex: Integer): TPenStyle;
GetPenWidthnull70       function GetPenWidth(const AIndex: Integer): Integer;
GetPointerStylenull71       function GetPointerStyle(AIndex: Integer): TSeriesPointerStyle; inline;
72       procedure PopulateBrushStyles;
73       procedure PopulatePenStyles;
74       procedure PopulatePenWidths;
75       procedure PopulatePointerStyles;
76       procedure RealSetText(const AValue: TCaption); override;
77       procedure SetItemIndex(const AValue: Integer); override;
78     public
79       constructor Create(AOwner: TComponent); override;
80       destructor Destroy; override;
81       procedure SetPenPattern(APen: TPen); overload;
82     published
83       property Alignment: TAlignment read FAlignment write SetAlignment default taLeftJustify;
84       property BrushBitmap: TBitmap read FBrushBitmap write SetBrushBitmap;
85       property BrushColor: TColor read FBrushColor write SetBrushColor default clBlack;
86       property BrushStyle: TBrushStyle read FBrushStyle write SetSelectedBrushStyle default bsSolid;
87       property Cosmetic: Boolean read FCosmetic write SetCosmetic default true;
88       property MaxPenWidth: Integer read FMaxPenWidth write SetMaxPenWidth default 5;
89       property Mode: TChartComboMode read FMode write SetMode default ccmPenStyle;
90       property Options: TChartComboOptions read FOptions write SetOptions default DEFAULT_OPTIONS;
91       property PenPattern: string read GetPenPattern write SetPenPattern;
92       property PenColor: TColor read FPenColor write SetPenColor default clBlack;
93       property PenStyle: TPenStyle read FPenStyle write SetSelectedPenStyle default psSolid;
94       property PenWidth: Integer read FPenWidth write SetSelectedPenWidth default 1;
95       property PointerStyle: TSeriesPointerStyle read FPointerStyle write SetSelectedPointerStyle default DEFAULT_POINTER_STYLE;
96 //      property ShowNames: Boolean read FShowNames write SetShowNames default true;
97       property SymbolWidth: Integer read GetSymbolWidth write SetSymbolWidth stored SymbolWidthStored;
98 
99       property Align;
100       property Anchors;
101       property AutoDropDown;
102       property BidiMode;
103       property BorderSpacing;
104       property Color;
105       property Constraints;
106       property Cursor;
107       property DragCursor;
108       property DragKind;
109       property DragMode;
110       property DropDownCount default DEFAULT_DROPDOWN_COUNT;
111       property Enabled;
112       property Font;
113       property ItemHeight;
114       property ItemIndex;
115       property ItemWidth;
116       property Left;
117       property ParentBidiMode;
118       property ParentColor;
119       property ParentFont;
120       property ParentShowHint;
121       property PopupMenu;
122       property ShowHint;
123       property TabOrder;
124       property TabStop;
125       property Top;
126       property Visible;
127       property Width;
128 
129       property OnChange;
130       property OnChangeBounds;
131       property OnClick;
132       property OnCloseUp;
133       property OnContextPopup;
134       property OnDblClick;
135       property OnDragDrop;
136       property OnDragOver;
137       property OnDrawItem;
138       property OnEndDrag;
139       property OnDropDown;
140       property OnEditingDone;
141       property OnEnter;
142       property OnExit;
143       property OnKeyDown;
144       property OnKeyPress;
145       property OnKeyUp;
146       property OnMeasureItem;
147       property OnMouseDown;
148       property OnMouseEnter;
149       property OnMouseLeave;
150       property OnMouseMove;
151       property OnMouseUp;
152       property OnStartDrag;
153       property OnSelect;
154       property OnUTF8KeyPress;
155     end;
156 
157 procedure Register;
158 
159 
160 implementation
161 
162 uses
163   LCLType, Types, TypInfo, Math, FPCanvas,
164   TAChartStrConsts, TAChartUtils, TADrawUtils, TADrawerCanvas, TACustomSeries,
165   TASeries, TALegend;
166 
167 procedure Register;
168 begin
169   RegisterComponents(CHART_COMPONENT_IDE_PAGE, [
170     //TSeriesPointerStyleCombobox,
171     TChartComboBox
172   ]);
173 end;
174 
GetBrushStyleNamenull175 function GetBrushStyleName(AStyle: TBrushStyle): String;
176 begin
177   case AStyle of
178     bsSolid      : Result := rsBSSolid;
179     bsHorizontal : Result := rsBSHorizontal;
180     bsVertical   : Result := rsBSVertical;
181     bsFDiagonal  : Result := rsBSFDiagonal;
182     bsBDiagonal  : Result := rsBSBDiagonal;
183     bsCross      : Result := rsBSCross;
184     bsDiagCross  : Result := rsBSDiagCross;
185     bsImage      : Result := rsBSImage;
186     bsPattern    : Result := rsBSPattern;
187     else           Result := rsBSClear;
188   end;
189 end;
190 
GetSymbolNamenull191 function GetSymbolName(ASymbol: TSeriesPointerStyle): string;
192 begin
193   case ASymbol of
194     psRectangle    : Result := rsRectangleSymbol;
195     psCircle       : Result := rsCircleSymbol;
196     psCross        : Result := rsCrossSymbol;
197     psDiagCross    : Result := rsDiagCrossSymbol;
198     psStar         : Result := rsStarSymbol;
199     psLowBracket   : Result := rsLowBracketSymbol;
200     psHighBracket  : Result := rsHighBracketSymbol;
201     psLeftTriangle : Result := rsLeftTriangleSymbol;
202     psRightTriangle: Result := rsRightTriangleSymbol;
203     psDiamond      : Result := rsDiamondSymbol;
204     psVertBar      : Result := rsVertBarSymbol;
205     psTriangle     : Result := rsTriangleSymbol;
206     psLeftBracket  : Result := rsLeftBracketSymbol;
207     psRightBracket : Result := rsRightBracketSymbol;
208     psHorBar       : Result := rsHorBarSymbol;
209     psPoint        : Result := rsPointSymbol;
210     psDownTriangle : Result := rsDownTriangleSymbol;
211     psHexagon      : Result := rsHexagonSymbol;
212     psFullStar     : Result := rsFullStarSymbol;
213     else             Result := rsNoSymbol;
214   end;
215 end;
216 
GetPenStyleNamenull217 function GetPenStyleName(AStyle: TPenStyle): String;
218 begin
219   case AStyle of
220     psSolid       : Result := rsPSSolid;
221     psDash        : Result := rsPSDash;
222     psDot         : Result := rsPSDot;
223     psDashDot     : Result := rsPSDashDot;
224     psDashDotDot  : Result := rsPSDashDotDot;
225     psInsideFrame : Result := rsPSInsideFrame;
226     psPattern     : Result := rsPSPattern;
227     else            Result := rsPSClear;
228   end;
229 end;
230 
231 
232 { TChartComboBox }
233 
234 constructor TChartComboBox.Create(AOwner: TComponent);
235 begin
236   inherited Create(AOwner);
237   DropdownCount := DEFAULT_DROPDOWN_COUNT;
238   ReadOnly := true;  // Needed to see the symbol without dropdown.
239   Style := csOwnerDrawFixed;
240   SetLength(FPenPattern, 2);
241   FPenPattern[0] := 1;
242   FPenPattern[1] := 1;
243   FPenColor := clBlack;
244   FCosmetic := true;
245   FMode := ccmPenStyle;
246   FBrushBitmap := TBitmap.Create;
247   FBrushColor := clBlack;
248   FBrushStyle := bsSolid;
249   FPenStyle := psSolid;
250   FPenWidth := 1;
251   FMaxPenWidth := 5;
252   FOptions := DEFAULT_OPTIONS;
253   FSymbolWidth := -1;
254   PopulatePenStyles;
255   SetSelectedPenStyle(FPenStyle);
256   GetItems;
257 end;
258 
259 destructor TChartCombobox.Destroy;
260 begin
261   DestroyBitmaps;
262   FBrushBitmap.Free;
263   inherited;
264 end;
265 
266 procedure TChartCombobox.Change;
267 begin
268   SetItemIndex(ItemIndex);
269   inherited;
270 end;
271 
272 procedure TChartCombobox.CreateBitmaps(AWidth, AHeight: Integer);
273 var
274   ps: TSeriesPointerStyle;
275   chart: TChart;
276   id: IChartDrawer;
277   series: TLineSeries;
278   legItems: TChartLegendItems;
279 begin
280   DestroyBitmaps;
281 
282   chart := TChart.Create(nil);
283   try
284     for ps in TSeriesPointerStyle do begin
285       FBitmaps[ps] := TBitmap.Create;
286       FBitmaps[ps].Transparent := true;
287       FBitmaps[ps].TransparentColor := RgbToColor(254,254,254);
288       FBitmaps[ps].SetSize(AWidth, AHeight);
289       FBitmaps[ps].Canvas.Brush.Color := FBitmaps[ps].TransparentColor;
290       FBitmaps[ps].Canvas.FillRect(0, 0, AWidth, AHeight);
291 
292       series := TLineSeries.Create(chart);
293       try
294         with series do begin
295           Pointer.Style := ps;
296           Pointer.Brush.Color := FBrushColor;
297           Pointer.Pen.Color := FPenColor;
298           Pointer.HorizSize := Min(AWidth, AHeight);
299           Pointer.VertSize := Pointer.HorizSize;
300           ShowPoints := true;
301           LineType := ltNone;
302         end;
303         chart.AddSeries(series);
304         legitems := TChartLegendItems.Create;
305         try
306           series.GetSingleLegendItem(legItems);
307           id := TCanvasDrawer.Create(FBitmaps[ps].Canvas);
308           id.Pen := Chart.Legend.SymbolFrame;
309           legItems[0].Draw(id, Rect(0, 0, AWidth-1, AHeight-1));
310         finally
311           legitems.Free;
312         end;
313       finally
314         series.Free;
315       end;
316     end;
317   finally
318     chart.Free;
319   end;
320 end;
321 
322 procedure TChartCombobox.DestroyBitmaps;
323 var
324   ps: TSeriesPointerStyle;
325 begin
326   for ps in TSeriesPointerStyle do
327     FreeAndNil(FBitmaps[ps]);
328 end;
329 
330 procedure TChartComboBox.DoAutoAdjustLayout(
331   const AMode: TLayoutAdjustmentPolicy;
332   const AXProportion, AYProportion: Double);
333 begin
334   inherited DoAutoAdjustLayout(AMode, AXProportion, AYProportion);
335 
336   if AMode in [lapAutoAdjustWithoutHorizontalScrolling, lapAutoAdjustForDPI] then
337   begin
338     if SymbolWidthStored then
339       FSymbolWidth := Round(FSymbolWidth * AXProportion);
340     Invalidate;
341   end;
342 end;
343 
344 procedure TChartComboBox.DrawItem(AIndex: Integer; ARect: TRect;
345   AState: TOwnerDrawState);
346 const
347   DIST = 4;
348   MARGIN = 2;
349 var
350   ts: TTextStyle;
351   alignmnt: TAlignment;
352   x1, x2, y: Integer;
353   txt: String;
354   bs: TBrushStyle;
355   sps: TSeriesPointerStyle;
356   symwidth, symheight: Integer;
357 begin
358   if Assigned(OnDrawItem) then
359     OnDrawItem(Self, AIndex, ARect, AState)
360   else begin
361     if odFocused in AState then begin
362       Canvas.Brush.Color := clHighlight;
363       Canvas.Font.Color := clHighlightText;
364     end;
365     Canvas.FillRect(ARect);
366 
367     if (BiDiMode <> bdLeftToRight) then
368       case FAlignment of
369         taLeftJustify : alignmnt := taRightJustify;
370         taCenter      : alignmnt := taCenter;
371         taRightJustify: alignmnt := taLeftJustify
372       end
373     else
374       alignmnt := FAlignment;
375 
376     symheight := ARect.Bottom - ARect.Top - 2 * MARGIN;
377     symwidth := IfThen(FMode = ccmPointerStyle, symheight * 6 div 4, SymbolWidth);
378 
379     case alignmnt of
380       taLeftJustify  : x1 := IfThen(DroppedDown, MARGIN, MARGIN * 2);
381       taRightJustify : x1 := ARect.Right - MARGIN - symwidth;
382       taCenter       : x1 := (ARect.Left + ARect.Right - symwidth) div 2;
383     end;
384     x2 := x1 + symwidth;
385 
386     if (odSelected in AState) or (odFocused in AState) then
387       Canvas.Pen.Color := clHighlightText
388     else
389       Canvas.Pen.Color := FPenColor;
390     Canvas.Pen.Cosmetic := FCosmetic;
391     case FMode of
392       ccmBrushStyle:
393         begin
394           bs := GetBrushStyle(AIndex);
395           if bs <> bsClear then begin
396             Canvas.Brush.Color := clWhite;
397             Canvas.Brush.Style := bsSolid;
398             Canvas.FillRect(x1, ARect.Top + MARGIN, x2, ARect.Bottom - MARGIN);
399           end;
400           Canvas.Brush.Color := FBrushColor;
401           Canvas.Brush.Style := bs;
402           if (bs = bsImage) or (bs = bsPattern) then
403             Canvas.Brush.Bitmap := FBrushBitmap; // AFTER assigning Brush.Style!
404           Canvas.Pen.Color := clBlack;
405           Canvas.Pen.Style := psSolid;
406           Canvas.Rectangle(x1, ARect.Top + MARGIN, x2, ARect.Bottom - MARGIN)
407         end;
408       ccmPenStyle:
409         begin
410           Canvas.Pen.Style := GetPenStyle(AIndex);
411           if Canvas.Pen.Style = psPattern then
412             Canvas.Pen.SetPattern(FPenPattern);
413           Canvas.Pen.Width := 1;
414           Canvas.Brush.Style := bsClear;
415           y := (ARect.Top + ARect.Bottom) div 2;
416           Canvas.Line(x1, y, x2, y);
417         end;
418       ccmPenWidth:
419         begin
420           Canvas.Pen.Style := psSolid;
421           Canvas.Pen.Width := GetPenWidth(AIndex);
422           Canvas.Pen.EndCap := pecFlat;
423           Canvas.Brush.Style := bsClear;
424           y := (ARect.Top + ARect.Bottom) div 2;
425           Canvas.Line(x1, y, x2, y);
426         end;
427       ccmPointerStyle:
428         begin
429           if (FBitmaps[psCircle] = nil) or (FBitmaps[psCircle].Height <> symHeight)
430             then CreateBitmaps(symwidth, symHeight);
431           sps := GetPointerStyle(AIndex);
432           Canvas.Draw(x1, ARect.Top + MARGIN, FBitmaps[sps]);
433         end;
434     end;
435 
436     if (ccoNames in FOptions) and (FAlignment <> taCenter) then begin
437       ts := Canvas.TextStyle;
438       ts.Layout := tlCenter;
439       ts.Opaque := false;
440       ts.EndEllipsis := true;
441       txt := Items[AIndex];
442       case alignmnt of
443         taLeftJustify  : ARect.Left := x2 + DIST;
444         taRightJustify : ARect.Left := x1 - DIST - Canvas.TextWidth(txt);
445       end;
446       Canvas.TextRect(ARect, ARect.Left, ARect.Top, txt, ts);
447     end;
448   end;
449 end;
450 
GetBrushStylenull451 function TChartCombobox.GetBrushStyle(const AIndex: Integer): TBrushStyle;
452 begin
453   if AIndex < 0 then
454     Result := bsSolid
455   else
456     Result := TBrushStyle(AIndex);
457 end;
458 
TChartComboBox.GetPenPatternnull459 function TChartComboBox.GetPenPattern: String;
460 var
461   i: Integer;
462 begin
463   if Length(FPenPattern) > 0 then begin
464     Result := IntToStr(FPenPattern[0]);
465     for i := 1 to High(FPenPattern) do
466       Result := Result + '|' + IntToStr(FPenPattern[i]);
467   end else
468     Result := '';
469 end;
470 
GetPenStylenull471 function TChartComboBox.GetPenStyle(const AIndex: Integer): TPenStyle;
472 begin
473   if AIndex < 0 then
474     Result := psSolid
475   else
476 //    Result := TPenStyle(AIndex);
477     Result := TPenStyle(PtrInt(Items.Objects[AIndex]));
478 end;
479 
TChartComboBox.GetPenWidthnull480 function TChartComboBox.GetPenWidth(const AIndex: Integer): Integer;
481 begin
482   if AIndex < 0 then Result := 1 else Result := AIndex + 1;
483 end;
484 
GetPointerStylenull485 function TChartCombobox.GetPointerStyle(AIndex: Integer): TSeriesPointerStyle;
486 begin
487   if AIndex = -1 then
488     Result := psNone
489   else
490     Result := TSeriesPointerStyle(PtrInt(Items.Objects[AIndex]));
491 end;
492 
GetSymbolWidthnull493 function TChartCombobox.GetSymbolWidth: Integer;
494 begin
495   if SymbolWidthStored then
496     Result := FSymbolWidth
497   else
498     Result := Scale96ToFont(DEFAULT_SYMBOL_WIDTH);
499 end;
500 
501 procedure TChartCombobox.PopulateBrushStyles;
502 var
503   bs: TBrushStyle;
504 begin
505   inc(FLockItemIndex);
506   Items.BeginUpdate;
507   try
508     Items.Clear;
509     for bs in TBrushStyle do begin
510       if (bs = bsPattern) and not (ccoPatternBrush in FOptions) then
511         Continue;
512       if (bs = bsImage) and not (ccoImageBrush in FOptions) then
513         Continue;
514       Items.Add(GetBrushStylename(bs));
515     end;
516   finally
517     Items.EndUpdate;
518     dec(FLockItemIndex);
519   end;
520 end;
521 
522 procedure TChartComboBox.PopulatePenStyles;
523 var
524   ps: TPenStyle;
525 begin
526   inc(FLockItemIndex);
527   Items.BeginUpdate;
528   try
529     Items.Clear;
530     for ps in TPenStyle do begin
531       if (ps = psPattern) and not (ccoPatternPen in FOptions) then
532         Continue;
533       Items.AddObject(GetPenStyleName(ps), TObject(PtrInt(ps)));
534     end;
535   finally
536     Items.EndUpdate;
537     dec(FLockItemIndex);
538   end;
539 end;
540 
541 procedure TChartComboBox.PopulatePenWidths;
542 var
543   w: Integer;
544 begin
545   inc(FLockItemIndex);
546   Items.BeginUpdate;
547   try
548     Items.Clear;
549     for w := 1 to FMaxPenWidth do
550       Items.Add(IntToStr(w));
551   finally
552     Items.EndUpdate;
553     dec(FLockItemIndex);
554   end;
555 end;
556 
557 procedure TChartCombobox.PopulatePointerStyles;
558 const
559   // Arrange symbols in "nice" order
560   LIST: array[0..19] of TSeriesPointerStyle = (
561     psNone, psRectangle, psCircle, psDiamond,
562     psTriangle, psDownTriangle, psLeftTriangle, psRightTriangle,
563     psHexagon, psFullStar,
564     psStar, psCross, psDiagCross,
565     psLowBracket, psHighBracket, psLeftBracket, psRightBracket,
566     psHorBar, psVertBar, psPoint);
567 var
568   ps: TSeriesPointerStyle;
569   s: String;
570   i: Integer;
571   sel: TSeriesPointerStyle;
572   styleItems: TStrings;
573 begin
574   sel := FPointerStyle;
575   styleItems := TStringList.Create;
576   try
577     for i:=0 to High(LIST) do begin
578       ps := LIST[i];
579       s := GetSymbolName(ps);
580       if s <> '' then
581         styleItems.AddObject(s, TObject(PtrInt(ps)));
582     end;
583     Items.Assign(styleitems);
584   finally
585     styleItems.Free;
586     SetSelectedPointerStyle(sel);
587   end;
588 end;
589 
590 { Is overridden to prevent loss of default selected pointer style when
591   combo is added to a form in designer. }
592 procedure TChartComboBox.RealSetText(const AValue: TCaption);
593 var
594   bs: TBrushStyle;
595   ps: TPenStyle;
596   sps: TSeriesPointerStyle;
597   pw: Integer;
598 begin
599   case FMode of
600     ccmBrushStyle   : bs := GetBrushStyle(ItemIndex);
601     ccmPenStyle     : ps := GetPenStyle(ItemIndex);
602     ccmPenWidth     : pw := GetPenWidth(ItemIndex);
603     ccmPointerStyle : sps := GetPointerStyle(ItemIndex);
604   end;
605   inherited RealSetText(AValue);
606   case FMode of
607     ccmBrushStyle   : SetSelectedBrushStyle(bs);
608     ccmPenStyle     : SetSelectedPenStyle(ps);
609     ccmPenWidth     : SetSelectedPenWidth(pw);
610     ccmPointerStyle : SetSelectedPointerStyle(sps);
611   end;
612 end;
613 
614 procedure TChartComboBox.SetAlignment(const AValue: TAlignment);
615 begin
616   if FAlignment = AValue then exit;
617   FAlignment := AValue;
618   Invalidate;
619 end;
620 
621 procedure TChartCombobox.SetBrushBitmap(const AValue: TBitmap);
622 begin
623   if FBrushBitmap = AValue then exit;
624   FBrushBitmap.Assign(AValue);
625   Invalidate;
626 end;
627 
628 procedure TChartCombobox.SetBrushColor(const AValue: TColor);
629 begin
630   if FBrushColor = AValue then exit;
631   FBrushColor := AValue;
632   DestroyBitmaps;
633   Invalidate;
634 end;
635 
636 procedure TChartComboBox.SetCosmetic(const AValue: Boolean);
637 begin
638   if FCosmetic = AValue then exit;
639   FCosmetic := AValue;
640   Invalidate;
641 end;
642 
643 procedure TChartComboBox.SetItemIndex(const AValue: Integer);
644 begin
645   if FLockItemIndex = 0 then
646     case FMode of
647       ccmBrushStyle   : FBrushStyle := GetBrushStyle(AValue);
648       ccmPenStyle     : FPenStyle := GetPenStyle(AValue);
649       ccmPenWidth     : FPenWidth := AValue + 1;
650       ccmPointerStyle : FPointerStyle := GetPointerStyle(AValue);
651     end;
652   inherited SetItemIndex(AValue);
653 end;
654 
655 procedure TChartCombobox.SetMaxPenWidth(const AValue: Integer);
656 var
657   pw: Integer;
658 begin
659   if AValue = FMaxPenWidth then exit;
660   FMaxPenWidth := AValue;
661   if FMode = ccmPenWidth then begin
662     pw := GetPenWidth(ItemIndex);
663     PopulatePenWidths;
664     SetSelectedPenWidth(pw);
665   end;
666   Invalidate;
667 end;
668 
669 procedure TChartComboBox.SetMode(const AValue: TChartComboMode);
670 begin
671   if AValue = FMode then exit;
672   FMode := AValue;
673   case FMode of
674     ccmBrushStyle:
675       begin
676         DestroyBitmaps;
677         PopulateBrushStyles;
678         SetSelectedBrushStyle(FBrushStyle);
679       end;
680     ccmPenStyle:
681       begin
682         DestroyBitmaps;
683         PopulatePenStyles;
684         SetSelectedPenStyle(FPenStyle);
685       end;
686     ccmPenWidth:
687       begin
688         DestroyBitmaps;
689         PopulatePenWidths;
690         SetSelectedPenWidth(FPenWidth);
691       end;
692     ccmPointerStyle:
693       begin
694         DestroyBitmaps;  // bitmaps will be created when painting
695         PopulatePointerStyles;
696         SetSelectedPointerStyle(FPointerStyle);
697       end;
698   end;
699 end;
700 
701 procedure TChartComboBox.SetOptions(const AValue: TChartComboOptions);
702 begin
703   if FOptions = AValue then exit;
704   FOptions := AValue;
705   case FMode of
706     ccmBrushStyle   : PopulateBrushStyles;
707     ccmPenStyle     : PopulatePenStyles;
708     ccmPenWidth     : PopulatePenWidths;
709     ccmPointerStyle : PopulatePointerStyles;
710   end;
711   Invalidate;
712 end;
713 
714 procedure TChartComboBox.SetPenPattern(const AValue: String);
715 var
716   L: TStrings;
717   i: Integer;
718   patt: Integer;
719 begin
720   if AValue = GetPenPattern then
721     exit;
722 
723   L := TStringList.Create;
724   try
725     Split(AValue, L, '|');
726     SetLength(FPenPattern, L.Count);
727     for i := 0 to L.Count - 1 do
728       if TryStrToInt(L[i], patt) then
729         FPenPattern[i] := patt
730       else
731         FPenPattern[i] := 0;
732     Invalidate;
733   finally
734     L.Free;
735   end;
736 end;
737 
738 procedure TChartComboBox.SetPenColor(const AValue: TColor);
739 begin
740   if AValue = FPenColor then exit;
741   FPenColor := AValue;
742   DestroyBitmaps;
743   Invalidate;
744 end;
745 
746 procedure TChartComboBox.SetPenPattern(APen: TPen);
747 begin
748   if Assigned(APen) then APen.SetPattern(FPenPattern);
749 end;
750 
751 procedure TChartCombobox.SetSelectedBrushStyle(const AValue: TBrushStyle);
752 begin
753   ItemIndex := EnsureRange(ord(AValue), 0, Items.Count - 1);
754 end;
755 
756 procedure TChartComboBox.SetSelectedPenStyle(const AValue: TPenStyle);
757 var
758   i: Integer;
759 begin
760   for i := 0 to Items.Count - 1 do
761     if GetPenStyle(i) = AValue then begin
762       ItemIndex := i;
763       exit;
764     end;
765   ItemIndex := -1;
766 end;
767 
768 procedure TChartComboBox.SetSelectedPenWidth(const AValue: Integer);
769 begin
770   ItemIndex := EnsureRange(AValue - 1, 0, Items.Count - 1);
771 end;
772 
773 procedure TChartCombobox.SetSelectedPointerStyle(const AValue: TSeriesPointerStyle);
774 var
775   i: Integer;
776 begin
777   for i:= 0 to Items.Count - 1 do begin
778     if GetPointerStyle(i) = AValue then begin
779       FPointerStyle := AValue;
780       ItemIndex := i;
781       Invalidate;
782       exit;
783     end;
784   end;
785   ItemIndex := -1;
786   FPointerStyle := psNone;
787 end;
788 
789 procedure TChartComboBox.SetSymbolWidth(const AValue: Integer);
790 begin
791   if FSymbolWidth = AValue then exit;
792   FSymbolWidth := AValue;
793   Invalidate;
794 end;
795 
SymbolWidthStorednull796 function TChartCombobox.SymbolWidthStored: Boolean;
797 begin
798   Result := FSymbolWidth >= 0;
799 end;
800 
801 end.
802