~ubuntu-branches/ubuntu/saucy/lazarus/saucy

« back to all changes in this revision

Viewing changes to components/tachart/tachartlistbox.pas

  • Committer: Package Import Robot
  • Author(s): Paul Gevers, Abou Al Montacir, Bart Martens, Paul Gevers
  • Date: 2013-06-08 14:12:17 UTC
  • mfrom: (1.1.9)
  • Revision ID: package-import@ubuntu.com-20130608141217-7k0cy9id8ifcnutc
Tags: 1.0.8+dfsg-1
[ Abou Al Montacir ]
* New upstream major release and multiple maintenace release offering many
  fixes and new features marking a new milestone for the Lazarus development
  and its stability level.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_fixes_branch
* LCL changes:
  - LCL is now a normal package.
      + Platform independent parts of the LCL are now in the package LCLBase
      + LCL is automatically recompiled when switching the target platform,
        unless pre-compiled binaries for this target are already installed.
      + No impact on existing projects.
      + Linker options needed by LCL are no more added to projects that do
        not use the LCL package.
  - Minor changes in LCL basic classes behaviour
      + TCustomForm.Create raises an exception if a form resource is not
        found.
      + TNotebook and TPage: a new implementation of these classes was added.
      + TDBNavigator: It is now possible to have focusable buttons by setting
        Options = [navFocusableButtons] and TabStop = True, useful for
        accessibility and for devices with neither mouse nor touch screen.
      + Names of TControlBorderSpacing.GetSideSpace and GetSpace were swapped
        and are now consistent. GetSideSpace = Around + GetSpace.
      + TForm.WindowState=wsFullscreen was added
      + TCanvas.TextFitInfo was added to calculate how many characters will
        fit into a specified Width. Useful for word-wrapping calculations.
      + TControl.GetColorResolvingParent and
        TControl.GetRGBColorResolvingParent were added, simplifying the work
        to obtain the final color of the control while resolving clDefault
        and the ParentColor.
      + LCLIntf.GetTextExtentExPoint now has a good default implementation
        which works in any platform not providing a specific implementation.
        However, Widgetset specific implementation is better, when available.
      + TTabControl was reorganized. Now it has the correct class hierarchy
        and inherits from TCustomTabControl as it should.
  - New unit in the LCL:
      + lazdialogs.pas: adds non-native versions of various native dialogs,
        for example TLazOpenDialog, TLazSaveDialog, TLazSelectDirectoryDialog.
        It is used by widgetsets which either do not have a native dialog, or
        do not wish to use it because it is limited. These dialogs can also be
        used by user applications directly.
      + lazdeviceapis.pas: offers an interface to more hardware devices such
        as the accelerometer, GPS, etc. See LazDeviceAPIs
      + lazcanvas.pas: provides a TFPImageCanvas descendent implementing
        drawing in a LCL-compatible way, but 100% in Pascal.
      + lazregions.pas. LazRegions is a wholly Pascal implementation of
        regions for canvas clipping, event clipping, finding in which control
        of a region tree one an event should reach, for drawing polygons, etc.
      + customdrawncontrols.pas, customdrawndrawers.pas,
        customdrawn_common.pas, customdrawn_android.pas and
        customdrawn_winxp.pas: are the Lazarus Custom Drawn Controls -controls
        which imitate the standard LCL ones, but with the difference that they
        are non-native and support skinning.
  - New APIs added to the LCL to improve support of accessibility software
    such as screen readers.
* IDE changes:
  - Many improvments.
  - The detailed list of changes can be found here:
    http://wiki.lazarus.freepascal.org/New_IDE_features_since#v1.0_.282012-08-29.29
    http://wiki.lazarus.freepascal.org/Lazarus_1.0_release_notes#IDE_Changes
* Debugger / Editor changes:
  - Added pascal sources and breakpoints to the disassembler
  - Added threads dialog.
