2
*****************************************************************************
4
* See the file COPYING.modifiedLGPL.txt, included in this distribution, *
5
* for details about the copyright. *
7
* This program is distributed in the hope that it will be useful, *
8
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
9
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
11
*****************************************************************************
13
Authors: Alexander Klenin
24
Classes, Controls, Graphics, StdCtrls, TAChartUtils, TAGraph;
28
{ TChartNavScrollBar }
30
TChartNavScrollBar = class (TCustomScrollBar)
32
FAutoPageSize: Boolean;
35
procedure ChartExtentChanged(ASender: TObject);
36
procedure SetAutoPageSize(AValue: Boolean);
37
procedure SetChart(AValue: TChart);
40
AScrollCode: TScrollCode; var AScrollPos: Integer); override;
42
constructor Create(AOwner: TComponent); override;
43
destructor Destroy; override;
45
property AutoPageSize: Boolean
46
read FAutoPageSize write SetAutoPageSize default false;
47
property Chart: TChart read FChart write SetChart;
52
property BorderSpacing;
63
property ParentBidiMode;
64
property ParentShowHint;
74
property OnContextPopup;
85
property OnUTF8KeyPress;
90
TChartNavPanel = class(TCustomControl)
93
FLogicalExtentRect: TRect;
94
FOffset: TDoublePoint;
96
FPrevPoint: TDoublePoint;
98
procedure ChartExtentChanged(ASender: TObject);
100
FAllowDragNavigation: Boolean;
102
FDragCursor: TCursor;
103
FFullExtentPen: TPen;
104
FListener: TListener;
105
FLogicalExtentPen: TPen;
107
FProportional: Boolean;
109
procedure SetChart(AValue: TChart);
110
procedure SetDragCursor(AValue: TCursor);
111
procedure SetFullExtentPen(AValue: TPen);
112
procedure SetLogicalExtentPen(AValue: TPen);
113
procedure SetMiniMap(AValue: Boolean);
114
procedure SetProportional(AValue: Boolean);
117
AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer); override;
118
procedure MouseMove(AShift: TShiftState; AX, AY: Integer); override;
120
AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer); override;
122
constructor Create(AOwner: TComponent); override;
123
destructor Destroy; override;
124
procedure Paint; override;
126
property AllowDragNavigation: Boolean
127
read FAllowDragNavigation write FAllowDragNavigation default true;
128
property Chart: TChart read FChart write SetChart;
129
property DragCursor: TCursor read FDragCursor write SetDragCursor default crSizeAll;
130
property FullExtentPen: TPen read FFullExtentPen write SetFullExtentPen;
131
property LogicalExtentPen: TPen read FLogicalExtentPen write SetLogicalExtentPen;
132
property MiniMap: Boolean read FMiniMap write SetMiniMap default false;
133
property Proportional: Boolean read FProportional write SetProportional default false;
134
property Shift: TShiftState read FShift write FShift default [ssLeft];
144
Forms, SysUtils, TAGeometry;
149
CHART_COMPONENT_IDE_PAGE, [TChartNavScrollBar, TChartNavPanel]);
152
{ TChartNavScrollBar }
154
procedure TChartNavScrollBar.ChartExtentChanged(ASender: TObject);
160
if Chart = nil then exit;
161
fe := Chart.GetFullExtent;
162
le := Chart.LogicalExtent;
163
if le = EmptyExtent then
167
fw := fe.b.X - fe.a.X;
171
Position := Round(WeightedAverage(Min, Max, (le.a.X - fe.a.X) / fw));
172
lw := le.b.X - le.a.X;
175
fw := fe.b.Y - fe.a.Y;
179
Position := Round(WeightedAverage(Max, Min, (le.a.Y - fe.a.Y) / fw));
180
lw := le.b.Y - le.a.Y;
183
if AutoPageSize and not (csDesigning in ComponentState) then
184
PageSize := Round(lw / fw * (Max - Min));
187
constructor TChartNavScrollBar.Create(AOwner: TComponent);
189
inherited Create(AOwner);
190
FListener := TListener.Create(@FChart, @ChartExtentChanged);
193
destructor TChartNavScrollBar.Destroy;
195
FreeAndNil(FListener);
199
procedure TChartNavScrollBar.Scroll(
200
AScrollCode: TScrollCode; var AScrollPos: Integer);
205
inherited Scroll(AScrollCode, AScrollPos);
206
if Chart = nil then exit;
209
fe := Chart.GetFullExtent;
210
le := Chart.LogicalExtent;
211
if le = EmptyExtent then
215
d := WeightedAverage(fe.a.X, fe.b.X, Position / w);
216
le.b.X += d - le.a.X;
220
d := WeightedAverage(fe.b.Y, fe.a.Y, Position / w);
221
le.b.Y += d - le.a.Y;
225
Chart.LogicalExtent := le;
226
// Focused ScrollBar is glitchy under Win32, especially after PageSize change.
227
if (GetParentForm(Chart) <> nil) and GetParentForm(Chart).Active then
231
procedure TChartNavScrollBar.SetAutoPageSize(AValue: Boolean);
233
if FAutoPageSize = AValue then exit;
234
FAutoPageSize := AValue;
235
ChartExtentChanged(Self);
238
procedure TChartNavScrollBar.SetChart(AValue: TChart);
240
if FChart = AValue then exit;
242
if FListener.IsListening then
243
FChart.ExtentBroadcaster.Unsubscribe(FListener);
245
if FChart <> nil then
246
FChart.ExtentBroadcaster.Subscribe(FListener);
247
ChartExtentChanged(Self);
252
procedure TChartNavPanel.ChartExtentChanged(ASender: TObject);
258
constructor TChartNavPanel.Create(AOwner: TComponent);
263
inherited Create(AOwner);
264
FListener := TListener.Create(@FChart, @ChartExtentChanged);
265
FFullExtentPen := TPen.Create;
266
FFullExtentPen.OnChange := @ChartExtentChanged;
267
FLogicalExtentPen := TPen.Create;
268
FLogicalExtentPen.OnChange := @ChartExtentChanged;
269
FLogicalExtentRect := Rect(0, 0, 0, 0);
271
Height := DEF_HEIGHT;
272
FAllowDragNavigation := true;
273
FDragCursor := crSizeAll;
277
destructor TChartNavPanel.Destroy;
279
FreeAndNil(FListener);
280
FreeAndNil(FFullExtentPen);
281
FreeAndNil(FLogicalExtentPen);
285
procedure TChartNavPanel.MouseDown(
286
AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer);
288
if (Chart <> nil) and AllowDragNavigation then begin
289
FPrevPoint := (DoublePoint(AX, Height - AY) - FOffset) / FScale;
291
(AShift = Shift) and IsPointInRect(Point(AX, AY), FLogicalExtentRect);
292
if FIsDragging then begin
293
FOldCursor := Cursor;
294
Cursor := DragCursor;
297
inherited MouseDown(AButton, AShift, AX, AY);
300
procedure TChartNavPanel.MouseMove(AShift: TShiftState; AX, AY: Integer);
305
if (Chart <> nil) and FIsDragging then begin
306
p := (DoublePoint(AX, Height - AY) - FOffset) / FScale;
307
le := Chart.LogicalExtent;
308
le.a += p - FPrevPoint;
309
le.b += p - FPrevPoint;
310
Chart.LogicalExtent := le;
313
inherited MouseMove(AShift, AX, AY);
316
procedure TChartNavPanel.MouseUp(
317
AButton: TMouseButton; AShift: TShiftState; AX, AY: Integer);
320
Cursor := FOldCursor;
321
FIsDragging := false;
322
inherited MouseUp(AButton, AShift, AX, AY);
325
procedure TChartNavPanel.Paint;
327
function GraphRect(ARect: TDoubleRect): TRect;
330
a := a * FScale + FOffset;
331
b := b * FScale + FOffset;
333
Round(a.X), Height - Round(b.Y), Round(b.X), Height - Round(a.Y));
338
fe, le, ext: TDoubleRect;
340
oldAxisVisible: Boolean;
343
if Chart = nil then exit;
344
fe := Chart.GetFullExtent;
345
le := Chart.LogicalExtent;
346
if le = EmptyExtent then
349
ExpandRect(ext, le.a);
350
ExpandRect(ext, le.b);
352
if (sz.X <= 0) or (sz.Y <= 0) then exit;
353
FScale := DoublePoint(Width, Height) / sz;
354
FOffset := ZeroDoublePoint;
355
if Proportional then begin
356
if FScale.X < FScale.Y then begin
357
FScale.Y := FScale.X;
358
FOffset.Y := (Height - sz.Y * FScale.Y) / 2;
361
FScale.X := FScale.Y;
362
FOffset.X := (Width - sz.X * FScale.X) / 2;
365
FOffset -= ext.a * FScale;
367
feRect := GraphRect(fe);
368
if MiniMap then begin
369
oldAxisVisible := Chart.AxisVisible;
370
Chart.AxisVisible := false;
371
Chart.PaintOnAuxCanvas(Canvas, feRect);
372
Chart.AxisVisible := oldAxisVisible;
375
Canvas.Brush.Color := Chart.BackColor;
376
Canvas.Brush.Style := bsSolid;
377
Canvas.FillRect(ClientRect);
379
Canvas.Brush.Style := bsClear;
380
Canvas.Pen := FullExtentPen;
381
Canvas.Rectangle(feRect);
382
Canvas.Pen := LogicalExtentPen;
383
FLogicalExtentRect := GraphRect(le);
384
Canvas.Rectangle(FLogicalExtentRect);
387
procedure TChartNavPanel.SetChart(AValue: TChart);
389
if FChart = AValue then exit;
391
if FListener.IsListening then
392
FChart.ExtentBroadcaster.Unsubscribe(FListener);
394
if FChart <> nil then
395
FChart.ExtentBroadcaster.Subscribe(FListener);
396
ChartExtentChanged(Self);
399
procedure TChartNavPanel.SetDragCursor(AValue: TCursor);
401
if FDragCursor = AValue then exit;
402
FDragCursor := AValue;
404
Cursor := FDragCursor;
407
procedure TChartNavPanel.SetFullExtentPen(AValue: TPen);
409
if FFullExtentPen = AValue then exit;
410
FFullExtentPen := AValue;
414
procedure TChartNavPanel.SetLogicalExtentPen(AValue: TPen);
416
if FLogicalExtentPen = AValue then exit;
417
FLogicalExtentPen := AValue;
421
procedure TChartNavPanel.SetMiniMap(AValue: Boolean);
423
if FMiniMap = AValue then exit;
428
procedure TChartNavPanel.SetProportional(AValue: Boolean);
430
if FProportional = AValue then exit;
431
FProportional := AValue;