* Components changes:
  - TAChart: many fixes and new features
  - CodeTool: support Delphi style generics and new syntax extensions.
  - AggPas: removed to honor free licencing. (Closes: Bug#708695)
[Bart Martens]
* New debian/watch file fixing issues with upstream RC release.
[Abou Al Montacir]
* Avoid changing files in .pc hidden directory, these are used by quilt for
  internal purpose and could lead to surprises during build.
[Paul Gevers]
* Updated get-orig-source target and it compinion script orig-tar.sh so that they
  repack the source file, allowing bug 708695 to be fixed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
{
 
2
 
 
3
 *****************************************************************************
 
4
 *                                                                           *
 
5
 *  See the file COPYING.modifiedLGPL.txt, included in this distribution,    *
 
6
 *  for details about the copyright.                                         *
 
7
 *                                                                           *
 
8
 *  This program is distributed in the hope that it will be useful,          *
 
9
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of           *
 
10
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                     *
 
11
 *                                                                           *
 
12
 *****************************************************************************
 
13
 
 
14
Authors: Werner Pamler, Alexander Klenin
 
15
 
 
16
Usage:
 
17
- Add the ChartListbox to a form with a TChart
 
18
- Connect the chart to the listbox by setting the chart property of the
 
19
  TChartlistbox. The ChartListbox will be populated with the series in the
 
20
  chart and will automatically track changes of the series.
 
21
- Check/uncheck series in the ChartListbox to show/hide them in the chart.
 
22
  As usual, checking is done by mouse clicks or by pressing the space bar.
 
23
- Play with the properties to modify the standard behavior, e.g. set
 
24
  CheckStyle to cbsRadioButton in order to get a radiobutton behavior, i.e. to
 
25
  allow only one visible series.
 
26
}
 
27
 
 
28
unit TAChartListbox;
 
29
 
 
30
{$mode objfpc}{$H+}
 
31
 
 
32
interface
 
33
 
 
34
uses
 
35
  Classes, Controls, StdCtrls,
 
36
  TAChartUtils, TACustomSeries, TALegend, TAGraph;
 
37
 
 
38
type
 
39
  TChartListbox = class;
 
40
 
 
41
  TChartListboxIndexEvent = procedure (
 
42
    ASender: TObject; AIndex: Integer) of object;
 
43
 
 
44
  TChartListboxAddSeriesEvent = procedure (
 
45
    ASender: TChartListbox; ASeries: TCustomChartSeries;
 
46
    AItems: TChartLegendItems; var ASkip: Boolean
 
47
  ) of object;
 
48
 
 
49
  TCheckBoxesStyle = (cbsCheckbox, cbsRadiobutton);
 
50
 
 
51
  TChartListOption = (cloShowCheckboxes, cloShowIcons, cloRefreshOnSourceChange);
 
52
  TChartListOptions = set of TChartListOption;
 
53
 
 
54
const
 
55
  SHOW_ALL = [cloShowCheckboxes, cloShowIcons];
 
56
 
 
57
type
 
58
  TChartListbox = class(TCustomListbox)
 
59
  private
 
60
    FChart: TChart;
 
61
    FCheckStyle: TCheckBoxesStyle;
 
62
    FLegendItems: TChartLegendItems;
 
63
    FListener: TListener;
 
64
    FOnAddSeries: TChartListboxAddSeriesEvent;
 
65
    FOnCheckboxClick: TChartListboxIndexEvent;
 
66
    FOnItemClick: TChartListboxIndexEvent;
 
67
    FOnPopulate: TNotifyEvent;
 
68
    FOnSeriesIconDblClick: TChartListboxIndexEvent;
 
69
    FOptions: TChartListOptions;
 
70
    FSeriesIconClicked: Integer;
 
71
    function GetChecked(AIndex: Integer): Boolean;
 
72
    function GetSeries(AIndex: Integer): TCustomChartSeries;
 
73
    function GetSeriesCount: Integer;
 
74
    procedure EnsureSingleChecked(AIndex: Integer = -1);
 
75
    procedure SetChart(AValue: TChart);
 
76
    procedure SetChecked(AIndex: Integer; AValue: Boolean);
 
77
    procedure SetCheckStyle(AValue: TCheckBoxesStyle);
 
78
    procedure SetOnAddSeries(AValue: TChartListboxAddSeriesEvent);
 
79
    procedure SetOnPopulate(AValue: TNotifyEvent);
 
80
    procedure SetOptions(AValue: TChartListOptions);
 
81
 
 
82
  protected
 
83
    procedure DblClick; override;
 
84
    procedure DrawItem(
 
85
      AIndex: Integer; ARect: TRect; AState: TOwnerDrawState); override;
 
86
    procedure KeyDown(var AKey: Word; AShift: TShiftState); override;
 
87
    procedure MouseDown(
 
88
      AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer); override;
 
89
  protected
 
90
    procedure CalcRects(
 
91
      const AItemRect: TRect; out ACheckboxRect, ASeriesIconRect: TRect);
 
92
    procedure ClickedCheckbox(AIndex: Integer); virtual;
 
93
    procedure ClickedItem(AIndex: Integer); virtual;
 
94
    procedure ClickedSeriesIcon(AIndex: Integer); virtual;
 
95
    function CreateLegendItems: TChartLegendItems;
 
96
    procedure Populate;
 
97
 
 
98
  public
 
99
    constructor Create(AOwner: TComponent); override;
 
100
    destructor Destroy; override;
 
101
    function FindSeriesIndex(ASeries: TCustomChartSeries): Integer;
 
102
    procedure MeasureItem(AIndex: Integer; var AHeight: Integer); override;
 
103
    procedure RemoveSeries(ASeries: TCustomChartSeries);
 
104
    procedure SeriesChanged(ASender: TObject);
 
105
 
 
106
    property Checked[AIndex: Integer]: Boolean read GetChecked write SetChecked;
 
107
    property Series[AIndex: Integer]: TCustomChartSeries read GetSeries;
 
108
    property SeriesCount: Integer read GetSeriesCount;
 
109
 
 
110
  published
 
111
    property Chart: TChart read FChart write SetChart;
 
112
    property CheckStyle: TCheckBoxesStyle
 
113
      read FCheckStyle write SetCheckStyle default cbsCheckbox;
 
114
    property Options: TChartListOptions
 
115
      read FOptions write SetOptions default SHOW_ALL;
 
116
  published
 
117
    property OnAddSeries: TChartListboxAddSeriesEvent
 
118
      read FOnAddSeries write SetOnAddSeries;
 
119
    property OnCheckboxClick: TChartListboxIndexEvent
 
120
      read FOnCheckboxClick write FOnCheckboxClick;
 
121
    property OnItemClick: TChartListboxIndexEvent
 
122
      read FOnItemClick write FOnItemClick;
 
123
    property OnPopulate: TNotifyEvent read FOnPopulate write SetOnPopulate;
 
124
    property OnSeriesIconDblClick: TChartListboxIndexEvent
 
125
      read FOnSeriesIconDblClick write FOnSeriesIconDblClick;
 
126
  published
 
127
    property Align;
 
128
//    property AllowGrayed;
 
129
    property Anchors;
 
130
    property BidiMode;
 
131
    property BorderSpacing;
 
132
    property BorderStyle;
 
133
    property Color;
 
134
    property Columns;
 
135
    property Constraints;
 
136
    property DragCursor;
 
137
    property DragMode;
 
138
    property Enabled;
 
139
    property ExtendedSelect;
 
140
    property Font;
 
141
    property IntegralHeight;
 
142
//    property Items;
 
143
    property ItemHeight;
 
144
    property MultiSelect;
 
145
    property OnChangeBounds;
 
146
    property OnClick;
 
147
//    property OnClickCheck;
 
148
    property OnContextPopup;
 
149
    property OnDblClick;
 
150
    property OnDragDrop;
 
151
    property OnDragOver;
 
152
    property OnDrawItem;
 
153
    property OnEndDrag;
 
154
    property OnEnter;
 
155
    property OnExit;
 
156
//    property OnItemClick;
 
157
    property OnKeyDown;
 
158
    property OnKeyPress;
 
159
    property OnKeyUp;
 
160
    property OnMouseDown;
 
161
    property OnMouseEnter;
 
162
    property OnMouseLeave;
 
163
    property OnMouseMove;
 
164
    property OnMouseUp;
 
165
    property OnMouseWheel;
 
166
    property OnMouseWheelDown;
 
167
    property OnMouseWheelUp;
 
168
    property OnResize;
 
169
    property OnShowHint;
 
170
    property OnStartDrag;
 
171
    property OnUTF8KeyPress;
 
172
    property ParentBidiMode;
 
173
    property ParentFont;
 
174
    property ParentShowHint;
 
175
    property PopupMenu;
 
176
    property ShowHint;
 
177
    property Sorted;
 
178
//    property Style;
 
179
    property TabOrder;
 
180
    property TabStop;
 
181
    property TopIndex;
 
182
    property Visible;
 
183
  end;
 
184
 
 
185
procedure Register;
 
186
 
 
187
 
 
188
implementation
 
189
 
 
190
uses
 
191
  Graphics, Math, LCLIntf, LCLType, SysUtils, Themes,
 
192
  TACustomSource, TADrawerCanvas, TADrawUtils, TAEnumerators, TAGeometry;
 
193
 
 
194
procedure Register;
 
195
begin
 
196
  RegisterComponents(CHART_COMPONENT_IDE_PAGE, [TChartListbox]);
 
197
end;
 
198
 
 
199
constructor TChartListbox.Create(AOwner: TComponent);
 
200
begin
 
201
  inherited Create(AOwner);
 
202
  Style := lbOwnerDrawFixed;
 
203
  FListener := TListener.Create(@FChart, @SeriesChanged);
 
204
  FOptions := SHOW_ALL;
 
205
end;
 
206
 
 
207
destructor TChartListbox.Destroy;
 
208
begin
 
209
  FreeAndNil(FListener);
 
210
  FreeAndNil(FLegendItems);
 
211
  inherited;
 
212
end;
 
213
 
 
214
procedure TChartListbox.CalcRects(
 
215
  const AItemRect: TRect; out ACheckboxRect, ASeriesIconRect: TRect);
 
216
{ based on the rect of a listbox item, calculates the locations of the
 
217
  checkbox and of the series icon }
 
218
var
 
219
  w, x: Integer;
 
220
begin
 
221
  ACheckBoxRect := Rect(-1, -1, -1, -1);
 
222
  ASeriesIconRect := Rect(-1, -1, -1, -1);
 
223
  w := GetSystemMetrics(SM_CYMENUCHECK);
 
224
  x := 2;
 
225
  if cloShowCheckboxes in Options then begin
 
226
    with AItemRect do
 
227
      ACheckboxRect := Bounds(Left + 1, (Top + Bottom - w) div 2, w, w);
 
228
    if cloShowIcons in Options then
 
229
      x += ACheckboxRect.Right;
 
230
  end
 
231
  else begin
 
232
    if cloShowIcons in Options then
 
233
      x += AItemRect.Left;
 
234
  end;
 
235
  if cloShowIcons in Options then
 
236
    ASeriesIconRect := Rect(
 
237
      x, AItemRect.Top + 2, x + FChart.Legend.SymbolWidth, AItemRect.Bottom - 2);
 
238
end;
 
239
 
 
240
procedure TChartListbox.ClickedCheckbox(AIndex: Integer);
 
241
begin
 
242
  Checked[AIndex] := not Checked[AIndex];
 
243
  if Assigned(OnCheckboxClick) then
 
244
    OnCheckboxClick(Self, AIndex);
 
245
end;
 
246
 
 
247
procedure TChartListbox.ClickedItem(AIndex: Integer);
 
248
begin
 
249
  if Assigned(OnItemClick) then
 
250
    OnItemClick(Self, AIndex);
 
251
end;
 
252
 
 
253
procedure TChartListbox.ClickedSeriesIcon(AIndex: Integer);
 
254
begin
 
255
  if Assigned(OnSeriesIconDblClick) then
 
256
    OnSeriesIconDblClick(Self, AIndex);
 
257
end;
 
258
 
 
259
function TChartListbox.CreateLegendItems: TChartLegendItems;
 
260
{ creates the a TLegendItems list and populates it with information for
 
261
  all series contained in the Chart. In case of MultiLegend items, only
 
262
  a single legend item is used }
 
263
var
 
264
  skip: Boolean;
 
265
  s: TCustomChartSeries;
 
266
begin
 
267
  Result := TChartLegendItems.Create;
 
268
  try
 
269
    if FChart = nil then exit;
 
270
    for s in CustomSeries(Chart) do begin
 
271
      if Assigned(OnAddSeries) then begin
 
272
        skip := false;
 
273
        FOnAddSeries(Self, s, Result, skip);
 
274
        if skip then continue;
 
275
      end;
 
276
      s.GetSingleLegendItem(Result);
 
277
    end;
 
278
  except
 
279
    FreeAndNil(Result);
 
280
    raise;
 
281
  end;
 
282
end;
 
283
 
 
284
procedure TChartListbox.DblClick;
 
285
begin
 
286
  inherited DblClick;
 
287
  if FSeriesIconClicked <> -1 then
 
288
    ClickedSeriesIcon(FSeriesIconClicked);
 
289
end;
 
290
 
 
291
procedure TChartListbox.DrawItem(
 
292
  AIndex: Integer; ARect: TRect; AState: TOwnerDrawState);
 
293
{ draws the listbox item }
 
294
const
 
295
  UNTHEMED_FLAGS: array [TCheckboxesStyle, Boolean] of Integer = (
 
296
    (DFCS_BUTTONCHECK, DFCS_BUTTONCHECK or DFCS_CHECKED),
 
297
    (DFCS_BUTTONRADIO, DFCS_BUTTONRADIO or DFCS_CHECKED)
 
298
  );
 
299
  THEMED_FLAGS: array [TCheckboxesStyle, Boolean] of TThemedButton = (
 
300
    (tbCheckBoxUncheckedNormal, tbCheckBoxCheckedNormal),
 
301
    (tbRadioButtonUnCheckedNormal, tbRadioButtonCheckedNormal)
 
302
  );
 
303
var
 
304
  id: IChartDrawer;
 
305
  rcb, ricon: TRect;
 
306
  te: TThemedElementDetails;
 
307
  x: Integer;
 
308
  ch: Boolean;
 
309
begin
 
310
  if Assigned(OnDrawItem) then begin
 
311
    OnDrawItem(Self, AIndex, ARect, AState);
 
312
    exit;
 
313
  end;
 
314
  if
 
315
    (odPainted in AState) or (FChart = nil) or not InRange(AIndex, 0, Count - 1)
 
316
  then exit;
 
317
 
 
318
  Canvas.FillRect(ARect);
 
319
  CalcRects(ARect, rcb, ricon);
 
320
 
 
321
  if cloShowCheckboxes in Options then begin
 
322
    ch := Checked[AIndex];
 
323
    if ThemeServices.ThemesEnabled then begin
 
324
      te := ThemeServices.GetElementDetails(THEMED_FLAGS[FCheckStyle, ch]);
 
325
      ThemeServices.DrawElement(Canvas.Handle, te, rcb);
 
326
    end
 
327
    else
 
328
      DrawFrameControl(
 
329
        Canvas.Handle, rcb, DFC_BUTTON, UNTHEMED_FLAGS[FCheckStyle, ch]);
 
330
    x := rcb.Right;
 
331
  end
 
332
  else
 
333
    x := ARect.Left;
 
334
 
 
335
  Canvas.Brush.Style := bsClear;
 
336
  if cloShowIcons in Options then begin
 
337
    id := TCanvasDrawer.Create(Canvas);
 
338
    id.Pen := Chart.Legend.SymbolFrame;
 
339
    FLegendItems[AIndex].Draw(id, ricon);
 
340
  end
 
341
  else
 
342
    Canvas.TextOut(x + 2, ARect.Top, FLegendItems.Items[AIndex].Text);
 
343
end;
 
344
 
 
345
procedure TChartListbox.EnsureSingleChecked(AIndex: Integer);
 
346
var
 
347
  i: Integer;
 
348
  ser: TCustomChartSeries;
 
349
begin
 
350
  if (FCheckStyle <> cbsRadioButton) or not (cloShowCheckboxes in Options) then
 
351
    exit;
 
352
  FListener.OnNotify := nil;
 
353
  try
 
354
    for i := 0 to FLegendItems.Count - 1 do begin
 
355
      ser := GetSeries(i);
 
356
      if ser = nil then continue;
 
357
      if (AIndex < 0) and ser.Active then
 
358
        AIndex := i
 
359
      else
 
360
        ser.Active := AIndex = i;
 
361
    end;
 
362
  finally
 
363
    FListener.OnNotify := @SeriesChanged;
 
364
  end;
 
365
end;
 
366
 
 
367
function TChartListbox.FindSeriesIndex(ASeries: TCustomChartSeries): Integer;
 
368
{ searches the internal legend items list for the specified series }
 
369
begin
 
370
  for Result := 0 to FLegendItems.Count - 1 do
 
371
    if GetSeries(Result) = ASeries then exit;
 
372
  Result := -1;
 
373
end;
 
374
 
 
375
function TChartListbox.GetChecked(AIndex: Integer): Boolean;
 
376
{ report the checked status. This is determined by the visibility of the
 
377
  series with the given index. }
 
378
var
 
379
  ser: TBasicChartSeries;
 
380
begin
 
381
  ser := GetSeries(AIndex);
 
382
  Result := (ser <> nil) and ser.Active;
 
383
end;
 
384
 
 
385
function TChartListbox.GetSeries(AIndex: Integer): TCustomChartSeries;
 
386
{ extracts, for the given index, the series from the internal
 
387
  legend items list. }
 
388
var
 
389
  legitem: TLegendItem;
 
390
begin
 
391
  legitem := FLegendItems[AIndex];
 
392
  if (legitem <> nil) and (legitem.Owner is TCustomChartSeries) then
 
393
    Result := TCustomChartSeries(legitem.Owner)
 
394
  else
 
395
    Result := nil;
 
396
end;
 
397
 
 
398
function TChartListbox.GetSeriesCount : Integer;
 
399
{ determines the number of series displayed in the listbox.
 
400
  Note that this may be different from the Chart.SeriesCount if
 
401
  RemoveSeries has been called }
 
402
begin
 
403
  Result := FLegendItems.Count;
 
404
end;
 
405
 
 
406
procedure TChartListbox.KeyDown(var AKey: Word; AShift: TShiftState);
 
407
{ allows checking/unchecking of items by means of pressing the space bar }
 
408
begin
 
409
  if
 
410
    (AKey = VK_SPACE) and (AShift = []) and
 
411
    (cloShowCheckboxes in Options) and (ItemIndex >= 0)
 
412
  then begin
 
413
    ClickedCheckbox(ItemIndex);
 
414
    AKey := VK_UNKNOWN;
 
415
  end
 
416
  else
 
417
    inherited KeyDown(AKey, AShift);
 
418
end;
 
419
 
 
420
// Item height is determined as maximum of:
 
421
// checkbox height, text height, ItemHeight property value.
 
422
procedure TChartListbox.MeasureItem(AIndex: Integer; var AHeight: Integer);
 
423
begin
 
424
  inherited MeasureItem(AIndex, AHeight);
 
425
  AHeight := Max(CalculateStandardItemHeight, AHeight);
 
426
  if cloShowCheckboxes in Options then
 
427
    AHeight := Max(AHeight, GetSystemMetrics(SM_CYMENUCHECK) + 2);
 
428
end;
 
429
 
 
430
procedure TChartListbox.MouseDown(
 
431
  AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer);
 
432
{ standard MouseDown handler: checks if the click occured on the checkbox,
 
433
  on the series icon, or on the text.
 
434
  The visibility state of the item's series is changed when clicking on the
 
435
  checkbox, and an event OnCheckboxClick is generated.
 
436
  An event OnSeriesIconClick is generated when double-clicking on the
 
437
  series icon; the method stores the series list index here.
 
438
  An event OnItemClick is generated when the click occured neither on the
 
439
  checkbox nor the series icon.
 
440
}
 
441
var
 
442
  rcb, ricon: TRect;
 
443
  index: Integer;
 
444
  p: TPoint;
 
445
begin
 
446
  FSeriesIconClicked := -1;
 
447
  try
 
448
    if AButton <> mbLeft then exit;
 
449
    p := Point(AX, AY);
 
450
    index := GetIndexAtXY(AX, AY);
 
451
    if index < 0 then exit;
 
452
    CalcRects(ItemRect(index), rcb, ricon);
 
453
    if (cloShowCheckboxes in Options) and IsPointInRect(p, rcb) then
 
454
      ClickedCheckbox(index)
 
455
    else if (cloShowIcons in Options) and IsPointInRect(p, ricon) then
 
456
      // Remember clicked index for the double click event.
 
457
      FSeriesIconClicked := index
 
458
    else
 
459
      ClickedItem(index);
 
460
  finally
 
461
    inherited MouseDown(AButton, AShift, AX, AY);
 
462
  end;
 
463
end;
 
464
 
 
465
procedure TChartListbox.Populate;
 
466
{ populates the listbox with all series contained in the chart. Use the event
 
467
  OnPopulate if you don't omit special series from the listbox (RemoveSeries) }
 
468
var
 
469
  li: TLegendItem;
 
470
begin
 
471
  Items.BeginUpdate;
 
472
  try
 
473
    Items.Clear;
 
474
    if FChart = nil then exit;
 
475
    FreeAndNil(FLegendItems);
 
476
    FLegendItems := CreateLegendItems;
 
477
    Chart.Legend.SortItemsByOrder(FLegendItems);
 
478
    for li in FLegendItems do
 
479
      // The caption is owner-drawn, but add it anyway for user convenience.
 
480
      Items.AddObject(li.Text, li);
 
481
    if Assigned(OnPopulate) then
 
482
      OnPopulate(Self);
 
483
  finally
 
484
    Items.EndUpdate;
 
485
  end;
 
486
end;
 
487
 
 
488
procedure TChartListbox.RemoveSeries(ASeries: TCustomChartSeries);
 
489
{ removes the series from the listbox, but keeps it in the chart }
 
490
var
 
491
  index: Integer;
 
492
begin
 
493
  index := FindSeriesIndex(ASeries);
 
494
  if index = -1 then exit;
 
495
  FLegendItems.Delete(index);
 
496
  Items.Delete(index);
 
497
  Invalidate;
 
498
end;
 
499
 
 
500
procedure TChartListbox.SeriesChanged(ASender: TObject);
 
501
{ Notification procedure of the listener. Responds to chart broadcasts
 
502
  by populating the listbox with the chart's series }
 
503
begin
 
504
  if
 
505
    (ASender is TCustomChartSource) and
 
506
    not (cloRefreshOnSourceChange in Options)
 
507
  then
 
508
    exit;
 
509
  Populate;
 
510
  { in case of radiobutton mode, it is necessary to uncheck the other
 
511
    series; there can be only one active series in this mode }
 
512
  if
 
513
    (ASender is TCustomChartSeries) and (ASender as TCustomChartSeries).Active
 
514
  then
 
515
    EnsureSingleChecked(FindSeriesIndex(ASender as TCustomChartSeries))
 
516
  else
 
517
    EnsureSingleChecked;
 
518
end;
 
519
 
 
520
procedure TChartListbox.SetChart(AValue: TChart);
 
521
{ connects the ListBox to the chart }
 
522
begin
 
523
  if FChart = AValue then exit;
 
524
 
 
525
  if FListener.IsListening then
 
526
    FChart.Broadcaster.Unsubscribe(FListener);
 
527
  FChart := AValue;
 
528
  if FChart <> nil then
 
529
    FChart.Broadcaster.Subscribe(FListener);
 
530
  SeriesChanged(Self);
 
531
end;
 
532
 
 
533
procedure TChartListbox.SetChecked(AIndex: Integer; AValue: Boolean);
 
534
{ shows/hides the series with the specified index of its listbox item.
 
535
  In case of radiobutton style, all other series are hidden if AValue=true }
 
536
var
 
537
  ser: TCustomChartSeries;
 
538
begin
 
539
  ser := GetSeries(AIndex);
 
540
  if (ser = nil) or (ser.Active = AValue) then exit;
 
541
  // Do not listen to this change since we know what changed.
 
542
  FListener.OnNotify := nil;
 
543
  try
 
544
    ser.Active := AValue;
 
545
  finally
 
546
    FListener.OnNotify := @SeriesChanged;
 
547
  end;
 
548
  if AValue then
 
549
    EnsureSingleChecked(FindSeriesIndex(ser));
 
550
  Invalidate;
 
551
end;
 
552
 
 
553
procedure TChartListbox.SetCheckStyle(AValue: TCheckBoxesStyle);
 
554
{ selects "checkbox" or "radiobutton" styles. In radiobutton mode, only
 
555
  one series can be visible }
 
556
begin
 
557
  if FCheckStyle = AValue then exit;
 
558
  FCheckStyle := AValue;
 
559
  EnsureSingleChecked;
 
560
  Invalidate;
 
561
end;
 
562
 
 
563
procedure TChartListbox.SetOnAddSeries(AValue: TChartListboxAddSeriesEvent);
 
564
begin
 
565
  if TMethod(FOnAddSeries) = TMethod(AValue) then exit;
 
566
  FOnAddSeries := AValue;
 
567
  Populate;
 
568
end;
 
569
 
 
570
procedure TChartListbox.SetOnPopulate(AValue: TNotifyEvent);
 
571
begin
 
572
  if TMethod(FOnPopulate) = TMethod(AValue) then exit;
 
573
  FOnPopulate := AValue;
 
574
  Populate;
 
575
end;
 
576
 
 
577
procedure TChartListbox.SetOptions(AValue: TChartListOptions);
 
578
begin
 
579
  if FOptions = AValue then exit;
 
580
  FOptions := AValue;
 
581
  EnsureSingleChecked;
 
582
  Invalidate;
 
583
end;
 
584
 
 
585
end.
 
586