home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Chip 2001 October
/
Chip_2001-10_cd1.bin
/
zkuste
/
delphi
/
kompon
/
d123456
/
CHEMPLOT.ZIP
/
TPlot
/
Plot.pas
< prev
next >
Wrap
Pascal/Delphi Source File
|
2001-07-31
|
367KB
|
10,249 lines
unit Plot;
{$I Plot.inc}
{-----------------------------------------------------------------------------
The contents of this file are subject to the Q Public License
("QPL"); you may not use this file except in compliance
with the QPL. You may obtain a copy of the QPL from
the file QPL.html in this distribution, derived from:
http://www.trolltech.com/products/download/freelicense/license.html
The QPL prohibits development of proprietary software.
There is a Professional Version of this software available for this.
Contact sales@chemware.hypermart.net for more information.
Software distributed under the QPL is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the QPL for
the specific language governing rights and limitations under the QPL.
The Original Code is: Plot.PAS, released 12 September 2000.
The Initial Developer of the Original Code is Mat Ballard.
Portions created by Mat Ballard are Copyright (C) 1999 Mat Ballard.
Portions created by Microsoft are Copyright (C) 1998, 1999 Microsoft Corp.
All Rights Reserved.
Contributor(s): Mat Ballard e-mail: mat.ballard@chemware.hypermart.net.
Acknowledgements to:
Anders Melanders
- TGifImage (http://www.melander.dk)
Edmund H. Hand
- pnglib
Jack Goman <jack@SharePower.VirtualAve.net>
- PngUnit
Eric Engler (http://www.geocities.com/SiliconValley/Network/2114/)
- TPngImage in Pnglib24a
Atanas Stoyanov (http://www.poboxes.com/astoyanov/) and his marvelous
- MemProof
Renate Schaaf (schaaf@math.usu.edu), 1993
Alin Flaider (aflaidar@datalog.ro), 1996
Hallvard Vassbotn (hallvard.vassbotn@c2i.net),
- TParser10
Stefan Hoffmeister (Stefan.Hoffmeister@Uni-Passau.de), 1997
- TParser10,
- Linux LoadStr and LoadBitmapFromResource bugfix,
- most useful comments on the kylix newsgroups
John Shemitz
- second most useful comments on the kylix newsgroups,
and the rotated Kylix text code.
Thanks (or blame) to:
http://www.freetranslation.com/
for the French, German, Italian, Norwegian, Portuguese and Spanish translations.
Thanks to Amy Khai Luong <akluong@sandia.gov> for help in pointers and solutions to D6 compatibility.
Thanks to Rakesh Nagarajan <rakesh@pathbox.wustl.edu> for help in pointers and solutions to BCB5 compatibility.
Last Modified: 29/07/2001
Current Version: 2.32
You may retrieve the latest version of this file from:
http://Chemware.hypermart.net/
This work was created with the Project JEDI VCL guidelines:
http://www.delphi-jedi.org/Jedi:VCLVCL
in mind.
Kylix issues:
- Yes, there is no printing (yet)
- Yes, there is no GIF support (yet)
- Note the peculiar work-arounds that apply to resources:
you have to patch QGraphics see ResourceFix.pas, or FreeClx on SourceForge.
- No, everything else works.
- Help does not work yet - but check out:
http://Chemware.hypermart.net/tplot/help/ to see where we are heading
Kylix tricks and traps:
- symlinks: put Symlinks from your home directory to your
development and kylix directories:
>cd ~
>ln -s /opt/kylix
>ln -s /opt/kylix/help kylixhelp
>ln -s /mnt/dos/delphi/components/tplot
- case sensitivity - filenames, resources, unit names, etc, etc, etc.
- permissions: suggest you make $(KYLIX)/bin user-writable, and put final binaries there
- put XKill on the taskbar - you'll need it !
- from the command line: "ps -A", then "kill nnn"
- CLX objects and classes don't correspond 100% to VCL ones:
there are some old properties and methods missing, and some new ones
- eg: QForms.TForm is different from Forms.TForm.
This means you can open a form saved from Delphi into Linux, and vice-versa,
_BUT_ you will get errors about non-existent properties. eg:
Delphi bitches about:
BorderStyle,
HelpType,
Color (different clXXXs),
Font.Weight
Kylix bitches about:
BorderStyle,
If you don't save a form from the current IDE, then it will hopefully compile
(and run) OK, BUT you may get exceptions when you open a dialog.
Known Issues:
- D1 and D2 are no longer supported. The chosen localization technique (resourcestring)
is not supported under D1 and D2.
- Printing does not (yet) work under Kylix.
- TToolBar DOES NOT WORK if it Plot property is set in the IDE !
Please set its plot property in code ! (See Normal1.pas)
Also, you cannot select individual buttons until AFTER you have
"View as Text" then "View As Form".
- $IFDEFs: TPlot _WAS_ used in a Delphi 1 application, and will be migrated
to Linux. $IFDEFs are therefore unavoidable.
- Explicit dereferencing (eg: XData^[i]) _IS_ required for compatibility
with Delphi 1. Besides, I prefer it to distinguish dynamic from static arrays.
- Since TPlotMenu, etc are useless without TPlot, there is only the one
registration unit: TPlot_Reg.pas.
- if you work across different versions of Delphi, ALWAYS save any form from
the lowest version of Delphi (eg: Delphi 1), because otherwise the DFM
files will contain extra properties that will cause stream read errors in
lower versions of Delphi.
Comparison to TChart version 4 (in Delphi 5):
- Compare Normal.exe to TChartNormal.exe with "Fastline", then "Line" for symbols :
10 July 2001.
Number of Points TPlot TChart
fps K fps K
Winnt 4, sp5, no IDE:
101 28.9 2836 13.2 2108
9,997 6.61 2956 2.67 2628
10,001 19.8 2948 2.56 2644
99,889 7.71 3688 0.38 6084
992,403 1.42 10588 0.05 41088
With square Symbols, "Line":
101 28.9 2960 12.4 2120
99,889 to be fixed 0.15 6096
No TPlotImageList, TPlotMenu, TPlotToolBar:
101 39.0 2572
All - Shared = Total
Mandrake 7.2 std, no IDE):
101 10.3 8216 - 5808 = 2408
99,889 6.90 9000 - 5832 = 3168
992,403 1.53 15988 - 5844 = 10144
Mandrake 7.2 std under Kylix IDE:
101 10.3 8220 - 5784 = 2436
99,889 6.10 9004 - 5808 = 3196
992,403 1.52 15992 - 5820 = 10172
No TPlotImageList, TPlotMenu, TPlotToolBar:
101 12.15 7620 - 5572 = 2028
Comments:
1. TPlot is 3 - 20 x faster than TChart.
2. The TPlot demo also has the TPlotToolBar, which the TChart demo does not.
Resizing and redrawing this also adds to the TPlot times.
3. It uses more memory (700K) with a small number of points, mainly due to
TPlotMenu, TPlotImageList, and TPlotToolBar.
It uses much less memory (75% less !) with a large number of points.
4. Although not directly visible in these numbers, large series are built
much more quickly under Linux => memory management is more efficient.
This is also seen in the superior times of large data sets.
Feature Comparison:
TPlot TChart
Data file IO yes no
Extensible file IO yes no
Click & drag yes no
objects
Popup menu yes no
Main menu yes no
Toolbar yes no
Context sensitive yes no
Web images yes only GIF in Pro version
Web pages yes no
Sticky notes yes no
Dynamic, yes no
movable axes
Math functions:
User defined yes no
Average yes yes
Compression yes no
Contraction yes no
Differentiation yes no
Integration yes no
Linear Fits yes no
Moving Average yes no
Nearest Point yes no
Position yes no
Smoothing yes no
Splines yes no
True 3D plots yes Pro version
Database support in development yes
TO BE DONE:
- Right click on legend ? Edit Series ?
- Fix severe TPlotToolBar problem:
works fine when created dynamically, but dies in constructor with
"Component not found: TToolButton" when run from IDE placement.
- debug and thoroughly test TDBPlot
- get the HTML Help system working under Linux
Future Development:
- Printing under Kylix.
- streaming of component properties sometimes does not work
eg: try setting Axis widths to different values
- implementation of GIFs under Linux:
- addition of a "Financial" menu, similar to "File", "Edit", etc, and
populate it with goodies like RSI.
- re-write the "DetermineMenuVisibility and ...Enabledness so that they can
control the visibility of buttons in TPlotToolBar.
- Marry Parser10 to a good minimization algorithm (eg: Simplex) so that users
can fit _ANY_ function.
- add some keyboard input ? not straightforward
- rationalization and rotation of 3D axes
- 0 deg to 360 deg on Polars ?
- ptGantt ?
- drag points ?
- OpenGL 3D surfaces ?
- add Polynomial fits (CurveFit.pas).
- move "Result" of fits from TPlot to TSeries -> each series can have its own fit
History:
2.32 26 Jul 2001: Change most "with xxx do" blocks to "xxx."
Fixed "Canvas.Start" bug in GetDrawing under Linux, but printing still doesn't work.
Remove the 3rd party components from the Packages.
This causes warnings, but this is better than the "Missing file" errors.
They can be added back in by the user.
2.31 25 Jul 2001: Added GetPlotTypeAsString, fixed TPlotToolBar order bug in BCB.
2.30 23 Jul 2001: Modified AxisEditor and SeriesEditor to handle these new properties.
2.29 22 Jul 2001: Added Limits (Upper, Lower and Visible) to Axes and
ShadeLimits and DrawShades to Series (these are complementary).
2.28 18 Jul 2001: Add financial menu items, and skeleton functions.
2.27 18 Jul 2001: Put $I Plot.inc and $IFDEFs into Plot200_R50.dpk to fix "File not found" issues with 3rd party components.
Seems to work. Will extend to the D4 and Kylix versions.
2.26 17 Jul 2001: Completely rewrite Draw3DContour: implement High detail plots.
Add ContourWireFrame property.
2.25 17 Jul 2001: Implement DrawLineContour.
Add ContourStart and ContourInterval properties.
Modify Properties dialog to include these two new properties.
2.24 16 Jul 2001: Completely rewrite DrawContour to make it simpler, quicker, less fragile,
more compatible with the other 3D methods, especially future OpenGl extensions.
2.23 12 Jul 2001: Added Properties Property and PropertyEditor.
2.22 6 Jul 2001: Translations finished. Resize all labels and forms, debug.
Originals are in TPlot.xls, thence the "lang" subdirectory.
NB: these are machine translations, and so are probably very
humorous and misleading !
2.21 3 Jul 2001: Perform translations !
2.20 2 Jul 2001: Move all ResourceStrings into files for translation,
and load according to the Language defines in Misc.pas.
2.19 1 Jul 2001: place _ALL_ string resources into ResourceString statements.
2.18 30 Jun 2001: rewrite TPlot.CreateMenus to use new ResourceString instead of
the old Strlst32.res resource file.
2.17 26 Jun 2001: Place Plot menu and Caption resources into resourcestring ->
no longer need StrLst32.res, or resource editor.
2.16 16 Jun 2001: Make Selection: TAngleRect. This allows:
Selection, Clicking and dragging of the Z Axis.
Work over drawing Walls and Grids.
Work over SetAxisDimensions.
2.15 14 Jun 2001: Work over the TAxis.Draw method to eliminate bugs in click-and-drag selection (FLabels).
2.14 12 Jun 2001: Add GridColor and WallColor properties, and user interfaces thereto.
2.13 9 Jun 2001: Create TAngleRect - this will replace TRectangle as the ancestor
for many sub-components: eg: TAxis.
Reason: this will make ZAxes and titles clickable.
2.12 6 Jun 2001: DrawWalls for better 3D rendition.
Fixed minor TickDirection bug in TAxisEditorForm.
Fixed minor bug in rendition of labels on X Axis (Up not done properly).
2.11 5 Jun 2001: Much behind-the-scenes work on Linux:
printing, jumping to web pages, mailing, and helping.
Pity none of it works yet.
2.10 2 Jun 2001: Created 3DColumn plot type, implemented its TSeriesList.Draw method,
modified TPlotPropertyEditorForm to manage it.
Added ZLength property to TPlotPropertyEditorForm.
2.09 30 May 2001: Created Right Click and Drag popup menu - our first "gesture".
Revised handling of its menuitems OnClick events and MouseUp methods.
Added TDBPlot to BCB project - but something is wrong !
2.08 29 May 2001: renamed Zoom.pas to PlotZoom.pas to avoid namespace clash with RALib !!!
Fixed scaling bugs with 3D and Bubble plots.
Added Linearize and Zero functions.
2.07 16 May 2001: renamed ToolEdit.pas to Plottooledit.pas to avoid namespace clash with RXLib
Reworked autoscaling of axes.
Fixed some TDBPlot issues (FReadOnly replaced by FDataLink.ReadOnly),
but still not happy with it.
2.06 16 May 2001: Made many changes to graphics handling.
There are now Bitmap, Drawing, GIF and Png properties.
Saving or copying these now becomes a one-liner.
Great for all those web developers out there.
Massive amount of work on the help file to bring it up to date.
Create ActiveX control.
2.05 16 May 2001: Changed from Jack Goman's pngunit to Eric Engler's Pngimage
to enable a Png property under Windows.
2.04 16 May 2001: Made Draw public
2.03 16 May 2001: Add Drawing property
2.02 11 May 2001: Add Png property
2.01 11 May 2001: Get SaveAsPNG working under Kylix with Jon Shemitz's help.
2.00 10 May 2001: Bump up version number and release.
1.81 9 May 2001: Added TDBPlot projects to Kylix project group
1.80 8 May 2001: Added XYFastAt property
1.79 7 May 2001: Modified TSeries.Draw to use a different algorithm if
NoPts > 10000.
1.78 6 May 2001: Rewrote loading of binary files to handle XText data.
1.77 5 May 2001: Fixed bugs in reading of XText data from text files.
1.76 4 May 2001: Fixed bugs in display of XText data in Axis.
1.75 3 May 2001: Modified TCustomPlot.SetPlotMenu and TCustomPlot.SetPlotToolBar
to correctly apply the Popupoptions to TPlotMenu and TPlotToolBar;
also fixed bugs in the ApplyOptions methods of those two components.
1.74 2 May 2001: Added "ApplyOptions" to TPlotMenu.
1.73 2 May 2001: Added the CanConfigure property to TPlotToolBar
1.72 2 May 2001: Removed TPlotToolBar property editor -
Visibility of buttons now set by TPlot.PopupOptions.
1.71 1 May 2001: Fixed numerous features/bugs in TPlotToolBar under Kylix,
eg: "Buttons" vs "Controls", different indexing.
1.70 30 Apr 2001: Re-worked file and stream loading and saving,
moving most of it into TSeriesList.
1.69 29 Apr 2001: added PageButtons in Zoomed mode.
1.68 26 Apr 2001: Re-build BCB3 projects, and fix buglets associated with BCB compatibility:
TPlotToolBar in particular.
1.67 26 Apr 2001: Change EditPoint to be D1 compatible.
1.66 25 Apr 2001: Re-work Parser, ParseData and ConvertTextData to handle
matrix of Z values (Eugene Parsons).
1.65 25 Apr 2001: Total re-write of TSeries.DrawPie. Ain't it pretty now ?
1.64 25 Apr 2001: Modify ContourDetail to add cdVHigh, then bump all up by one,
then make cdLow rectangles, cdMedium triangles, cdHigh points, cdVHigh filled.
1.63 22 Apr 2001: Added ZLength property, other fixes.
1.62 19 Apr 2001: Finally got TPlotToolBar working properly !
1.61 19 Apr 2001: Enabled multiline Title.Captions.
1.60 19 Apr 2001: Fixed Columnses visibility buglet.
1.59 19 Apr 2001: Moved Legend drawing code into TLegend, and added check marks.
1.58 19 Apr 2001: Implemented the lfSI format for output (M, K, etc)
1.57 19 Apr 2001: Fixed fiendish little bug that causes repeated redraw of plots on file opening.
1.56 18 Apr 2001: Added XTEXT support to text file IO; Problem: Binary file IO ?
1.55 18 Apr 2001: Added MultiJoin property to better manage High-Low-open-Close plots.
1.54 18 Apr 2001: Augmented the Import Parser to cope with XYZ triple text files.
1.53 16 Apr 2001: Fixed bugs in DataEditor.
1.52 16 Apr 2001: Fixed "ZoomOutClick" bugs.
1.51 16 Apr 2001: Implemented "NewSeriesClick".
1.50 11 Apr 2001: Added ptBubble PlotType, and all associated methods and variables.
1.49 9 Apr 2001: Fixed/upgraded Parser, ConvertTextData and ParseData to import
3D data.
1.48 4 Apr 2001: Implemented Functions using TParser10- eat your heart out David B !
1.47 3 Apr 2001: Routed all dialog geometries into Misc.SetDialogGeometry()
1.46 2 Apr 2001: ... then fixed Linux color bug in the text output on Pie graphs
1.45 1 Apr 2001: Finally nailed correct positioning of the text output on Pie graphs
1.44 29 Mar 2001: Much work fixing Linux bugs: LoadStr for string resources (menus),
loading bitmaps (many thanks to Stephan Hoffmeister), TCanvas.Pie, etc.
1.43 28 Mar 2001: Major overhaul of dialogs: add "Apply" button and code to most.
1.42 27 Mar 2001: Get property editors to compile. "About" works once, but then
Kylix freezes whenever TPlot is installed.
1.41 27 Mar 2001: Fix Polygon issue, somehow. And other Kylix buglets.
1.40 23 Mar 2001: Kylix finally arrives. Fix many issues, but not all. See "Traps" below.
1.39 15 Mar 2001: Changed licensing from MPL to QPL.
In practise, this only affects commercial developers.
1.38 15 Mar 2001: Added TPlotComponentEditor to Plot_reg.pas to give design-time menus.
1.37 15 Mar 2001: Revise TSeries.DrawPie to add labels.
1.36 14 Mar 2001: Revise TSeries.XStringData extensively.
1.35 12 Mar 2001: Surface many TSeriesList methods in TPlot for TDBPlot to override.
1.34 7 Mar 2001: Revise the OnStyleChange/OnDataChange events in TSeries and TSeriesList
1.33 2 Mar 2001: Begin work on TDBPlot.
1.32 2 Mar 2001: We have a renaming frenzy, to make the purpose of the major
series manipulation functions more obvious.
Add -> AddSeries
AddExternal -> AddExternalSeries
AddInternal -> AddInternalSeries
AddSlice -> AddData
My apologies to all existing users. This will break existing
code, but fixing it should be trivial.
1.31 1 Mar 2001: Rename TSymbol elements to have two leading characters: fixes RTTI bug.
1.30 1 Mar 2001: Replace color selection combo boxes with TColorEdit.
1.29 1 Mar 2001: Replace most combobox items with RTTI generated strings.
1.28 28 Feb 2001: Add Grids due to popular demand (Yuck !).
1.27 28 Feb 2001: Add the TAxis.StepStart property.
Add a scale to ptContour plots.
1.26 27 Feb 2001: Fix bugs in TSeries.GetNearestPieSlice, and refine TSeries.Outline.
1.25 26 Feb 2001: Column, Stacked Column and 100% Column plots added to
GetTheClickedObject (and TSeriesList.GetNearestPoint).
Contemplate releasing next version as 2.0:
reason: TPlot now has 10 different plot types, instead of 1 !
1.24 22 Feb 2001: Refine DrawContour. Implement true WMF and printing. Now looks beautiful !
Add usage hints to PropertiesEdit dialog box.
1.23 21 Feb 2001: Pie plots added to GetTheClickedObject
1.22 20 Feb 2001: Add OnStyleChange event. Route all "Refresh"s through DoStyleChange.
Complete first go at DrawContour.
Add ContourDetail property.
1.21 1 Feb 2001: Add ZAngle, ZLink properties.
Rename pSeries.pas unit to Data.pas, SerList.pas to Datalist.pas
1.20 14 Jan 2001: Modify TSeriesList to add ZData (for 3D)
Create TAngleAxis class, and implement a ZAxis for 3D.
Add the ptError, ptPie, ptPolar and pt3DWire PlotTypes.
Create the NoMath unit, move some stuff into it from Misc.
1.19 9 Dec 2000: Modify movement of Note Pointer: place before selection of
series, and postpend to movement of the Note text.
1.18 8 Dec 2000: Refine SetPlotType so that each plot type initially displays
its features better.
1.17 6 Dec 2000: Add ptStack and ptNormStack PlotTypes types,
and implement their drawing routines.
1.16 1 Dec 2000: Add ColumnGap property.
1.15 16 Nov 2000: Implement TNote functionality: NewNote, DeleteNote, etc.
1.14 13 Nov 2000: Add Misc.TextOutVertical, and employ in various locations;
benefit: will work under Linux (look into native X calls later).
1.13 7 Nov 2000: Add sLeftDash and sRightDash to TSymbol, and to TSeries.DrawSymbol.
1.12 1 Nov 2000: Create TNote sub-component.
1.11 16 Oct 2000: Add "Compress Series" and "Compress All Series", and associated
CompressSeriesClick and CompressAllSeriesClick. Tidied up:
Contract originally compressed; now it really does contract.
Remove ability to clone X Axis.
Add LabelText to Axes, mainly for Column usage.
Fix Instruction property bug in IDE.
1.10 9 Oct 2000: Add and integrate Column capability with TPlotType type and PlotType properties
and TSeriesList.DrawColumns.
Consolidate some TCustomPlot.xxxClick methods.
****************************
*** Borland BC++ support ***
****************************
1.02 25 Sept 2000: add and integrate High-Low-Close capability with
TSeriesList.DrawMultiple and TSeriesList.DrawHistoryMultiple;
Hide menu visibility routine from D1 to avoid 64K problems.
1.01 21 Sept 2000: fix FontWidth bug in TAxis.Draw
add TPlotType type,
add PlotType and Multiplicity properties
add LabelText property to TAxis (for columns)
18 Sept 2000: delete PlotList.pas (replaced by SerList.pas);
remove GifPng from Plot dpks;
re-create saved files.
1.00 13 Sept 2000: Release version 1.00
-----------------------------------------------------------------------------}
interface
uses
Classes, SysUtils, TypInfo,
{$IFDEF NO_MATH}NoMath,{$ELSE}Math,{$ENDIF}
{$IFDEF WINDOWS}
WinTypes, WinProcs,
Buttons, Clipbrd, Controls, Dialogs,
Extctrls, Forms, Graphics, Menus, Printers, Stdctrls,
{$ENDIF}
{$IFDEF WIN32}
Windows,
Buttons, Clipbrd, ComCtrls, Controls, Dialogs,
Extctrls, Forms, Graphics, Menus, Printers, Stdctrls,
{$ENDIF}
{$IFDEF LINUX}
Types, Untranslated,
QTypes, QButtons, QClipbrd, QComCtrls, QControls, QDialogs,
QExtctrls, QForms, QGraphics, QImgList, QMenus, QPrinters, QStdctrls,
{$ENDIF}
{$IFDEF DELPHI1}
Metafile,
{$ENDIF}
{$IFDEF GIF}
GIFImage,
{$ENDIF}
{$IFDEF PNG}
{$IFDEF MSWINDOWS}
Pngimage,
{$ENDIF}
{$ENDIF}
Aboutdlg, Axis, Axisedit, Data, Misc, Optnsdlg, Parser,
Plotdefs, Plotzoom, Propedit, Datalist, Seredit, Titles;
const
SUBHEADER = 'Subheader';
{$IFDEF POLYNOMIAL_FIT}
POLYORDER = 9;
{$ELSE}
POLYORDER = 1;
{$ENDIF}
{$IFDEF DELPHI1}
DEF_EXTENSION = 'plt';
PROP_EXTENSION = 'prp';
{$ELSE}
DEF_EXTENSION = 'plot';
PROP_EXTENSION = 'props';
{$ENDIF}
crScope = 1;
crX = 2;
ImageExtensions: array[0..4] of string =
('wmf', 'emf', 'bmp', 'gif', 'png');
{$IFDEF MSWINDOWS}
PICTURE_TYPES =
'Metafile (picture)|*.wmf'
+ '|Enhanced Metafile (picture)|*.emf'
+ '|Bitmap|*.bmp'
{$IFDEF GIF}
+ '|Compuserve GIF|*.gif'
{$ENDIF}
{$IFDEF PNG}
+ '|Web Graphic|*.png'
{$ENDIF}
;
{$ENDIF}
{$IFDEF LINUX}
PICTURE_TYPES =
'Metafile picture (*.wmf)'
+ '|Enhanced Metafile picture (*.emf)'
+ '|Bitmap (*.bmp)'
{$IFDEF GIF}
+ '|Compuserve GIF (*.gif)'
{$ENDIF}
{$IFDEF PNG}
+ '|Web Graphic (*.png)'
{$ENDIF}
;
{$ENDIF}
type
{NB: many other types are in PlotDefs.pas}
TOnPaintEvent = procedure(Sender: TObject; ACanvas: TCanvas) of object;
TOnFileEvent = procedure(Sender: TObject; TheFile: String) of object;
{When a file is opened or closed, the app can be notified of the new file name
using this event.}
TOnHeaderEvent = procedure(Sender: TObject; TheStream: TMemoryStream) of object;
{When data is opened, the "user-added" Header (eg: the run date, flow rate,
comments, etc) is passed back to the user for processing.}
TOnRequestHeaderEvent = procedure(Sender: TObject; TheStream: TMemoryStream) of object;
{When data is saved or copied, then the "user" can add additional data via the
Header: eg: the run date, flow rate, comments, etc.}
TOnRequestHTMLHeaderEvent = procedure(Sender: TObject; Header: TStringList) of object;
{When data is saved or copied, then the "user" can add additional data via the
Header: eg: the run date, flow rate, comments, etc.}
TOnSelectionEvent = procedure(Sender: TObject; Sel: TRect) of object;
{When the user clicks and drags over a region, this event is fired.}
TOnDualSelectionEvent = procedure(Sender: TObject; Sel1, Sel2: TRect) of object;
{When the user clicks and drags over TWO regions, this event is fired.}
{******************************************************************************}
TCustomPlot = class(TCustomPanel)
private
{property editor variables:}
FAbout: String;
FAxesProperties: String;
FDataProperties: String;
FProperties: String;
FSeriesProperties: String;
{The AxisList is created and managed in the Plot unit and TCustomPlot component.
The specific axes are:
0 .. X Axis
1 .. Primary Y Axis
2 .. Secondary Y Axis
3 .. Tertiary Y Axis
4 .. etc.}
FAxisList: TList;
FBorder: TBorder;
FBubbleSize: TPercent;
FColumnGap: TPercent;
FContourDetail: TContourDetail;
FContourInterval: Single;
FContourStart: Single;
FContourWireFrame: Boolean;
{$IFNDEF DELPHI1}
FCreatedBy: String;
FDescription: String;
{$ENDIF}
FDefaultExtension: String;
FDisplayMode: TDisplayMode;
FDisplayHistory: Single;
FEditable: Boolean;
FFileName, {D:\Data\Delphi\Plot\Test3.csv}
{GetFileExtension, {csv}
{GetFileDriveDir, {D:\Data\Delphi\Plot}
{GetFileName, {Test3.csv}
{GetFileRoot, {Test3}
{where are the file types ?}
OpenDriveDir, {NB: SavePath == FileDriveDir}
OverlayDriveDir, {T:\Projects\}
ImageDriveDir, {D:\Data\Images}
PropsFileName: String;
{What file types ?}
OpenFilterIndex,
SaveFilterIndex,
ImageFilterIndex: Integer;
FGrid: TGridType;
FGridStyle: TPenStyle;
FGridColor: TColor;
FHelpFile: String;
FHighFont: TFont;
FInstructions: TStringList;
{The Legend of Series}
FLegend: TLegend;
FMenuTag: Integer; {may publish later}
FMovable: Boolean;
FMultiplePen: TPen;
FMultiplicity: Byte;
FMultiJoin1, FMultiJoin2: Integer;
FPageButtons: array[0..3] of TBitmap;
FPieRowCount: Byte;
FPlotMenu: TMainMenu;
FPlotToolBar: TToolBar;
FPlotType: TPlotType;
FPopupOptions: TPopupOptions;
FPolarRange: Single;
FPrintOrientation: TPrinterOrientation;
FOutlineWidth: Integer;
{The results of things like least-squares fits:}
FResult: TCaption;
FSaveOptions: TSaveOptions;
FAsText: Boolean; {the current, which depends on the file type and is ORed with FSaveOptions}
{the location of the graph title:}
FScreenJob: TScreenJob;
FTitle: TTitle;
FWallColor: TColor;
FXAxis: TAxis;
FXYFastAt: Longint;
FYAxis: TAxis;
FZAxis: TAngleAxis;
FZLink: Boolean;
{events:}
FOnAfterPaint: TOnPaintEvent;
FOnAfterDraw: TOnPaintEvent;
FOnBeforePaint: TOnPaintEvent;
FOnBeforeDraw: TOnPaintEvent;
FOnStyleChange: TNotifyEvent;
FOnDataChange: TNotifyEvent;
FOnFileOpen: TOnFileEvent;
FOnFileClose: TOnFileEvent;
FOnHeader: TOnHeaderEvent;
FOnHeaderRequest: TOnRequestHeaderEvent;
FOnHTMLHeaderRequest: TOnRequestHTMLHeaderEvent;
FOnSelection: TOnSelectionEvent;
FOnDualSelection: TOnDualSelectionEvent;
{the four borders, clickable by the user:}
LeftBorder: TRectangle;
TopBorder: TRectangle;
RightBorder: TRectangle;
BottomBorder: TRectangle;
{Ignore changes in sub-components during painting:}
IgnoreChanges: Boolean;
{The list of (TRectangle descended) objects on screen:}
ScreenObjectList: TList;
NoBasicScreenObjects: Integer;
{The list of notes:}
//NoteList: TList;
NoteCount: Integer;
{The timer to start click-and-drag operations:}
MouseTimer: TTimer;
{the position of the mousedown:}
MouseStart: TPoint;
{The starting point of click-and-drag operations:
MouseStart: TPoint; - replaced by Selection1}
{which object(s) were clicked ?}
ClickedObjectType: TObjectType;
pClickedObject: Pointer;
SecondClickedObjectType: TObjectType;
pSecondClickedObject: Pointer;
{the starting position of the object:}
ClickedObjectOffset: TPoint;
{the parameters of the line of best fit:}
Slope, Intercept: Single;
//PolyCoeff: array [0..POLYORDER] of Single;
{The rectangular outline of a ScreenObject that is dragged around the screen:}
Selection: TAngleRect;
{The first selection in a Dual Selection operation:}
Sel1, Sel2: TRect;
{Popup menus:}
FPlotPopUpMenu: TPopupMenu;
FDragPopUpMenu: TPopupMenu;
WhichPopUpMenu: TPopupMenu;
WhichPopUpItems: array[0..1] of TMenuItem;
{the in-place editor:}
FFlashEdit: TEdit;
{the currently selected (eg: by a mouse-click) series:}
TheSeries: Integer;
pSeries: TSeries;
ThePointNumber: Integer;
{the currently selected (eg: by a mouse-click) Axis:}
TheAxis: Integer;
pAxis: TAxis;
{The clipboard format number for HTML:}
ClipBoardFormatForHTML: Integer; {aka CF_HTML}
{Overlay Management:}
FirstOverlay: Integer;
BevelGap: Integer;
FileExtensions: array[0..3] of String;
{= (
FDefaultExtension,
'csv',
'txt',
'*');}
FileTypes: String;
{=
'Plot Files|*.' + FDefaultExtension
+ '|Comma Sep Var Files|*.csv'
+ '|Text Files|*.txt'
+ '|All Files|*.*';}
{Get functions}
function GetClickAndDragDelay: Integer;
function GetNoSeries: Word;
function GetNoYAxes: Integer;
function GetSeries(Index: Integer): TSeries;
function GetNoteFromUser: Boolean;
function GetSeriesFromUser: Boolean;
function GetAxisFromUser(StartAxis: Word): Boolean;
function GetFilterIndex(Ext: String): Integer;
{$IFDEF COMPILER4_UP}
{while TImageList exists from Delphi 2 onwards, TMenu and TPopupMenu
do not have an Images property until Delphi 4}
function GetImages: TImageList; {TCustomImageList}
procedure SetImages(Value: TImageList);
{$ENDIF}
{SetProcedures:}
{The main geometry manager.}
procedure SetAxisDimensions;
{Sets the behaviour upon adding new data points.}
procedure SetDisplayModeHistory(HistoryValue: Single; ScalingValue: TDisplayMode);
{$IFDEF MSWINDOWS}
{$IFDEF COMPILER2_UP}
{Puts CreatedBy and Description into the metafile.}
procedure SetMetafileDescription;
{$ENDIF}
{$ENDIF}
{Responding to mouse events, click & drag:}
procedure GetTheClickedObject(X, Y: Integer);
procedure MouseTimeOut(Sender: TObject);
procedure MoveTheClickedObjectTo(X, Y: Integer);
procedure OutlineTheClickedObject;
procedure SetResult(Slope, Intercept, Rsq: Single);
procedure StretchTheClickedObjectTo(X, Y: Integer);
procedure SwapEnds;
{These two respond to a user choice between overlaying objects:}
procedure MoveTheClickedObjectClick(Sender: TObject);
procedure MoveSecondClickedObjectClick(Sender: TObject);
{Sets the width of the outline for screen objects like lines: axes and borders.}
procedure CreateFlashEditor;
procedure FlashEditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
{Processes key presses from the in-place editor.}
procedure FlashEditExit(Sender: TObject);
protected
FSeriesList: TSeriesList;
{Huh ?! Why protected for both the internal variable and the property ?}
{Because the property is later Published in TPlot, and TDBPlot needs access to
the internal variable, but still has to hide the property.}
function GetMultiJoin: String;
function GetZAngle: Word;
function GetZLength: Word;
{Property Set Procedures:}
procedure SetZAngle(Value: Word);
procedure SetZLength(Value: Word);
procedure SetZLink(Value: Boolean);
procedure SetXYFastAt(Value: Longint);
procedure SetBubbleSize(Value: TPercent);
procedure SetColumnGap(Value: TPercent);
procedure SetContourDetail(Value: TContourDetail);
procedure SetContourInterval(Value: Single);
procedure SetContourStart(Value: Single);
procedure SetContourWireFrame(Value: Boolean);
procedure SetGrid(Value: TGridType);
procedure SetGridStyle(Value: TPenStyle);
procedure SetGridColor(Value: TColor);
procedure SetWallColor(Value: TColor);
procedure SetDefaultExtension(Value: String);
procedure SetDefaults;
procedure SetDisplayMode(Value: TDisplayMode);
procedure SetHistory(Value: Single);
procedure SetInstructions(Value: TStringList);
{Handles file names for saving and opening:}
procedure SetFileName(Value: String);
procedure SetNoYAxes(Value: Integer);
procedure SetPlotType(Value: TPlotType);
procedure SetPolarRange(Value: Single);
procedure SetPopupOptions(Value: TPopupOptions);
procedure SetOutlineWidth(Value: Integer);
procedure SetMultiplicity(Value: Byte);
procedure SetMultiplePen(Value: TPen);
procedure SetMultiJoin(Value: String);
procedure SetPieRowCount(Value: Byte);
procedure SetNoSeries(Value: Word); virtual;
procedure SetClickAndDragDelay(Value: Integer);
procedure SetOnSelection(Value: TOnSelectionEvent);
procedure SetOnDualSelection(Value: TOnDualSelectionEvent);
{procedure StyleChange(Sender: TObject);}
{Responds to appearance changes in subcomponents.}
{procedure DataChange(Sender: TObject); }
{Responds to changes in the basic data.}
{Copying data:}
procedure CopyText; virtual;
{Copies the data as tab-delimited text to the Clipboard, with any
TCustomPlot.Owner added header.}
procedure CopyHTML(Format: Word); virtual;
{Copies the data as HTML to the Clipboard in CF_HTML format, with any
TCustomPlot.Owner added header.}
{Copying pictures:}
procedure CopyBitmap; virtual;
function GetBitmap: TBitmap; virtual;
{Does what it says.}
{$IFDEF MSWINDOWS}
function GetDrawing: TMetafile; virtual;
{$ENDIF}
{$IFDEF LINUX}
function GetDrawing: TDrawing; virtual;
{$ENDIF}
{$IFDEF GIF}
function GetGIF: TGIFImage; virtual;
{$ENDIF}
{$IFDEF PNG}
{$IFDEF MSWINDOWS}
function GetPng: TPngImage; virtual;
{$ENDIF}
{$IFDEF LINUX}
function GetPng: TBitmap; virtual;
{$ENDIF}
{$ENDIF}
procedure CopyDrawing(Enhanced: Boolean); virtual;
{Does what it says.}
procedure CreateMenus;
{Creates the three popup menus.}
procedure CreatePageButtons;
procedure DestroyPageButtons;
procedure PageButtonClick(Index: Integer);
procedure DoStyleChange(Sender: TObject); dynamic;
procedure DoDataChange(Sender: TObject); dynamic;
procedure DoFileClose(AFileName: String); dynamic;
procedure DoFileOpen(AFileName: String); dynamic;
procedure DoHeader(TheStream: TMemoryStream); dynamic;
procedure DoHeaderRequest(TheStream: TMemoryStream); dynamic;
procedure DoHTMLHeaderRequest(TheHeader: TStringList); dynamic;
procedure DoSelection(Sel1: TRect); dynamic;
procedure DoDualSelection(Sel1, Sel2: TRect); dynamic;
{File manipulation:}
procedure OpenProperties(AFileName: String);
{Saves the Plot Properties to a file.}
procedure SaveTheProperties(AFileName: String);
{Saves the Plot Properties to a file.}
function CanPaste: Boolean;
{Can we paste data from the Clipboard into TPlot ?}
procedure DblClick; override;
{Some items - ie: the Title Captions, can be edited directly.}
{procedure KeyDown(var Key: Word; Shift: TShiftState); override;}
{This processes certain key strokes.}
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
{Implements dragging with the mouse.}
procedure MouseMove(Shift: TShiftState; X,Y: Integer); override;
{Further implements dragging with the mouse.}
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X,Y: Integer); override;
{Implements dragging with the mouse, and right clicking for a popup menu.}
procedure ProcessClickedObject(pObject: Pointer; TheObjectType: TObjectType); virtual;
{Applies effects of clicking and dragging to the selected object.}
{Paint and Draw:}
procedure DrawGrid(ACanvas: TCanvas);
{This draws grid for xy-type plots - it is called by Draw.}
procedure DrawWalls(ACanvas: TCanvas);
{This draws XY, XZ and YZ grids for 3D plots - it is called by Draw.}
procedure Paint; override;
{The normal paint procedure. Most of the work is done in Draw.}
procedure DrawInstructions;
{Just draws the instructions.}
procedure Resize; override;
{The normal Resize procedure - it manages screen geometry.}
procedure ZeroScreenStuff; dynamic;
{This re-initializes all the mouse-selection related variables}
{$IFNDEF DELPHI1}
procedure DetermineMenuVisibility;
{Sets the Visibility of the items of the internal Popup Menu.}
procedure SetSeriesVisibility(Value: Boolean);
{Makes series-related menu items visible or otherwise}
procedure SetSeriesEnabledness(TheMenu: TMenu);
{Makes the Series-related items of an external menu Enabled or otherwise}
{$ENDIF}
{Properties that will be published in the non-custom descendant:}
Property About: string read FAbout write FAbout {$IFDEF DELPHI2_UP}stored False{$ENDIF};
{Displays the "About" dialog box for this component.}
Property AxesProperties: string read FAxesProperties write FAxesProperties {$IFDEF DELPHI2_UP}stored False{$ENDIF};
{Displays the "Axis Editor" dialog box for the FAxisList subcomponent.}
Property DataProperties: string read FDataProperties write FDataProperties {$IFDEF DELPHI2_UP}stored False{$ENDIF};
{Displays the "Data Editor" dialog box.}
Property Properties: string read FProperties write FProperties {$IFDEF DELPHI2_UP}stored False{$ENDIF};
{Displays the "Property Editor" dialog box.}
Property SeriesProperties: string read FSeriesProperties write FSeriesProperties {$IFDEF DELPHI2_UP}stored False{$ENDIF};
{Displays the "Series Editor" dialog box.}
Property AxisList: TList read FAxisList {$IFDEF DELPHI2_UP}stored FALSE{$ENDIF};
{This is a list of all the axes. The 0th is X, the 1st Y.}
Property Bitmap: TBitmap read GetBitmap;
{This returns a Bitmap of the Plot.}
{$IFDEF MSWINDOWS}
Property Drawing: TMetafile read GetDrawing;
{This returns a Metafile/Drawing of the Plot.}
{$ENDIF}
{$IFDEF LINUX}
Property Drawing: TDrawing read GetDrawing;
{This returns a Metafile/Drawing of the Plot.}
{$ENDIF}
{$IFDEF GIF}
Property GIF: TGIFImage read GetGIF;
{This returns a Bitmap of the Plot IN GIF FORMAT.}
{$ENDIF}
{$IFDEF PNG}
{$IFDEF MSWINDOWS}
Property Png: TPngimage read GetPng;
{$ENDIF}
{$IFDEF LINUX}
Property Png: TBitmap read GetPng;
{This returns a Bitmap of the Plot IN PNG FORMAT.}
{$ENDIF}
{$ENDIF}
Property PlotPopUpMenu: TPopupMenu read FPlotPopUpMenu;
{The public exposure of the popupmenu for PlotMenu's use.}
Property Series[Index: Integer]: TSeries read GetSeries {$IFDEF DELPHI2_UP}stored FALSE{$ENDIF}; default;
{This provides direct access to the series maintained by SeriesList.}
Property SeriesList: TSeriesList read FSeriesList {$IFDEF DELPHI2_UP}stored FALSE{$ENDIF};
{This is the data in a list of data series.}
Property ScreenJob: TScreenJob read FScreenJob write FScreenJob {$IFDEF DELPHI2_UP}stored FALSE{$ENDIF};
{This is the job that is in progress in response to user input.}
{Displays the "Series Editor" dialog box.}
Property Border: TBorder read FBorder write FBorder;
{Manages the geometry of TCustomPlot: where the axes are, where they can go, etc.}
Property BubbleSize: TPercent read FBubbleSize write SetBubbleSize;
{This is the percentage size of Bubbles, compared to the Y Axis, in the ptBubble PlotType.}
Property ColumnGap: TPercent read FColumnGap write SetColumnGap;
{This is the percentage gap between groups of Columns in ptColumn PlotType.}
Property ContourDetail: TContourDetail read FContourDetail write SetContourDetail;
{This is the detail of the colour interpolation in a contour graph.
cdLow: each triangular tile has uniform colour; this is pretty grainy
cdMedium: each pixel in each triangular tile has its own colour: this makes a good bitmap, but a lousy metafile
cdHigh: each rectangular pixel in each triangular tile has its own colour: this makes a good metafile
See SeriesList.DrawContour.}
Property ContourInterval: Single read FContourInterval write SetContourInterval;
Property ContourStart: Single read FContourStart write SetContourStart;
Property ContourWireFrame: Boolean read FContourWireFrame write SetContourWireFrame;
Property Grid: TGridType read FGrid write SetGrid;
{Do we want a grid in XY-type plots ?}
Property GridStyle: TPenStyle read FGridStyle write SetGridStyle;
{What pen style (dash, dot, etc) do we want for Grids ?}
Property GridColor: TColor read FGridColor write SetGridColor default clGray;
{What colour is our grid ? Default is clGray.}
Property WallColor: TColor read FWallColor write SetWallColor;
{What colour is our Wall ? Default is clYellow.}
Property HelpFile: String read FHelpFile write FHelpFile;
{When this is set to "", TPlot uses Plot.hlp as its context-sensitive help file.}
{}
{When set to some other file, it uses that instead.}
Property Instructions: TStringList read FInstructions write SetInstructions;
{This is a message to the user, at the bottom-left of the graph, in the current
Font. It disappears on a MouseDown event.}
Property ClickAndDragDelay: Integer read GetClickAndDragDelay write SetClickAndDragDelay;
{The delay (in milliseconds) before a clicked object becomes draggable.}
{$IFNDEF DELPHI1}
Property CreatedBy: String read FCreatedBy write FCreatedBy;
{A string that is stored in the metafile description.}
{}
{This is also used as the "Author" value in a PNG file, if PNG is defined.}
Property Description: String read FDescription write FDescription;
{A string that is stored in the metafile description.}
{}
{This is also used as the "Description" value in a PNG file, if PNG is defined.}
{$ENDIF}
Property DisplayHistory: Single read FDisplayHistory write SetHistory;
{The width of the X Axis when in History mode.}
Property DisplayMode: TDisplayMode read FDisplayMode write SetDisplayMode;
{See TDisplayMode.}
Property Editable: Boolean read FEditable write FEditable;
{Are screen objects like axes Editable ?}
Property DefaultExtension: String read FDefaultExtension write SetDefaultExtension;
{What is the default extension of Plot files ?}
Property FileName: String read FFileName write SetFileName {$IFDEF DELPHI2_UP}stored FALSE{$ENDIF};
{This is the FileName to which the data is saved, or opened from.}
{}
{If FileName is blank, and an OpenClick or SaveClick occurs, then the standard
file dialog box appears to let the user pick a name.}
property HighFont: TFont read FHighFont write FHighFont;
{The font for annotation of the Highs and Lows.}
{$IFDEF COMPILER4_UP}
property Images: TImageList read GetImages write SetImages; {TCustomImageList}
{The images for the popupmenu.}
{$ENDIF}
property Legend: TLegend read FLegend write FLegend;
{The list of series with their line styles. This is a moveable, on-screen object.}
property MultiplePen: TPen read FMultiplePen write SetMultiplePen;
{The pen to use for the verticle lines of ptMultiple PlotTypes (eg: High-Low).}
property MultiJoin: String read GetMultiJoin write SetMultiJoin;
{Which two series, by number, to join with one rectangular symbol, in a ptMultiple plot.
Eg: if Multiplicity is 4, and MultiJoin = '2,3', then you have a "Candle" or
High-Low-Open-Close plot.}
Property PlotType: TPlotType read FPlotType write SetPlotType;
{What type of plot is this ?}
Property PolarRange: Single read FPolarRange write SetPolarRange;
{What does 360░ correspond to in a polar graph ? Examples are:
2 Pi (6.28...),
360 (degrees),
60 (minutes),
24 (hours)
100 (%)
Get the idea ? }
Property PopupOptions: TPopupOptions read FPopupOptions write SetPopupOptions;
{If true, then these popup menu items are visible.}
Property Movable: Boolean read FMovable write FMovable;
{Are screen objects like axes movable ?}
Property Multiplicity: Byte read FMultiplicity write SetMultiplicity;
{When the PlotType is ptMultiple, the series are grouped into multiples of Multiplicity.
Otherwise ignored.}
Property PieRowCount: Byte read FPieRowCount write SetPieRowCount;
{The number of rows of Pie Graphs.}
Property NoSeries: Word read GetNoSeries write SetNoSeries;
{The number of Series. Setting this can both create new series or free existing series.}
Property NoYAxes: Integer read GetNoYAxes write SetNoYAxes;
{The total number of Y Axes (primary, secondary, tertiary, etc).}
Property PrintOrientation: TPrinterOrientation
read FPrintOrientation write FPrintOrientation;
{Shall we print the graph in Landscape or Portrait mode ?}
Property OutlineWidth: Integer read FOutlineWidth write SetOutlineWidth;
{This is the width of the outline for screen objects like lines: axes and borders.}
Property SaveOptions: TSaveOptions read FSaveOptions write FSaveOptions;
{Shall we save the data as Text or binary ?}
{}
{Shall we also save the Plot properties when we save the data ?
If we do, then we:
1. Save the properties in a seperate file;
2. Look for a properties file to open.}
Property Title: TTitle read FTitle write FTitle;
{The title of the graph, including its geometry, font and visibility.}
Property XAxis: TAxis read FXAxis write FXAxis;
{This is the X Axis. Every nice graph should have an X Axis.}
Property YAxis: TAxis read FYAxis write FYAxis;
{This is the Y Axis. Every nice graph should have at least one Y Axis.}
{}
{Each Series must know what Y Axes it is being plotted against:
Primary (this one) or Secondary.}
Property ZAxis: TAngleAxis read FZAxis write FZAxis;
{This is the Z Axis. Every nice 3D graph should have an Z Axis.}
{}
{This is fairly experimental at the moment, so use with caution.
It is also nil with non-3D PlotTypes.}
Property ZAngle: Word read GetZAngle write SetZAngle;
{The angle made by the Z Axis, if any, with the vertical, in a clockwise direction.}
Property ZLength: Word read GetZLength write SetZLength;
{The Length made by the Z Axis, if any, with the vertical, in a clockwise direction.}
Property ZLink: Boolean read FZLink write SetZLink;
{Should we link 3D series together in the Z direction ?}
Property XYFastAt: Longint read FXYFastAt write SetXYFastAt default 10000;
{At how many data points should we switch to a fast drawing alforithm.}
{Events:}
Property OnAfterPaint: TOnPaintEvent read FOnAfterPaint write FOnAfterPaint;
Property OnAfterDraw: TOnPaintEvent read FOnAfterDraw write FOnAfterDraw;
Property OnBeforePaint: TOnPaintEvent read FOnBeforePaint write FOnBeforePaint;
Property OnBeforeDraw: TOnPaintEvent read FOnBeforeDraw write FOnBeforeDraw;
Property OnStyleChange: TNotifyEvent read FOnStyleChange write FOnStyleChange;
Property OnDataChange: TNotifyEvent read FOnDataChange write FOnDataChange;
Property OnFileOpen: TOnFileEvent read FOnFileOpen write FOnFileOpen;
{When a file is opened, the app can be notified of the new file name using this event.}
Property OnFileClose: TOnFileEvent read FOnFileClose write FOnFileClose;
{When a file is closed, the app can be notified of the new file name using this event.}
Property OnHeader: TOnHeaderEvent read FOnHeader write FOnHeader;
{When data is opened, this event passes the header information back to the "user".}
Property OnHeaderRequest: TOnRequestHeaderEvent read FOnHeaderRequest write FOnHeaderRequest;
{When data is saved or copied, this event allows the user to add a header
to the data.}
Property OnHTMLHeaderRequest: TOnRequestHTMLHeaderEvent read FOnHTMLHeaderRequest write FOnHTMLHeaderRequest;
{When data is copied as HTML, this event allows the user to add a header
to the data.}
Property OnSelection: TOnSelectionEvent read FOnSelection write SetOnSelection;
{When the user selects a region, then this event is fired.}
{}
{Note that after firing, this event is set to nil, so you have to reset it every usage.}
Property OnDualSelection: TOnDualSelectionEvent read FOnDualSelection write SetOnDualSelection;
{When the user selects TWO regions, then this event is fired.}
{}
{Note that after firing, this event is set to nil, so you have to reset it every usage.}
public
Constructor Create(AOwner: TComponent); override;
{The usual Constructor, where sub-components are created, properties set, etc.}
Destructor Destroy; override;
{The usual Destructor, where sub-components are destroyed.}
procedure Clear(Cancellable: Boolean); virtual;
{Saves any changed files (at user request) and then clears the SeriesList.}
procedure Draw(ACanvas: TCanvas); virtual;
{This draws the graph on a Canvas. The canvas can be:}
{}
{ 1. Self.Canvas - ie: on screen;}
{ 2. a Bitmap, for copying and saving.}
{ 3. a MetafileCanvas, for copying and saving.}
{ 4. the printer.}
{}
{It is called by Paint, and also many of the copying and saving routines.}
function GetFileExtension: String; {csv}
function GetFileDriveDir: String; {D:\Data\Delphi\Plot}
function GetFileRoot: String; {Test3}
function GetPlotTypeAsString: String;
procedure ShowAbout;
{This displays the components "About" dialog box.}
procedure ShowAxes;
{This displays the properties of the Series in the SeriesList.}
procedure ShowData;
{This displays the properties of the Data in the DataList.}
procedure ShowProperties;
{This displays the properties of the Plot.}
procedure ShowSeries;
{This displays the properties of the Series in the SeriesList.}
{Wrappers for the SeriesList functions; the first three also set the
OnStyleChange event and the Visibility property:}
function AddSeries(XSeriesIndex: Integer): Integer; virtual;
{This adds a new, empty series to the list.}
function AddExternalSeries(XPointer, YPointer: pSingleArray; NumberOfPoints: Integer): Integer; virtual;
{This adds a new, empty series to the list, and sets its data to point to the
external XPointer, YPointer data.}
function AddInternalSeries(XPointer, YPointer: pSingleArray; NumberOfPoints: Integer): Integer; virtual;
{This adds a new, empty series to the list, and copies the data from the
XPointer, YPointer data.}
function CloneSeries(TheSeries: Integer): Integer; virtual;
{This adds a new, empty series to the list, copies the data and properties from
TheSeries into the new clone, and changes the color and Y Displacement.}
procedure DeleteSeries(Index: Integer); virtual;
{This deletes TheSeries from the list.}
{$IFNDEF DELPHI1}
procedure DetermineMenuEnabledness(TheMenu: TMenu);
{$ENDIF}
procedure AddData(NoPoints: Integer; XYArray: pXYArray); virtual;
{Add a slice of readings to the internal series.
These will become the Nth points in every series.}
{}
{This method is extremely useful for data acquisition.}
procedure Trace;
{This draws all the Series in an erasable mode without re-drawing the Axes,
Titles or Legend.}
{}
{More specifically, the first call to Trace draws the Series, the second erases them.}
{}
{This is useful for rapidly changing data such as an oscilloscope. To use it:}
{}
{ 1. Set up the Axes, etc.}
{ 2. Create each Series you need.}
{ 3a. Use AllocateNoPts for each one, or:}
{ 3b. Allocate and manage the memory yourself, then use PointToData.}
{ 4. Dump you data into each Series via the XData and YData properties.}
{ 5. Trace the data.}
{ 6. Get more data.}
{ 7. Trace the data again to erase the old image.}
{ 8. Repeat steps (4)-(7) indefinitely.}
{}
{Note that in step (4), you can either use the XData and YData properties as:}
{}
{ a. pSeries.XData^[i];}
{ b. pX, pY: pSingle; pX := pSeries.XData; pY := pSeries.YData;}
procedure CopyClick(Sender: TObject);
{This responds to a user selection of "Copy" in the popupmenu,
and copies the data as text, as a bitmap, and as an enhanced metafile.}
procedure HideClick(Sender: TObject);
{This hides (.Visible := FALSE) the selected object.}
procedure PrintClick(Sender: TObject);
{This prints the graph.}
procedure ShowAllClick(Sender: TObject);
{This shows (.Visible := TRUE) ALL objects.}
procedure PositionClick(Sender: TObject);
{This reports the Position of the mouse (right) click.}
procedure NearestPointClick(Sender: TObject);
{This reports the Position of the nearest data series point to the mouse
(right) click.}
procedure DeleteSeriesClick(Sender: TObject);
{This deletes the currently selected series.}
procedure CopySeriesClick(Sender: TObject);
{This copies the selected series to the clipboard in tab-delimited form.}
procedure NewSeriesClick(Sender: TObject);
{This creates a new, empty series.}
procedure CloneSeriesClick(Sender: TObject);
{This creates a new series, and copies the data of the selected series into it.}
procedure ModeClick(Sender: TObject);
{procedure ModeNoneClick(Sender: TObject);
procedure ModeRunClick(Sender: TObject);
procedure ModeHistoryClick(Sender: TObject);}
{This sets the Display Mode of the graph.}
procedure PasteClick(Sender: TObject);
{This pastes (Tab Delimited) data from the clipboard.}
procedure LineBestFitClick(Sender: TObject);
{This initiates a line of best fit determination.}
procedure TwoRegionLineBestFitClick(Sender: TObject);
{This initiates a line of best fit determination over two different regions.}
{$IFDEF FUNCTIONS}
procedure FunctionClick(Sender: TObject);
{This creates a new series which is a function of the existing series.}
{$ENDIF}
procedure SmoothSeriesClick(Sender: TObject);
{This smoothes the currently seleccted data series.}
procedure CompressSeriesClick(Sender: TObject);
{This Compresss the currently selected data series by a factor of 2, 3, 4, etc.}
procedure CompressAllSeriesClick(Sender: TObject);
{This Compresss ALL data series by a factor of 2, 3, 4, etc.}
procedure ContractSeriesClick(Sender: TObject);
{This contracts the currently selected data series by a factor of 2, 3, 4, etc.}
procedure ContractAllSeriesClick(Sender: TObject);
{This contracts ALL data series by a factor of 2, 3, 4, etc.}
procedure LegendClick(Sender: TObject);
{This responds to a user selection of "Legend" in the popupmenu.}
procedure EditAxisClick(Sender: TObject);
{This responds to a user selection of "Axis ..." in the popupmenu,
runs the Edit Axis Dialog, and assigns any changes to the appropriate axis.}
procedure ApplyAxisChange(Sender: TObject);
{Apply changes from the AxisEditor to the Axes.}
procedure NewNoteClick(Sender: TObject);
{This responds to a user selection of "New Note ..." in the popupmenu,
creates the note, and gets the user to set it and place it.}
procedure MoveNotePointerClick(Sender: TObject);
{This responds to a user selection of "Move Note Pointer" in the popupmenu,
and gets the user to move it and place it.}
procedure DeleteNoteClick(Sender: TObject);
{This responds to a user selection of "Delete Note ..." in the popupmenu,
checks with the user, then deletes it.}
procedure EditFontClick(Sender: TObject);
{This responds to a user selection of "Font ..." in the popupmenu,
runs the FontDialog, and assigns any changes to the appropriate object.}
procedure EditPointClick(Sender: TObject);
{This responds to a user selection of "Point ..." in the popupmenu,
runs the Series.PointEdit method, which displays and runs the PointEditor.}
procedure EditDataClick(Sender: TObject);
{This responds to a user selection of "Edit ... Data ..." in the popupmenu,
and displays and runs the DataEditor.}
procedure EditSeriesClick(Sender: TObject);
{This responds to a user selection of "Edit ... Series ..." in the popupmenu,
and displays and runs the SeriesEditor.}
procedure ApplySeriesChange(Sender: TObject);
{Apply changes from the SeriesEditor to the Series.}
procedure ResetDisplacementClick(Sender: TObject);
{This sets the Displacement properties DeltaX and DeltaY to ZeroScreenStuff.}
procedure EditPropertiesClick(Sender: TObject);
{This responds to a user selection of "Properties ..." in the popupmenu,
runs the PropertiesDialog, and assigns any changes to the appropriate objects.}
procedure ApplyPropertiesChange(Sender: TObject);
{This applies changes from the PropertiesDialog.}
procedure NewClick(Sender: TObject);
{This responds to a user selection of "New" in the File popupmenu,
and clears all the data and resets the graph.}
{$IFDEF FINANCE}
{Now all the financial functions:}
procedure ADLClick(Sender: TObject);
{This runs the ADL financial calculation.}
{$ENDIF}
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
{needed by D1 for PlotMenu insertion/removal}
procedure OpenClick(Sender: TObject);
{This responds to a user selection of "Open ..." in the popupmenu,
runs the Open Dialog, and calls the LoadFromFile method.}
procedure OpenFile(TheFile: String);
procedure ClearOverlaysClick(Sender: TObject);
{This responds to a user selection of "Clear Overlays" in the popupmenu,
and removes any Overlays.}
procedure OverlayClick(Sender: TObject);
{This responds to a user selection of "Overlay Data" in the popupmenu,
runs the Overlay Dialog, and calls the LoadFromFile method.}
procedure SaveImageClick(Sender: TObject);
{This responds to a user selection of "Save Image" in the popupmenu,
runs the Save Dialog, and calls the SaveAsBitmap, SaveAsGIF or the SaveAsDrawing method.}
procedure SaveClick(Sender: TObject);
{This responds to a user selection of "Save Data" in the popupmenu,
runs the Save Dialog if FileName is blank, and calls the SaveToFile method.}
procedure SaveAsClick(Sender: TObject);
{This responds to a user selection of "Save Data As" in the popupmenu,
runs the Save Dialog, and calls the SaveToFile method.}
procedure LoadFromFile(AFileName: String); virtual;
{Loads the data from a file, using LoadFromStream.}
procedure LoadFromStream(AStream: TMemoryStream); virtual;
{Loads the data from a stream.}
procedure AppendToFile;
{Appends the data as text to a text file.}
procedure SaveToFile(AFileName: String); virtual;
{Saves the data as text to a text file, with any TCustomPlot.Owner added header.}
procedure SaveToStream(var TheStream: TMemoryStream); virtual;
{Saves the data to a stream, with any TCustomPlot.Owner added header.}
{Saving as a picture:}
procedure SaveAsBitmap(AFileName: String); virtual;
{Does what it says.}
procedure SaveAsDrawing(AFileName: String); virtual;
{$IFDEF GIF}
procedure SaveAsGIF(AFileName: String); virtual;
{$ENDIF}
{Does what it says.}
{}
{If GIF is defined (in Plot.inc) then saving as a GIF is enabled.}
{}
{Commercial developers note: the use of GIFs requires a license from Unisys:
http://www.unisys.com/unisys/lzw/}
{$IFDEF PNG}
procedure SaveAsPNG(AFileName: String); virtual;
{$ENDIF}
{Does what it says.}
{}
{If PNG is defined (in Plot.inc) then saving as a PNG is enabled.
Note that PNG is always enabled under Kylix.}
procedure SetAsNormalClick(Sender: TObject);
{Defines the current view == Mins and Maxes of axes, as the Normal view.}
procedure NormalViewClick(Sender: TObject);
{Zooms the screen the screen to the Normal view.}
procedure ManualZoomClick(Sender: TObject);
{Zooms the screen using a manual dialog box.}
procedure ApplyZoom(Sender: TObject);
{Applies the zoom.}
procedure ZoomOutClick(Sender: TObject);
{Zooms the screen out after a zoom-in operation.}
procedure MakeDummyData(NoSteps: Integer);
{This procedure is used to generate some dummy data for testing purposes.}
procedure CopyHTMLClick(Sender: TObject);
{Copies the data as HTML to the Clipboard in CF_TEXT format, with any
TCustomPlot.Owner added header.}
procedure DisplaceClick(Sender: TObject);
{This responds to a user selection of "Displace" in the popupmenu, and runs
the Displacement Form, which moves the selected Series from its origin.}
procedure DifferentiateClick(Sender: TObject);
{This responds to a user selection of "Differentiate" in the popupmenu,
and replaces the selected series with its differential.
{}
{(Hint: Clone the series first !)}
procedure HandleClick(Sender: TObject; TheTag: Integer);
{The externally-exposed event handler for all menu items.}
{}
{It is used by TPlotMenu to forward the click event to TPlot, which then passes
it onto the appropriate handler method based on the value of TheTag.}
function GetIndicesFromTag(TheTag: Integer; var i, j: Integer): Boolean;
{Get the i and j indices for the menu from the Tag.}
procedure IntegrateClick(Sender: TObject);
{This responds to a user selection of "Integrate" in the popupmenu, and replaces
the selected series with its integral.}
{}
{(Hint: Clone the series first !)}
procedure IntegralClick(Sender: TObject);
{This responds to a user selection of "Integral" in the popupmenu,
and calculates the integral of the selected series over the user-selected
(by click-and-drag) range.}
procedure SortClick(Sender: TObject);
{This runs the Sort method.}
procedure SplineClick(Sender: TObject);
{This responds to a user menu click and performs a cubic spline interpolation
of the currently selected data series by calling the Spline method.}
function Spline(ASeries: Integer): Integer;
{This performs a cubic spline interpolation of ASeries by calling the
TSeries.Spline method to place the cubic spline into a new data series.}
procedure ZoomInClick(Sender: TObject);
{}
procedure HighsClick(Sender: TObject);
{Finds and displays the Highs (peaks) and/or Lows (troughs) of a series.}
procedure MovingAverageClick(Sender: TObject);
{Calculates and displays the Moving Average of a series.}
procedure AverageClick(Sender: TObject);
{Calculates the Average of a series over a range.}
procedure LinearizeClick(Sender: TObject);
{Linearizes a series over a range.}
procedure ZeroClick(Sender: TObject);
{Zeros a series over a range.}
procedure NewYAxisClick(Sender: TObject);
{Adds a new axis, based on either the selected or last axis.}
procedure DeleteAxis(Index: Integer; Confirm: Boolean);
{Deletes the selected axis.}
procedure DeleteAxisClick(Sender: TObject);
{Deletes the axis selected by the user.}
procedure SetPlotMenu(Value: TMainMenu);
{Sets the PlotMenu property.}
procedure SetPlotToolBar(Value: TToolBar);
{Sets the PlotMenu property.}
procedure SetInstructionText(Value: String);
{Sets the Instructions stringlist by its Text property.}
published
end;
{End of declaration of TCustomPlot.}
{******************************************************************************}
TPlot = class(TCustomPlot)
protected
public
Property AxisList;
{This is a list of all the axes. The 0th is X, the 1st Y.}
Property Bitmap;
{This returns a Bitmap of the Plot.}
Property Drawing;
{This returns a Drawing/metafile of the Plot. Very useful for printing.}
{$IFDEF GIF}
Property GIF;
{This returns an image of the Plot IN GIF FORMAT.}
{$ENDIF}
{$IFDEF LINUX}
Property Png;
{This returns a Bitmap of the Plot IN PNG FORMAT.}
{$ENDIF}
Property PlotPopUpMenu;
{The public exposure of the popupmenu for PlotMenu's use.}
Property Series;
{This provides direct access to the series maintained by SeriesList.}
Property SeriesList;
{This is the data in a list of data series.}
Property ScreenJob;
{This is the job that is in progress in response to user input.}
Property ZAxis;
{This is the Z Axis. Every nice 3D graph should have an Z Axis.}
{}
{This is fairly experimental at the moment, so use with caution.
It is also nil with non-3D PlotTypes.}
published
{All the protected properties of TCustomPlot:}
Property About;
{Displays the "About" dialog box for this component.}
Property AxesProperties;
{Displays the "Axis Editor" dialog box for the FAxisList subcomponent.}
Property DataProperties;
{Displays the "Data Editor" dialog box.}
Property Properties;
{Displays the "Property Editor" dialog box.}
Property SeriesProperties;
{Displays the "Series Editor" dialog box.}
Property Border;
{Manages the geometry of TCustomPlot: where the axes are, where they can go, etc.}
Property ClickAndDragDelay;
{The delay (in milliseconds) before a clicked object becomes draggable.}
Property ColumnGap;
{This is the percentage gap between groups of Columns in ptColumn PlotType.}
Property ContourDetail;
{This is the detail of the colour interpolation in a contour graph.
cdLow: each triangular tile has uniform colour; this is pretty grainy
cdMedium: each pixel in each triangular tile has its own colour: this makes a good bitmap, but a lousy metafile
cdHigh: each rectangular pixel in each triangular tile has its own colour: this makes a good metafile
See SeriesList.DrawContour.}
Property ContourInterval;
Property ContourStart;
Property ContourWireFrame;
{$IFNDEF DELPHI1}
Property CreatedBy;
{For a metafile, this is a string that is stored in the metafile.}
Property Description;
{For a metafile, this is a string that is stored in the metafile.}
{$ENDIF}
Property DisplayHistory;
{The width of the X Axis when in History mode.}
Property DisplayMode;
{See TDisplayMode.}
Property DefaultExtension;
{What is the default extension of Plot files ?}
Property Editable;
{Are screen objects like axes Editable ?}
Property FileName;
{This is the filename to which the data is saved, or opened from.}
{}
{If FileName is blank, and an OpenClick or SaveClick occurs, then the standard
file dialog box appears to let the user pick a name.}
Property Grid;
{Do we want a grid in XY-type plots ?}
Property GridStyle;
{What pen style (dash, dot, etc) do we want for Grids ?}
Property GridColor;
{What colour is our grid ? Default is clGray.}
property HighFont;
{The font for annotation of the Highs and Lows.}
{$IFDEF COMPILER4_UP}
property Images;
{A publication of the Popup Menu's Images property}
{$ENDIF}
Property HelpFile;
{When this is set to "", TPlot uses Plot.hlp as its context-sensitive help file.}
{}
{When set to some other file, it uses that instead.}
Property Instructions;
{This is a hint-like message at the bottom of the graph.
It used to be Caption - a string - but now has to be a
stringlist to be fully Delphi-compatible (to avoid API calls).
Remember Kylix !
It disappears upon a MouseDown. See Font.}
property Legend;
{The list of series with their line styles. This is a moveable, on-screen object.}
Property Movable;
{Are screen objects like axes movable ?}
Property Multiplicity;
{When the PlotType is ptMultiple, the series are grouped into multiples of Multiplicity.
Otherwise ignored.}
property MultiplePen;
{The pen to use for the verticle lines of ptMultiple PlotTypes (eg: High-Low).}
property MultiJoin;
{Which two series, by number, to join with one rectangular symbol, in a ptMultiple plot.
Eg: if Multiplicity is 4, and MultiJoin = '2,3', then you have a "Candle" or
High-Low-Open-Close plot.}
property PieRowCount;
{The number of rows of Pie Graphs.}
property NoSeries;
{The number of Series.}
property NoYAxes;
{The total number of Y Axes (primary, secondary, tertiary, etc).}
Property OutlineWidth;
{This is the width of the outline for screen objects like lines: axes and borders.}
Property PlotType;
{What type of plot is this ?}
Property PolarRange;
{What does 360░ correspond to in a polar graph ? Examples are:
2 Pi (6.28...),
360 (degrees),
60 (minutes),
24 (hours)
100 (%)
Get the idea ? }
Property PopupOptions;
{If true, then these popup menu items are visible.}
Property PrintOrientation;
{Shall we print the graph in Landscape or Portrait mode ?}
Property SaveOptions;
{Shall we save the data as Text or binary ?}
{}
{Shall we also save the Plot properties when we save the data ?
If we do, then we:
1. Save the properties in a seperate file;
2. Look for a properties file to open.}
Property Title;
{The title of the graph, including its geometry, font and visibility.}
Property WallColor;
{What colour is our Wall ? Default is clYellow.}
Property XAxis;
{This is the X Axis. Every nice graph should have an X Axis.}
Property YAxis;
{This is the Y Axis. Every nice graph should have at least one Y Axis.}
{}
{Each Series must know what Y Axes it is being plotted against:
Primary (this one) or Secondary.}
Property ZAngle;
{The angle made by the Z Axis, if any, with the vertical, in a clockwise direction.}
Property ZLink;
{Should we link 3D series together ?}
Property XYFastAt;
{At how many data points should we switch to a fast drawing alforithm.}
{Events:}
Property OnAfterPaint;
Property OnAfterDraw;
Property OnBeforePaint;
Property OnBeforeDraw;
Property OnStyleChange;
Property OnDataChange;
Property OnFileOpen;
{When a file is opened, the app can be notified of the new file name using this event.}
Property OnFileClose;
{When a file is closed, the app can be notified of the new file name using this event.}
Property OnHeader;
{When data is opened, this event passes the header information back to the "user".}
Property OnHeaderRequest;
{When data is saved or copied, this event allows the user to add a header
to the data.}
Property OnHTMLHeaderRequest;
{When data is copied as HTML, this event allows the user to add a header
to the data.}
Property OnSelection;
Property OnDualSelection;
{all the "extra" TPanel properties in D4 (alias "VCL Bloat"):}
{Now all the TPanel properties-------------------------------------------------}
{all the TPanel properties in D1:}
property Align;
{property Alignment;}
property BevelInner;
property BevelOuter;
property BevelWidth;
property BorderWidth;
property BorderStyle;
{property Caption; - replaced by Instructions}
property Color;
{$IFDEF MSWINDOWS}
property Ctl3D;
property DragCursor;
{$ENDIF}
property DragMode;
property Enabled;
property Font;
{This is the font of the hint-like message at the bottom of the graph.}
property ParentColor;
{$IFDEF MSWINDOWS}
property Locked;
property ParentCtl3D;
{$ENDIF}
property ParentFont;
property ParentShowHint;
{ Note: D1 to D4 were quite happy for:
PopupMenu := FPlotPopUpMenu;
FPlotPopUpMenu was then run by inherited MouseUp.
However, D5 introduced TControl.WMContextMenu, which ran BEFORE MouseDown.
This went spastic when it tried to Popup the PopupMenu.
We have therefore returned to hiding FPlotPopUpMenu, and running it manually.
property PopupMenu;}
property ShowHint;
property TabOrder;
property TabStop;
property Visible;
property OnClick;
property OnDblClick;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnResize;
{$IFDEF COMPILER2_UP}
{$ENDIF}
{$IFDEF COMPILER3_UP}
{$IFDEF MSWINDOWS}
property FullRepaint;
property OnStartDrag;
{$ENDIF}
{$ENDIF}
{$IFDEF COMPILER4_UP}
property Anchors;
// property AutoSize; - leads to bizzare behaviour
{$IFDEF MSWINDOWS}
property BiDiMode;
{$ENDIF}
property Constraints;
{$IFDEF MSWINDOWS}
property UseDockManager default True;
property DockSite;
property DragKind;
property ParentBiDiMode;
property OnCanResize;
{$ENDIF}
property OnConstrainedResize;
{$IFDEF MSWINDOWS}
property OnDockDrop;
property OnDockOver;
property OnEndDock;
property OnGetSiteInfo;
property OnStartDock;
property OnUnDock;
{$ENDIF}
{$ENDIF}
{$IFDEF COMPILER5_UP}
{$ENDIF}
end;
implementation
{$IFDEF DELPHI1}
{$R strlist.res}
{$R Cursor16.res}
{$ELSE}
{$R Cursor32.res}
{$ENDIF}
uses
Plotmenu, Plottoolbar;
{TCustomPlot methods --------------------------------------------------------------}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ShowAbout
Description: Property editor methods, et cetera
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 03/29/2001 by Mat Ballard
Purpose: design-time user interface
Known Issues: TAboutDlg adds about 8 K to the app
------------------------------------------------------------------------------}
procedure TCustomPlot.ShowAbout;
var
AboutDlg: TAboutDlg;
{Msg: String;}
begin
AboutDlg := TAboutDlg.Create(nil);
AboutDlg.Comments :=
'TPlot ' + sVersion + ' ' + FloatToStrF(TPLOT_VERSION / 100, ffFixed, 5, 2) + #10 +
sReleasedQ + #10 + #10 +
sAcknowledgementsTo + #10 +
' Anders Melanders - TGifImage' + #10 +
' Edmund H. Hand, Dominique Louis, Uberto Barbini' + sAnd + #10 +
' Eric Engler - TPngimage' + #10 +
' Atanas Stoyanov - MemProof' + #10 +
' Renate Schaaf, Alin Flaider, Hallvard Vassbotn' + sAnd + #10 +
' Stefan Hoffmeister - TParser10' + #10 +
' John Shemitz - ' + sRotated + ' Kylix ' + sText;
AboutDlg.Execute;
AboutDlg.Free;
end;
procedure TCustomPlot.ShowData;
begin
EditDataClick(Self);
end;
procedure TCustomPlot.ShowSeries;
begin
EditSeriesClick(Self);
end;
procedure TCustomPlot.ShowAxes;
begin
EditAxisClick(Self);
end;
procedure TCustomPlot.ShowProperties;
begin
EditPropertiesClick(Self);
end;
{Constructor and Destructor:-------------------------------------------------}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.Create
Description: class constructor
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: initialize variables and create sub-components
Known Issues:
------------------------------------------------------------------------------}
Constructor TCustomPlot.Create(
AOwner:TComponent);
begin
{First call the ancestor:}
inherited Create(AOwner);
{we create all objects here, otherwise property changes trigger
references to non-existent objects:}
FPlotPopUpMenu := TPopupMenu.Create(Self);
{ see note above at 'property PopupMenu':
PopUpMenu := FPlotPopUpMenu;}
FPopupOptions := TPopupOptions.Create;
FInstructions := TStringList.Create;
FFlashEdit := nil;
{create the list of all axes:}
FAxisList := TList.Create;
{create all the Axes:}
FXAxis := TAxis.Create(Self);
FAxisList.Add(FXAxis);
FYAxis := TAxis.Create(Self);
FAxisList.Add(FYAxis);
{create the list of data series:}
FSeriesList := TSeriesList.Create(FAxisList);
{Do things with the series list:}
{create the border of the graph:}
FBorder := TBorder.Create(Self);
{create the user-clickable edges of the graph (for clicking and dragging):}
LeftBorder := TRectangle.Create(Self);
TopBorder := TRectangle.Create(Self);
RightBorder := TRectangle.Create(Self);
BottomBorder := TRectangle.Create(Self);
{create the graph title:}
FTitle := TTitle.Create(Self);
{The Result of a least-squares fit:}
FResult := TCaption.Create(Self);
{create the plot legend:}
FLegend := TLegend.CreateList(Self, FSeriesList);
{the font for annotation of the highs and lows:}
FHighFont := TFont.Create;
FMultiplePen := TPen.Create;
FMultiJoin1 := 0;
FMultiJoin2 := 0;
{create the object that is clicked and dragged:}
Selection := TAngleRect.Create(Self);
{create the list of objects on the screen:}
ScreenObjectList := TList.Create;
{nil out the page buttons:}
FPageButtons[0] := nil;
FPageButtons[1] := nil;
FPageButtons[2] := nil;
FPageButtons[3] := nil;
{This is a typical size:}
Height := 300;
Width := 400;
{Users can edit some screen text:}
FEditable := TRUE;
{Users can move screen objects:}
FMovable := TRUE;
{10% of Y Axis maximum bubble size:}
FBubbleSize := 10;
{20% gap between columns:}
FColumnGap := 20;
{distance between line contours is 1:}
FContourInterval := 1;
{Dotted grids are the default:}
FGridStyle := psDot;
FGridColor := clGray;
FWallColor := clYellow;
{our default help file:}
FHelpFile := 'Plot.hlp';
{only one row of pie graphs:}
FPieRowCount := 1;
{High-Low is the default Multiple plot:}
FMultiPlicity := 2;
{One whole rotation corrsponds to ...}
FPolarRange := TWO_PI;
FZLink := TRUE;
FXYFastAt := 10000;
{No mouse timer as yet:}
MouseTimer := TTimer.Create(Self);
MouseTimer.Enabled := FALSE;
MouseTimer.OnTimer := MouseTimeOut;
{no series has been selected yet:}
pSeries := nil;
TheSeries := -1;
ClickedObjectType := soNone;
FDisplayHistory := 30;
FirstOverlay := -1;
FPlotMenu := nil;
//FPlotActionList := nil;
FPrintOrientation := poLandscape;
{ZeroScreenStuff everything to do with mice:}
FScreenJob := sjNone;
FOnSelection := nil;
FOnDualSelection := nil;
FSaveOptions := [soProperties];
DefaultExtension := DEF_EXTENSION;
FileExtensions[1] := 'csv';
FileExtensions[2] := 'txt';
FileExtensions[3] := '*';
OpenFilterIndex := 1;
SaveFilterIndex := 1;
ImageFilterIndex := 1;
BevelGap := 1;
{Take the hint:}
FInstructions.Add(sInstructionLine1);
FInstructions.Add(sInstructionLine2);
{... and initialize the X-Axis:}
FXAxis.Title.Units := sSeconds;
FXAxis.Tag := Ord(soXAxis);
FXAxis.Labels.Tag := Ord(soXAxisLabel);
FXAxis.Title.Tag := Ord(soXAxisTitle);
FXAxis.TickDirection := orRight;
{... and initialize the Y-Axis:}
FYAxis.Direction := drVertical;
FYAxis.TickDirection := orLeft;
FYAxis.Title.Orientation := orLeft;
FYAxis.Title.Units := smVolts;
FYAxis.Title.Caption := 'Y-' + sAxis;
FYAxis.Tag := Ord(soYAxis);
FYAxis.Labels.Tag := Ord(soYAxisLabel);
FYAxis.Title.Tag := Ord(soYAxisTitle);
{create the border dimensions of the plot:}
SetDefaults;
{Name the user-clickable edges of the graph (for clicking and dragging):}
LeftBorder.Name := sLeft + ' ' + sBorder;
LeftBorder.Tag := Ord(soLeftBorder);
TopBorder.Name := sTop + ' ' + sBorder;
TopBorder.Tag := Ord(soTopBorder);
RightBorder.Name := sRight + ' ' + sBorder;
RightBorder.Tag := Ord(soRightBorder);
BottomBorder.Name := sBottom + ' ' + sBorder;
BottomBorder.Tag := Ord(soBottomBorder);
{... and initialize the Plot Title:}
FTitle.Caption := ClassName;
FTitle.Name := sPlot + ' ' + sTitle;
FTitle.Orientation := orLeft;
FTitle.Font.Size := LARGE_FONT_SIZE;
FTitle.Tag := Ord(soTitle);
{The Result of a least-squares fit:}
FResult.Font.Size := SMALL_FONT_SIZE;
{invisibilize it:}
FResult.Top := -100;
FResult.Tag := Ord(soResult);
{... and initialize the plot legend:}
FLegend.Name := sLegend;
FLegend.Font.Size := SMALL_FONT_SIZE;
FLegend.Tag := Ord(soLegend);
{Initialize the Instruction font:}
Font.Name := sArial;
Font.Size := SMALL_FONT_SIZE;
Font.Color := clRed;
{the font for annotation of the highs and lows:}
FHighFont.Name := sArial;
FHighFont.Size := SMALL_FONT_SIZE;
{load the list of screen objects:}
ScreenObjectList.Add(Selection); {soNone}
ScreenObjectList.Add(FTitle); {soTitle}
ScreenObjectList.Add(FLegend); {soLegend}
ScreenObjectList.Add(FResult); {soResult}
ScreenObjectList.Add(FXAxis); {soXAxis}
ScreenObjectList.Add(FXAxis.Title); {soXAxisTitle}
ScreenObjectList.Add(FXAxis.Labels); {soXAxisLabel}
ScreenObjectList.Add(FYAxis); {soYAxis}
ScreenObjectList.Add(FYAxis.Title); {soYAxisTitle}
ScreenObjectList.Add(FYAxis.Labels); {soYAxisLabel}
{Reserved for the Z axis:}
ScreenObjectList.Add(nil); {soZAxis}
ScreenObjectList.Add(nil); {soZAxisTitle}
ScreenObjectList.Add(nil); {soZAxisLabel}
ScreenObjectList.Add(LeftBorder); {soLeftBorder}
ScreenObjectList.Add(TopBorder); {soTopBorder}
ScreenObjectList.Add(RightBorder); {soRightBorder}
ScreenObjectList.Add(BottomBorder); {soBottomBorder}
{Note: NoBasicScreenObjects is this list here.
Additional objects (secondary Y Axes, Z Axes, notes, etc,
are not counted in this total.}
NoBasicScreenObjects := ScreenObjectList.Count;
{The reason for this is that these latter can be added in any order.}
{create the list of notes:}
//NoteList := TList.Create;
NoteCount := 0;
SetPlotType(ptXY);
{set the user-clickable border thicknesses:}
SetOutlineWidth(10);
{this fires SetAxisDimensions.}
CreateMenus;
{Set all the OnStyleChanges:}
FXAxis.OnChange := DoStyleChange;
FYAxis.OnChange := DoStyleChange;
FBorder.OnChange := DoStyleChange;
FTitle.OnChange := DoStyleChange;
FSeriesList.OnStyleChange := DoStyleChange;
FSeriesList.OnDataChange := DoDataChange;
FLegend.OnChange := DoStyleChange;
Color := clWindow;
{load some cursors:}
{$IFDEF MSWINDOWS}
Screen.Cursors[crScope] := {WinProcs.}LoadCursor(HInstance, 'crScope');
Screen.Cursors[crX] := {WinProcs.}LoadCursor(HInstance, 'crX');
{$ENDIF}
ZeroScreenStuff;
IgnoreChanges := FALSE;
if (csDesigning in ComponentState) then
MakeDummyData(20);
end;
{functions called by constructor ----------------------------------------------}
{set the graph dimensions:}
procedure TCustomPlot.SetDefaults;
begin
FBorder.Left := 70;
FBorder.Top := 40;
FBorder.RightEx := Width;
FBorder.BottomEx := Height;
FBorder.RightGap := 50;
FBorder.BottomGap := 80;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.MakeDummyData
Description: procedure to add two series, with sine wave data
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: 1. test TCustomPlot
2. display capabilities in design mode.
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.MakeDummyData(NoSteps: Integer);
var
i,
j: Integer;
Amplitude,
MidY,
Phase,
StepSize,
X,
Y: Single;
OldIgnoreChanges: Boolean;
begin
OldIgnoreChanges := IgnoreChanges;
IgnoreChanges := TRUE;
{clean up first:}
for i := 0 to FSeriesList.Count-1 do
begin
TSeries(FSeriesList.Items[i]).DelData;
end;
if (FSeriesList.Count = 0) then
begin
FSeriesList.Add(-1);
//TSeries(FSeriesList.Items[0]).OnStyleChange := DoStyleChange(Self);
case FPlotType of
ptError:
begin
{add two series:}
FSeriesList.Add(-1);
//TSeries(FSeriesList.Items[1]).OnStyleChange := DoStyleChange(Self);
end;
ptLineContour, ptContour, pt3DContour, pt3DWire, pt3DColumn{, pt3DSurface}:
begin
end;
else
begin
{add two series, the second depending on the first:}
{this second series uses the X data of the first series:}
FSeriesList.Add(0);
TSeries(FSeriesList.Items[1]).OnStyleChange := DoStyleChange;
end;
end; {case}
end;
{seed it:}
Randomize;
{set the phase for trig functions:}
Phase := Random;
{initialize: calculate the step size:}
StepSize := (FXAxis.Max - FXAxis.Min) / NoSteps;
{... and the size:}
Amplitude := (FYAxis.Max - FYAxis.Min) / 2;
MidY := (FYAxis.Max + FYAxis.Min) / 2;
for i := 0 to NoSteps do
begin
for j := 0 to FSeriesList.Count-1 do
begin
case FPlotType of
ptError, ptBubble:
begin
if (j mod 2 > 0) then
begin
X := Random;
Y := Random;
end
else
begin
X := FXAxis.Min + i * StepSize;
Y := MidY + Amplitude * Sin(X + (j+1) * Phase) + Random;
end;
end;
ptPolar:
begin
X := (i / NoSteps) * Self.FPolarRange;
Y := FXAxis.Max / 2 + (Amplitude/3) * Sin(X + (j+1) * Phase);
end;
ptLineContour, ptContour, pt3DContour, pt3DWire, pt3DColumn{, pt3DSurface}:
begin
X := FXAxis.Min + i * StepSize;
Y := Exp(-j / 2.0) * (MidY + Amplitude * Sin(X));
end;
else
begin
X := FXAxis.Min + i * StepSize;
Y := MidY + Amplitude * Sin(X + (j+1) * Phase) + Random;
end;
end; {case}
TSeries(FSeriesList.Items[j]).ZData := j;
{Don't fire any events, and don't adjust axes:}
TSeries(FSeriesList.Items[j]).AddPoint(X, Y, FALSE, FALSE);
end; {for j}
end; {for i}
for j := 0 to FSeriesList.Count-1 do
TSeries(FSeriesList.Items[j]).Visible := TRUE;
IgnoreChanges := OldIgnoreChanges;
ZoomOutClick(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CreateMenus
Description: creates popup menus that are accessible by right-click
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 04/20/2000 by Mat Ballard
Purpose: modularize user-interface code
Known Issues: this was a bitch to get right !
------------------------------------------------------------------------------}
procedure TCustomPlot.CreateMenus;
var
i, j: Integer;
{$IFDEF COMPILER4_UP}
ImageIndex: Integer;
{$ENDIF}
TagIndex: Longint;
{This following is just a dummy matrix of menu items used to create sub-menus,
then removed and the menuitems freed.}
{$IFDEF FINANCE}
TempMenu: array [0..Ord(mnuFinance)] of array [0..0] of TMenuItem;
{$ELSE}
TempMenu: array [0..Ord(mnuCalc)] of array [0..0] of TMenuItem;
{$ENDIF}
TempMenuItem: TMenuItem;
StrResName: String;
RightDragItems: array[0..8] of TPoint;
const
{$IFDEF FINANCE}
MaxIndex = Ord(mnuFinance);
{$ELSE}
MaxIndex = Ord(mnuCalc);
{$ENDIF}
NoMenusItems: array [0..MaxIndex] of Integer =
(Ord(mnuPrint),
Ord(mnuProperties),
Ord(mnuZoomOut),
{$IFDEF FUNCTIONS}
Ord(mnuFunction)
{$ELSE}
Ord(mnuTwoRegionLineOfBestFit)
{$ENDIF}
{$IFDEF FINANCE}
, Ord(mnuWilliams));
{$ELSE}
);
{$ENDIF}
procedure CreateTempMenu(k: Integer; ACaption: String);
begin
{we create a temporary menu array to add the submenu, and then later remove it:}
TempMenu[k][0] := TMenuItem.Create(Self);
{ we used to use the caption, until localization:
StrResName := CleanString(ACaption, '&');
StrResName := CleanString(StrResName, '.');
StrResName := CleanString(StrResName, ' ');
StrResName := StrResName + 'SubMenu';}
StrResName := 'm' + IntToStr(k);
TempMenuItem := NewSubMenu(
ACaption,
0,
StrResName,
TempMenu[k]);
TempMenuItem.Tag := TagIndex + TAG_BASE;
FPlotPopUpMenu.Items.Add(TempMenuItem);
Inc(TagIndex);
end;
procedure CreateOnClicks;
begin
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuNew)].OnClick := NewClick;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuOpen)].OnClick := OpenClick;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuOverlayDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuOverlay)].OnClick := OverlayClick;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuClearOverlays)].OnClick := ClearOverlaysClick;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSaveDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSave)].OnClick := SaveClick;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSaveAs)].OnClick := SaveAsClick;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSaveImage)].OnClick := SaveImageClick;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuPrintDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuPrint)].OnClick := PrintClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopy)].OnClick := CopyClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopyHTML)].OnClick := CopyHTMLClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopySeries)].OnClick := CopySeriesClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuPaste)].OnClick := PasteClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDisplaceDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDisplace)].OnClick := DisplaceClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuResetDisplacement)].OnClick := ResetDisplacementClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditSeriesDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuNewSeries)].OnClick := NewSeriesClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCloneSeries)].OnClick := CloneSeriesClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditPoint)].OnClick := EditPointClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditData)].OnClick := EditDataClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditSeries)].OnClick := EditSeriesClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteSeries)].OnClick := DeleteSeriesClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuLinearize)].OnClick := LinearizeClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuZero)].OnClick := ZeroClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuAxisDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuNewYAxis)].OnClick := NewYAxisClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditAxis)].OnClick := EditAxisClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteY2Axis)].OnClick := DeleteAxisClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditFontDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuNewNote)].OnClick := NewNoteClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuMoveNotePointer)].OnClick := MoveNotePointerClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteNote)].OnClick := DeleteNoteClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditFont)].OnClick := EditFontClick;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuPropertiesDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuProperties)].OnClick := EditPropertiesClick;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuHide)].OnClick := HideClick;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuShowAll)].OnClick := ShowAllClick;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuDisplayMode)].OnClick := ModeClick;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuLegend)].OnClick := LegendClick;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuZoomDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuSetAsNormal)].OnClick := SetAsNormalClick;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuNormal)].OnClick := NormalViewClick;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuManualZoom)].OnClick := ManualZoomClick;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuZoomIn)].OnClick := ZoomInClick;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuZoomOut)].OnClick := ZoomOutClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuPosition)].OnClick := PositionClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuNearestPoint)].OnClick := NearestPointClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalcAverageDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalcAverage)].OnClick := AverageClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCompressSeries)].OnClick := CompressSeriesClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCompressAllSeries)].OnClick := CompressAllSeriesClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuContractSeries)].OnClick := ContractSeriesClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuContractAllSeries)].OnClick := ContractAllSeriesClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuHighs)].OnClick := HighsClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuMovingAverage)].OnClick := MovingAverageClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCubicSpline)].OnClick := SplineClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuSmoothSeries)].OnClick := SmoothSeriesClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuSortSeries)].OnClick := SortClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalculusDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuDifferentiate)].OnClick := DifferentiateClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuIntegrate)].OnClick := IntegrateClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuIntegral)].OnClick := IntegralClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuLineOfBestFitDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuLineOfBestFit)].OnClick := LineBestFitClick;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuTwoRegionLineOfBestFit)].OnClick := TwoRegionLineBestFitClick;
{$IFDEF FUNCTIONS}
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuFunctionDiv)].OnClick := nil;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuFunction)].OnClick := FunctionClick;
{$ENDIF}
{$IFDEF FINANCE}
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuADL)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuAroon)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuADX)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuATR)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuBB)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuCCI)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuCMF)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuMACD)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuMA)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuPVO)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuPO)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuPR)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuPVB)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuRSI)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuStochOsc)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuStochRSI)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuTRIN)].OnClick := ADLClick;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuWilliams)].OnClick := ADLClick;
{$ENDIF}
end;
procedure CreateCaptions;
begin
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuNew)].Caption := sNew;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuOpen)].Caption := sOpen;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuOverlayDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuOverlay)].Caption := sOverlay;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuClearOverlays)].Caption := sClearOverlays;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSaveDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSave)].Caption := sSave;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSaveAs)].Caption := sSaveAs;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSaveImage)].Caption := sSaveImage;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuPrintDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuPrint)].Caption := sPrint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopy)].Caption := sCopy;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopyHTML)].Caption := sCopyHTML;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopySeries)].Caption := sCopySeries;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuPaste)].Caption := sPaste;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDisplaceDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDisplace)].Caption := sDisplace;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuResetDisplacement)].Caption := sResetDisplacement;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditSeriesDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuNewSeries)].Caption := sNewSeries;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCloneSeries)].Caption := sCloneSeries;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditPoint)].Caption := sEditPoint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditData)].Caption := sEditData;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditSeries)].Caption := sEditSeries;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteSeries)].Caption := sDeleteSeries;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuLinearize)].Caption := sLinearize;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuZero)].Caption := sZero;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuAxisDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuNewYAxis)].Caption := sNewYAxis;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditAxis)].Caption := sEditAxis;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteY2Axis)].Caption := sDeleteY2Axis;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditFontDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuNewNote)].Caption := sNewNote;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuMoveNotePointer)].Caption := sMoveNotePointer;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteNote)].Caption := sDeleteNote;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditFont)].Caption := sEditFont;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuPropertiesDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuProperties)].Caption := sProperties;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuHide)].Caption := sHide;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuShowAll)].Caption := sShowAll;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuDisplayModeDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuDisplayMode)].Caption := sDisplayMode;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuLegend)].Caption := sLegend;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuZoomDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuSetAsNormal)].Caption := sSetAsNormal;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuNormal)].Caption := sNormal;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuManualZoom)].Caption := sManualZoom;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuZoomIn)].Caption := sZoomIn;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuZoomOut)].Caption := sZoomOut;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuPosition)].Caption := sPosition;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuNearestPoint)].Caption := sNearestPoint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalcAverageDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalcAverage)].Caption := sAverage;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCompressSeries)].Caption := sCompressSeries;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCompressAllSeries)].Caption := sCompressAllSeries;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuContractSeries)].Caption := sContractSeries;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuContractAllSeries)].Caption := sContractAllSeries;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuHighs)].Caption := sHighs;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuMovingAverage)].Caption := sMovingAverage;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCubicSpline)].Caption := sCubicSpline;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuSmoothSeries)].Caption := sSmoothSeries;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuSortSeries)].Caption := sSortSeries;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalculusDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuDifferentiate)].Caption := sDifferentiate;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuIntegrate)].Caption := sIntegrate;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuIntegral)].Caption := sIntegral;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuLineOfBestFitDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuLineOfBestFit)].Caption := sLineOfBestFit;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuTwoRegionLineOfBestFit)].Caption := sTwoRegionLineOfBestFit;
{$IFDEF FUNCTIONS}
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuFunctionDiv)].Caption := '-';
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuFunction)].Caption := sFunction;
{$ENDIF}
{$IFDEF FINANCE}
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuADL)].Caption := sADL;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuAroon)].Caption := sAroon;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuADX)].Caption := sADX;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuATR)].Caption := sATR;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuBB)].Caption := sBB;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuCCI)].Caption := sCCI;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuCMF)].Caption := sCMF;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuMACD)].Caption := sMACD;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuMA)].Caption := sMA;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuPVO)].Caption := sPVO;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuPO)].Caption := sPO;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuPR)].Caption := sPR;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuPVB)].Caption := sPVB;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuRSI)].Caption := sRSI;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuStochOsc)].Caption := sStochOsc;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuStochRSI)].Caption := sStochRSI;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuTRIN)].Caption := sTRIN;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuWilliams)].Caption := sWilliamsR;
{$ENDIF}
end;
procedure CreateHints;
begin
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuNew)].Hint := sNewHint;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuOpen)].Hint := sOpenHint;
//FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuOverlayDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuOverlay)].Hint := sOverlayHint;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuClearOverlays)].Hint := sClearOverlaysHint;
//FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSaveDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSave)].Hint := sSaveHint;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSaveAs)].Hint := sSaveAsHint;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSaveImage)].Hint := sSaveImageHint;
//FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuPrintDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuPrint)].Hint := sPrintHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopy)].Hint := sCopyHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopyHTML)].Hint := sCopyHTMLHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopySeries)].Hint := sCopySeriesHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuPaste)].Hint := sPasteHint;
//FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDisplaceDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDisplace)].Hint := sDisplaceHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuResetDisplacement)].Hint := sResetDisplacementHint;
//FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditSeriesDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuNewSeries)].Hint := sNewSeriesHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCloneSeries)].Hint := sCloneSeriesHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditPoint)].Hint := sEditPointHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditData)].Hint := sEditDataHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditSeries)].Hint := sEditSeriesHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteSeries)].Hint := sDeleteSeriesHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuLinearize)].Hint := sLinearizeHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuZero)].Hint := sZeroHint;
//FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuAxisDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuNewYAxis)].Hint := sNewYAxisHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditAxis)].Hint := sEditAxisHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteY2Axis)].Hint := sDeleteY2AxisHint;
//FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditFontDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuNewNote)].Hint := sNewNoteHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuMoveNotePointer)].Hint := sMoveNotePointerHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteNote)].Hint := sDeleteNoteHint;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditFont)].Hint := sEditFontHint;
//FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditPropertiesDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuProperties)].Hint := sPropertiesHint;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuHide)].Hint := sHideHint;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuShowAll)].Hint := sShowAllHint;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuDisplayMode)].Hint := sDisplayModeHint;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuLegend)].Hint := sLegendHint;
//FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuZoomDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuSetAsNormal)].Hint := sSetAsNormalHint;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuNormal)].Hint := sNormalHint;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuManualZoom)].Hint := sManualZoomHint;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuZoomIn)].Hint := sZoomInHint;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuZoomOut)].Hint := sZoomOutHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuPosition)].Hint := sPositionHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuNearestPoint)].Hint := sNearestPointHint;
//FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalcAverageDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalcAverage)].Hint := sAverageHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCompressSeries)].Hint := sCompressSeriesHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCompressAllSeries)].Hint := sCompressAllSeriesHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuContractSeries)].Hint := sContractSeriesHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuContractAllSeries)].Hint := sContractAllSeriesHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuHighs)].Hint := sHighsHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuMovingAverage)].Hint := sMovingAverageHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCubicSpline)].Hint := sCubicSplineHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuSmoothSeries)].Hint := sSmoothSeriesHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuSortSeries)].Hint := sSortSeriesHint;
//FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalculusDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuDifferentiate)].Hint := sDifferentiateHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuIntegrate)].Hint := sIntegrateHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuIntegral)].Hint := sIntegralHint;
//FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuLineOfBestFitDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuLineOfBestFit)].Hint := sLineOfBestFitHint;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuTwoRegionLineOfBestFit)].Hint := sTwoRegionLineOfBestFitHint;
{$IFDEF FUNCTIONS}
//FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuFunctionDiv)].Hint := nil;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuFunction)].Hint := sFunctionHint;
{$ENDIF}
{$IFDEF FINANCE}
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuADL)].Hint := sADLHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuAroon)].Hint := sAroonHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuADX)].Hint := sADXHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuATR)].Hint := sATRHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuBB)].Hint := sBBHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuCCI)].Hint := sCCIHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuCMF)].Hint := sCMFHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuMACD)].Hint := sMACDHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuMA)].Hint := sMAHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuPVO)].Hint := sPVOHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuPO)].Hint := sPOHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuPR)].Hint := sPRHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuPVB)].Hint := sPVBHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuRSI)].Hint := sRSIHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuStochOsc)].Hint := sStochOscHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuStochRSI)].Hint := sStochRSIHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuTRIN)].Hint := sTRINHint;
FPlotPopUpMenu.Items[Ord(mnuFinance)].Items[Ord(mnuWilliams)].Hint := sWilliamsRHint;
{$ENDIF}
end;
begin
{create the sub-menus:}
TagIndex := 1;
CreateTempMenu(0, sFile);
CreateTempMenu(1, sEdit);
CreateTempMenu(2, sView);
CreateTempMenu(3, sCalc);
{$IFDEF FINANCE}
CreateTempMenu(4, sFinance);
{$ENDIF}
{create the menus in each sub-menu:}
for i := Ord(mnuFile) to MaxIndex do
begin
for j := 0 to NoMenusItems[i] do
begin
TempMenuItem := TMenuItem.Create(Self);
TempMenuItem.Tag := TagIndex + TAG_BASE;
{add the TempMenuItem to the popup:}
FPlotPopUpMenu.Items[i].Add(TempMenuItem);
Inc(TagIndex);
end; {j over menu items}
{remove the temporary menu array used to create the submenu:}
if (FPlotPopUpMenu.Items[i].Items[0].Tag = 0) then
begin
FPlotPopUpMenu.Items[i].Remove(TempMenu[i][0]);
{then free it:}
TempMenu[i][0].Free;
end;
end; {i over submenus}
{now set all the OnClick event handlers, Captions and Hints. What a bitch !}
CreateOnClicks;
CreateCaptions;
CreateHints;
{$IFNDEF SHOWALLMENUS}
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuNormal)].Enabled := FALSE;
{$ENDIF}
{$IFDEF COMPILER4_UP}
ImageIndex := 0;
for i := Ord(mnuFile) to Ord(mnuCalc) do //MaxIndex
begin
for j := 0 to NoMenusItems[i] do
begin
if (FPlotPopUpMenu.Items[i].Items[j].Caption <> '-') then
begin
FPlotPopUpMenu.Items[i].Items[j].ImageIndex := ImageIndex;
Inc(ImageIndex);
end; {not a line}
end; {NoMenusItems}
end; {SubMenus}
{$IFDEF FINANCE}
{If FUNCTIONS are NOT defined, then we need to skip over the Function bitmap resource:}
{$IFNDEF FUNCTIONS}
Inc(ImageIndex);
{$ENDIF}
for j := 0 to NoMenusItems[MaxIndex] do
begin
if (FPlotPopUpMenu.Items[MaxIndex].Items[j].Caption <> '-') then
begin
FPlotPopUpMenu.Items[MaxIndex].Items[j].ImageIndex := ImageIndex;
//Inc(ImageIndex);
end; {not a line}
end; {NoMenusItems}
{$ENDIF}
{$ENDIF} //COMPILER4_UP
{We create the "which" popup menu:}
WhichPopUpMenu := TPopUpMenu.Create(Self);
for i := 0 to 1 do begin
WhichPopUpItems[i] := TMenuItem.Create(Self);
WhichPopUpItems[i].Tag := i;
WhichPopUpMenu.Items.Add(WhichPopUpItems[i]);
end;
{Note: we set the FInstructions just before we display this popup:}
{WhichPopUpItems[0].Caption := 'ClickedObjectType';}
{WhichPopUpItems[1].Caption := 'SecondClickedObjectType';}
WhichPopUpItems[0].OnClick := MoveTheClickedObjectClick;
WhichPopUpItems[1].OnClick := MoveSecondClickedObjectClick;
{We create the "Right Drag" popup menu:}
RightDragItems[0] := Point(Ord(mnuView), Ord(mnuZoomIn));
RightDragItems[1] := Point(Ord(mnuEdit), Ord(mnuLinearize));
RightDragItems[2] := Point(Ord(mnuEdit), Ord(mnuZero));
RightDragItems[3] := Point(Ord(mnuCalc), Ord(mnuCalcAverage));
RightDragItems[4] := Point(Ord(mnuCalc), Ord(mnuContractSeries));
RightDragItems[5] := Point(Ord(mnuCalc), Ord(mnuContractAllSeries));
RightDragItems[6] := Point(Ord(mnuCalc), Ord(mnuIntegral));
RightDragItems[7] := Point(Ord(mnuCalc), Ord(mnuLineOfBestFit));
RightDragItems[8] := Point(Ord(mnuCalc), Ord(mnuTwoRegionLineOfBestFit));
FDragPopUpMenu := TPopupMenu.Create(Self);
for i := 0 to 8 do
begin
TempMenuItem := TMenuItem.Create(Self);
TempMenuItem.Caption :=
FPlotPopUpMenu.Items[RightDragItems[i].x].Items[RightDragItems[i].y].Caption;
{$IFDEF COMPILER4_UP}
TempMenuItem.ImageIndex :=
FPlotPopUpMenu.Items[RightDragItems[i].x].Items[RightDragItems[i].y].ImageIndex;
{$ENDIF}
TempMenuItem.Tag :=
FPlotPopUpMenu.Items[RightDragItems[i].x].Items[RightDragItems[i].y].Tag;
TempMenuItem.OnClick :=
FPlotPopUpMenu.Items[RightDragItems[i].x].Items[RightDragItems[i].y].OnClick;
FDragPopUpMenu.Items.Add(TempMenuItem);
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CreatePageButtons
Description: creates the Page buttons and assigns their properties
Author: Mat Ballard
Date created: 04/28/2001
Date modified: 04/28/2001 by Mat Ballard
Purpose: user interface management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.CreatePageButtons;
var
i: Integer;
begin
if (FPageButtons[0] = nil) then
begin
for i := 0 to 3 do
begin
FPageButtons[i] := TBitmap.Create;
end;
FPageButtons[0].LoadFromResourceName(HInstance, 'BMLEFT');
FPageButtons[1].LoadFromResourceName(HInstance, 'BMRIGHT');
FPageButtons[2].LoadFromResourceName(HInstance, 'BMUP');
FPageButtons[3].LoadFromResourceName(HInstance, 'BMDOWN');
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DestroyPageButtons
Description: frees the Page buttons
Author: Mat Ballard
Date created: 04/28/2001
Date modified: 04/28/2001 by Mat Ballard
Purpose: user interface management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DestroyPageButtons;
var
i: Integer;
begin
if (FPageButtons[0] <> nil) then
begin
for i := 0 to 3 do
begin
FPageButtons[i].Free;
FPageButtons[i] := nil;
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.PageButtonClick
Description: changes the ranges of the axes in Zoomed mode
Author: Mat Ballard
Date created: 04/28/2001
Date modified: 04/28/2001 by Mat Ballard
Purpose: User Interface control of axis ranges and zooming
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.PageButtonClick(Index: Integer);
var
Gap,
OldVar,
NewVar,
MinMax: Single;
begin
case Index of
0: {left}
begin
Gap := FXAxis.Max - FXAxis.Min;
OldVar := FXAxis.Min;
NewVar := OldVar - Gap;
MinMax := FSeriesList.Xmin;
if (NewVar < MinMax) then
NewVar := MinMax;
FXAxis.Min := NewVar;
FXAxis.Max := NewVar + Gap;
end;
1: {right}
begin
Gap := FXAxis.Max - FXAxis.Min;
OldVar := FXAxis.Max;
NewVar := OldVar + Gap;
MinMax := FSeriesList.Xmax;
if (NewVar > MinMax) then
NewVar := MinMax;
FXAxis.Max := NewVar;
FXAxis.Min := NewVar - Gap;
end;
2: {up}
begin
Gap := FYAxis.Max - FYAxis.Min;
OldVar := FYAxis.Max;
NewVar := OldVar + Gap;
MinMax := FSeriesList.Ymax;
if (NewVar > MinMax) then
NewVar := MinMax;
FYAxis.Max := NewVar;
FYAxis.Min := NewVar - Gap;
end;
3: {down}
begin
Gap := FYAxis.Max - FYAxis.Min;
OldVar := FYAxis.Min;
NewVar := OldVar - Gap;
MinMax := FSeriesList.Ymin;
if (NewVar < MinMax) then
NewVar := MinMax;
FYAxis.Min := NewVar;
FYAxis.Max := NewVar + Gap;
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.Destroy
Description: standard destructor
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: free sub-components
Known Issues:
------------------------------------------------------------------------------}
Destructor TCustomPlot.Destroy;
var
i: Integer;
begin
{nil out the events:}
FOnStyleChange := nil;
FOnFileOpen := nil;
FOnFileClose := nil;
FOnHeader := nil;
FOnHeaderRequest := nil;
FOnHTMLHeaderRequest := nil;
FOnSelection := nil;
FOnDualSelection := nil;
{Clear the SeriesList, thereby provoking a file save if required:}
Clear(FALSE);
DestroyPageButtons;
{Free all the Notes:}
for i := NoBasicScreenObjects to ScreenObjectList.Count-1 do
if (TObject(ScreenObjectList.Items[i]) is TNote) then
TNote(ScreenObjectList.Items[i]).Free;
{Free all the Axes:}
for i := FAxisList.Count-1 downto 0 do
TAxis(FAxisList.Items[i]).Free;
{Free the lists of objects:}
FAxisList.Free;
//NoteList.Free;
ScreenObjectList.Free;
FSeriesList.Free;
{Free the visual sub-components}
FInstructions.Free;
FResult.Free;
FLegend.Free;
FTitle.Free;
FBorder.Free;
{free non-visible screen elements:}
LeftBorder.Free;
TopBorder.Free;
RightBorder.Free;
BottomBorder.Free;
Selection.Free;
{Free fonts, pens, etc:}
FHighFont.Free;
FMultiplePen.Free;
MouseTimer.Free;
{Free menus:}
FPopupOptions.Free;
FPlotPopUpMenu.Free;
FDragPopUpMenu.Free;
WhichPopUpMenu.Free;
{then call ancestor:}
inherited Destroy;
end;
{End Constructor and Destructor: ----------------------------------------------}
{Get functions ----------------------------------------------------------------}
{------------------------------------------------------------------------------
Function: TCustomPlot.GetSeries
Description: private property Get function
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: interface to Series property, which is the default property
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetSeries(
Index: Integer): TSeries;
begin
if ((Index < 0) or (Index >= FSeriesList.Count)) then raise
ERangeError.CreateFmt(sGetSeries1, [Index, FSeriesList.Count-1]);
GetSeries := TSeries(FSeriesList.Items[Index]);
end;
{Set procedures ---------------------------------------------------------------}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetAxisDimensions
Description: geometry manager
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets up the border, axes and Title position
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetAxisDimensions;
var
i: Integer;
TheRect: TRect;
pThisYAxis: TAxis;
OldIgnoreChanges: Boolean;
procedure LimitXAxis;
begin
if (FXAxis.Intercept < FYAxis.Min) then
FXAxis.Intercept := FYAxis.Min;
if (FXAxis.Intercept > FYAxis.Max) then
FXAxis.Intercept := FYAxis.Max;
end;
procedure LimitYAxis;
begin
if (FYAxis.Intercept < FXAxis.Min) then
FYAxis.Intercept := FXAxis.Min;
if (FYAxis.Intercept > FXAxis.Max) then
FYAxis.Intercept := FXAxis.Max;
end;
procedure LimitZAxis;
begin
{Intercept on the X Axis:}
if (FZAxis.Intercept < FXAxis.Min) then
FZAxis.Intercept := FXAxis.Min;
if (FZAxis.Intercept > FXAxis.Max) then
FZAxis.Intercept := FXAxis.Max;
{Intercept on the Y Axis:}
if (FZAxis.ZInterceptY < FYAxis.Min) then
FZAxis.ZInterceptY := FYAxis.Min;
if (FZAxis.ZInterceptY > FYAxis.Max) then
FZAxis.ZInterceptY := FYAxis.Max;
end;
begin
OldIgnoreChanges := IgnoreChanges;
IgnoreChanges := TRUE;
if ((FPlotType = ptContour) or
(FPlotType = ptLineContour)) then
begin
if (FYAxis.AutoScale) then
begin
FYAxis.Min := FSeriesList.ZMin;
FYAxis.Max := FSeriesList.ZMax;
end;
end;
{do the simple bits, where the border sets the axis lengths:}
FXAxis.Left := FBorder.Left;
FXAxis.Right := FBorder.Right;
for i := 1 to FAxisList.Count-1 do
begin
pThisYAxis := TAxis(FAxisList[i]);
if (pThisYAxis <> FZAxis) then
begin
pThisYAxis.Top := FBorder.Top;
pThisYAxis.Bottom := FBorder.Bottom;
end;
end;
{Limit the X Axis intercept:}
LimitXAxis;
if (FXAxis.AutoZero) then
if ((FYAxis.Min <= 0) and (0 <= FYAxis.Max)) then
FXAxis.Intercept := 0;
{Limit the Y Axis intercept:}
LimitYAxis;
if (FYAxis.AutoZero) then
if ((FXAxis.Min <= 0) and (0 <= FXAxis.Max)) then
FYAxis.Intercept := 0;
{Limit the secondary Y Axes intercepts:}
for i := 2 to FAxisList.Count-1 do
begin
pThisYAxis := TAxis(FAxisList[i]);
if (not pThisYAxis.AutoScale) then {???}
begin
pThisYAxis.Intercept := FXAxis.Max +
(i-2) * Width;
end;
if (pThisYAxis.AxisType = atTertiary) then
begin
if (pThisYAxis.Intercept < FXAxis.XofF(1)) then
pThisYAxis.Intercept := FXAxis.XofF(1);
if (pThisYAxis.Intercept > FXAxis.XofF(Width-2)) then
pThisYAxis.Intercept := FXAxis.XofF(Width-2);
end
else
begin
{and Secondary axis is limited to the borders:}
if (pThisYAxis.Intercept < FXAxis.Min) then
pThisYAxis.Intercept := FXAxis.Min;
if (pThisYAxis.Intercept > FXAxis.Max) then
pThisYAxis.Intercept := FXAxis.Max;
end;
end;
{Set the screen positions based on the Intercepts:}
FXAxis.MidY := FYAxis.FofY(FXAxis.Intercept);
for i := 1 to FAxisList.Count-1 do
begin
pThisYAxis := TAxis(FAxisList[i]);
if (pThisYAxis <> FZAxis) then
pThisYAxis.MidX := FXAxis.FofX(pThisYAxis.Intercept);
end;
if (FZAxis <> nil) then
begin
{Limit the Z Axis interceptS:}
LimitZAxis;
if (FZAxis.AutoZero) then
if ((FZAxis.Min <= 0) and (0 <= FZAxis.Max)) then
FZAxis.Intercept := 0;
{Set the screen positions based on the Intercepts:}
FZAxis.Left := FXAxis.FofX(FZAxis.Intercept);
FZAxis.Top := FYAxis.FofY(FZAxis.ZInterceptY);
end;
{do the borders for click-and-drag purposes:}
LeftBorder.Top := FBorder.Top;
LeftBorder.Bottom := FBorder.Bottom;
LeftBorder.MidX := FBorder.Left;
RightBorder.Top := FBorder.Top;
RightBorder.Bottom := FBorder.Bottom;
RightBorder.MidX := FBorder.Right;
TopBorder.Left := FBorder.Left;
TopBorder.Right := FBorder.Right;
TopBorder.MidY := FBorder.Top;
BottomBorder.Left := FBorder.Left;
BottomBorder.Right := FBorder.Right;
BottomBorder.MidY := FBorder.Bottom;
{set up the title envelope:}
TheRect.Left := FBorder.Left;
TheRect.Right := FBorder.Right;
TheRect.Top := BevelGap + FTitle.Height;
TheRect.Bottom := Height - BevelGap - FTitle.Height;
FTitle.Envelope := TheRect;
IgnoreChanges := OldIgnoreChanges;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetClickAndDragDelay
Description: standard property Set procedure
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: sets the ClickAndDragDelay Property
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetClickAndDragDelay(Value: Integer);
begin
MouseTimer.Interval := Value;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetBubbleSize
Description: private property Set procedure
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets the BubbleSize in ptBubble mode
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetBubbleSize(Value: TPercent);
begin
FBubbleSize := Value;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetColumnGap
Description: private property Set procedure
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets the Gap between Columns in ptColumn mode
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetColumnGap(Value: TPercent);
begin
FColumnGap := Value;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetContourDetail
Description: private property Set procedure
Author: Mat Ballard
Date created: 02/08/2001
Date modified: 02/08/2001 by Mat Ballard
Purpose: sets the granularity of the colour interpolation in a contour graph.
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetContourDetail(Value: TContourDetail);
begin
FContourDetail := Value;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetContourInterval
Description: private property Set procedure
Author: Mat Ballard
Date created: 07/15/2001
Date modified: 07/15/2001 by Mat Ballard
Purpose: sets the granularity of the intervals in a contour graph.
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetContourInterval(Value: Single);
begin
FContourInterval := Value;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetContourStart
Description: private property Set procedure
Author: Mat Ballard
Date created: 07/15/2001
Date modified: 07/15/2001 by Mat Ballard
Purpose: sets the granularity of the Starts in a contour graph.
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetContourStart(Value: Single);
begin
FContourStart := Value;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetContourWireFrame
Description: private property Set procedure
Author: Mat Ballard
Date created: 07/15/2001
Date modified: 07/15/2001 by Mat Ballard
Purpose: sets the presence or absence of a wireframe on the 3D surface
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetContourWireFrame(Value: Boolean);
begin
FContourWireFrame := Value;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetDefaultExtension
Description: private property Set procedure
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets the DefaultExtension for TPlot files
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetDefaultExtension(
Value: String);
begin
FDefaultExtension := Value;
FileExtensions[0] := Value;
FileTypes :=
{$IFDEF MSWINDOWS}
'Plot ' + sFiles + '*.' + Value
+ '|Comma Sep Var ' + sFiles + '|*.csv'
+ '|' + sText + ' ' + sFiles + '|*.txt'
+ '|' + sAll + ' ' + sFiles + '|*.*';
{$ENDIF}
{$IFDEF LINUX}
'Plot ' + sFiles + '(*.' + Value +
')|Comma Sep Var ' + sFiles + ' (*.csv)' +
'|' + sText + ' ' + sFiles + ' (*.txt)' +
'|' + sAll + ' ' + sFiles + ' (*.*)';
{$ENDIF}
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetDisplayMode
Description: private property Set procedure
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets the DisplayMode property, which is how
graphs are updated when more data is Added
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetDisplayMode(
Value: TDisplayMode);
begin
if (FDisplayMode = Value) then exit;
SetDisplayModeHistory(FDisplayHistory, Value);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetDisplayModeHistory
Description: adjusts axes and sets DisplayMode and History properties
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: DisplayMode and History must be set and the graph updated simultaneously.
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetDisplayModeHistory(
HistoryValue: Single;
ScalingValue: TDisplayMode);
begin
if (ScalingValue = dmHistory) then
begin
{we are changing to History from normal behaviour,
or we are in History mode:}
FXAxis.Min := -HistoryValue;
FXAxis.Max := 0;
FYAxis.Intercept := -HistoryValue;
end
else if (FDisplayMode = dmHistory) then
begin
{We are changing from History to normal behaviour.
We therefore need to reset the X Axis dimensions:}
if (ScalingValue = dmRun) then
FXAxis.Max := 1.5 * FSeriesList.Xmax
else
FXAxis.Max := FSeriesList.Xmax;
FXAxis.Min := FSeriesList.Xmin;
FYAxis.Intercept := FXAxis.Min;
end;
FDisplayHistory := HistoryValue;
FDisplayMode := ScalingValue;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetGrid
Description: private property Set procedure
Author: Mat Ballard
Date created: 02/28/2001
Date modified: 02/28/2001 by Mat Ballard
Purpose: do we want a grid in XY-type graphs ?
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetGrid(Value: TGridType);
begin
if (FGrid = Value) then exit;
FGrid := Value;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetGridStyle
Description: private property Set procedure
Author: Mat Ballard
Date created: 02/28/2001
Date modified: 02/28/2001 by Mat Ballard
Purpose: do we want a grid in XY-type graphs ?
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetGridStyle(Value: TPenStyle);
begin
if (FGridStyle = Value) then exit;
FGridStyle := Value;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetGridColor
Description: private property Set procedure
Author: Mat Ballard
Date created: 02/28/2001
Date modified: 02/28/2001 by Mat Ballard
Purpose: do we want a grid in XY-type graphs ?
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetGridColor(Value: TColor);
begin
if (FGridColor = Value) then exit;
FGridColor := Value;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetWallColor
Description: private property Set procedure
Author: Mat Ballard
Date created: 02/28/2001
Date modified: 02/28/2001 by Mat Ballard
Purpose: do we want a Wall in XY-type graphs ?
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetWallColor(Value: TColor);
begin
if (FWallColor = Value) then exit;
FWallColor := Value;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetFileName
Description: private property Set procedure
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets and parses the FileName property
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetFileName(
Value: String);
begin
if (FFileName = Value) then exit;
FFileName := Value;
if (Length(FFileName) > 0) then
begin
PropsFileName := GetFileDriveDir;
PropsFileName := PropsFileName + GetFileRoot + '.';
PropsFileName := PropsFileName + PROP_EXTENSION;
end
else
PropsFileName := '';
end;
{------------------------------------------------------------------------------
Functions: TCustomPlot.GetFileXXX
Description: gets various file parameters from the name
Author: Mat Ballard
Date created: 08/10/2000
Date modified: 08/10/2000 by Mat Ballard
Purpose: file management
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetFileExtension: String; {csv}
var
FileExtension: String;
begin
FileExtension := LowerCase(ExtractFileExt(FFileName));
if (Pos('.', FileExtension) = 1) then
FileExtension := Copy(FileExtension, 2, Length(FileExtension));
GetFileExtension := FileExtension;
end;
function TCustomPlot.GetFileDriveDir: String; {D:\Data\Delphi\Plot}
var
FileDriveDir: String;
begin
FileDriveDir := ExtractFilePath(FFileName);
if (Length(FileDriveDir) = 0) then
FileDriveDir := GetCurrentDir;
GetFileDriveDir := FileDriveDir;
end;
function TCustomPlot.GetFileRoot: String; {Test3}
var
Ext,
FileRoot: String;
i: Integer;
begin
Ext := GetFileExtension;
if (Length(Ext) > 0) then
begin
FileRoot := ExtractFileName(FFileName);
i := Pos(Ext, FileRoot);
FileRoot := Copy(FileRoot, 1, i-2);
end
else
FileRoot := FFileName;
GetFileRoot := FileRoot;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.GetFilterIndex
Description: gets the file filter index from the extension
Author: Mat Ballard
Date created: 08/10/2000
Date modified: 08/10/2000 by Mat Ballard
Purpose: file management
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetFilterIndex(
Ext: String): Integer;
var
i: Integer;
begin
{the default filterindex is actually '*'}
GetFilterIndex := 4;
for i := 0 to 3 do
begin
if (LowerCase(Ext) = FileExtensions[i]) then
begin
GetFilterIndex := i+1;
break;
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetHistory
Description: private property Set procedure
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets the History property: which is how far back
a History graph goes
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetHistory(
Value: Single);
begin
if (FDisplayHistory = Value) then exit;
SetDisplayModeHistory(Value, FDisplayMode);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetInstructions
Description: private property Set procedure
Author: Mat Ballard
Date created: 10/09/1999
Date modified: 10/09/2000 by Mat Ballard
Purpose: sets the Instructions property
Known Issues: Fixed IDE crash when Instructions set
------------------------------------------------------------------------------}
procedure TCustomPlot.SetInstructions(Value: TStringList);
begin
if (Value.Count > 0) then
FInstructions.Assign(Value)
else
FInstructions.Clear;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetInstructions
Description: private property Set procedure
Author: Mat Ballard
Date created: 07/23/2001
Date modified: 07/23/2001 by Mat Ballard
Purpose: sets the Instructions property by its text
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetInstructionText(Value: String);
begin
FInstructions.Text := Value;
DoStyleChange(Self);
end;
{$IFDEF COMPILER4_UP}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetImages
Description: private property Set procedure
Author: Mat Ballard
Date created: 10/09/1999
Date modified: 10/09/2000 by Mat Ballard
Purpose: sets the Images property
Known Issues: TMenu.Images is of type TCustomImageList, which lurks in unit
imglist; however, BC++'s DCLSTD35 contains an imglist, and so
we get a namespace collision.
------------------------------------------------------------------------------}
procedure TCustomPlot.SetImages(Value: TImageList);
begin
FPlotPopUpMenu.Images := Value;
FDragPopUpMenu.Images := Value;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.GetImages
Description: private property Set procedure
Author: Mat Ballard
Date created: 10/09/1999
Date modified: 10/09/2000 by Mat Ballard
Purpose: sets the Images property
Known Issues: TMenu.Images is of type TCustomImageList, which lurks in unit
imglist; however, BC++'s DCLSTD35 contains an imglist, and so
we get a namespace collision.
------------------------------------------------------------------------------}
function TCustomPlot.GetImages: TImageList;
begin
GetImages := TImageList(FPlotPopUpMenu.Images);
end;
{$ENDIF}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetMetafileDescription
Description: sets the CreatedBy and Description properties
if they are not yet set
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: fully utilise enhanced metafile capabilities to
put keywords into WMF
Known Issues:
------------------------------------------------------------------------------}
{$IFDEF MSWINDOWS}
{$IFDEF COMPILER2_UP}
procedure TCustomPlot.SetMetafileDescription;
var
i: Integer;
begin
if (Length(FCreatedBy) = 0) then
FCreatedBy := 'Chemware';
FCreatedBy := InputBox(sAuthor, sCreatedBy2, FCreatedBy);
if (Length(FDescription) = 0) then
begin
FDescription := FTitle.Caption + ': ';
for i := 0 to FSeriesList.Count-1 do
begin
FDescription := FDescription + TSeries(FSeriesList.Items[i]).Name + ', ';
end;
{remove trailing ', ':}
SetLength(FDescription, Length(FDescription)-2);
end;
FDescription := InputBox(sAuthor, sSetMetafileDescription1, FDescription);
end;
{$ENDIF}
{$ENDIF}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetMultiplicity
Description: standard property Set procedure
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets the Multiplicity property
Known Issues: see also: PlotTpe property
------------------------------------------------------------------------------}
procedure TCustomPlot.SetMultiplicity(Value: Byte);
begin
FMultiplicity := Value;
if (FPlotType = ptMultiple) then DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetMultiplePen
Description: standard property Set procedure
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets the Multiplicity property
Known Issues: see also: PlotType property
------------------------------------------------------------------------------}
procedure TCustomPlot.SetMultiplePen(Value: TPen);
begin
FMultiplePen.Assign(Value);
if (FPlotType = ptMultiple) then DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Function: TCustomPlot.GetMultiJoin
Description: standard property Set procedure
Author: Mat Ballard
Date created: 04/18/2001
Date modified: 04/18/2001 by Mat Ballard
Purpose: sets the MultiJoin property
Return Value: String, in the form "x,y"
Known Issues: see also: PlotType property
------------------------------------------------------------------------------}
function TCustomPlot.GetMultiJoin: String;
begin
GetMultiJoin := Format('%d,%d', [FMultiJoin1, FMultiJoin2]);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetMultiJoin
Description: standard property Set procedure
Author: Mat Ballard
Date created: 04/18/2001
Date modified: 04/18/2001 by Mat Ballard
Purpose: sets the MultiJoin property
Known Issues: see also: PlotType property
------------------------------------------------------------------------------}
procedure TCustomPlot.SetMultiJoin(Value: String);
var
TempStr, TheCell: String;
Index: Integer;
begin
if (Value = GetMultiJoin) then exit;
if (Pos(',', Value) > 0) then
begin
TempStr := Value;
TheCell := GetWord(TempStr, ',');
{If any of this throws an exception, we know we have a loser:}
try
Index := StrToInt(TheCell);
{if ((Index < 0) or (Index >= FSeriesList.Count)) then}
FMultiJoin2 := StrToInt(TempStr);
FMultiJoin1 := Index;
except
ShowMessage(Value + sSetMultiJoin1 + #10 + #10 +
sSetMultiJoin2);
end;
if (FPlotType = ptMultiple) then DoStyleChange(Self);
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetPieRowCount
Description: standard property Set procedure
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets the PieRowCount property
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetPieRowCount(Value: Byte);
begin
if ((Value > 0) and
(Value <= FSeriesList.Count) and
(Value <> FPieRowCount)) then
begin
FPieRowCount := Value;
DoStyleChange(Self);
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetNoSeries
Description: standard property Set procedure
Author: Mat Ballard
Date created: 22/12/2000
Date modified: 22/12/2000 by Mat Ballard
Purpose: sets the NoSeries property
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetNoSeries(Value: Word);
var
i,
j: Integer;
begin
if (Value = FSeriesList.Count) then exit;
if (Value > FSeriesList.Count) then
begin
for i := FSeriesList.Count+1 to Value do
begin
{note that the series are added with independent X data:}
j := FSeriesList.Add(-1);
TSeries(FSeriesList.Items[j]).OnStyleChange := DoStyleChange;
end;
if (csDesigning in ComponentState) then
MakeDummyData(20);
end
else
begin
for i := FSeriesList.Count-1 downto Value do
DeleteSeries(i);
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetOutlineWidth
Description: standard property Set procedure
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets the OutlineWidth property
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetOutlineWidth(
Value: Integer);
begin
if (FOutlineWidth = Value) then exit;
{Set border widths:}
FOutlineWidth := Value;
LeftBorder.Height := FOutlineWidth;
LeftBorder.Width := FOutlineWidth;
TopBorder.Height := FOutlineWidth;
TopBorder.Width := FOutlineWidth;
RightBorder.Height := FOutlineWidth;
RightBorder.Width := FOutlineWidth;
BottomBorder.Height := FOutlineWidth;
BottomBorder.Width := FOutlineWidth;
{Set axis widths:}
FXAxis.Height := FOutlineWidth;
FYAxis.Width := FOutlineWidth;
SetAxisDimensions;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetOnSelection
Description: standard property Set procedure
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: sets the OnSelection event
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetOnSelection(Value: TOnSelectionEvent);
begin
FOnSelection := Value;
ScreenJob := sjSelection;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetOnDualSelection
Description: standard property Set procedure
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: sets the OnDualSelection event
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetOnDualSelection(Value: TOnDualSelectionEvent);
begin
FOnDualSelection := Value;
ScreenJob := sjDualSelection1;
end;
{The painting/drawing methods -----------------------------------------------}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.Paint
Description: painting the graph
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: paints the background, border, then draws the graph: NOT called by graphics and printer.
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.Paint;
{const
Alignments: array[TAlignment] of Longint = (DT_LEFT, DT_RIGHT, DT_CENTER);}
var
iX, iY: Integer;
Rect: TRect;
TopColor,
BottomColor: TColor;
procedure AdjustColors(Bevel: TPanelBevel);
begin
TopColor := clBtnHighlight;
if Bevel = bvLowered then TopColor := clBtnShadow;
BottomColor := clBtnShadow;
if Bevel = bvLowered then BottomColor := clBtnHighlight;
end;
begin
{$IFDEF DELPHI3_UP}
Assert(Canvas <> nil, sPaintError);
{$ENDIF}
if Assigned(FOnBeforePaint) then
OnBeforePaint(Self, Canvas);
Canvas.Pen.Mode := pmCopy;
Canvas.Pen.Style := psSolid;
BevelGap := 0;
Rect := GetClientRect;
if BevelOuter <> bvNone then
begin
Inc(BevelGap);
AdjustColors(BevelOuter);
Frame3D(Canvas, Rect, TopColor, BottomColor, BevelWidth);
end;
Frame3D(Canvas, Rect, Color, Color, BorderWidth);
if BevelInner <> bvNone then
begin
Inc(BevelGap);
AdjustColors(BevelInner);
Frame3D(Canvas, Rect, TopColor, BottomColor, BevelWidth);
end;
BevelGap := BevelGap * BevelWidth;
Canvas.Brush.Color := Color;
Canvas.FillRect(Rect);
Canvas.Brush.Style := bsClear;
Draw(Canvas);
Canvas.Brush.Color := Color;
Canvas.Brush.Style := bsClear;
{The Instructions are usually an instruction to the user.
As such, it does not need to be copied or printed,
so it is placed here, rather than in the "Draw" method:}
DrawInstructions;
if (FPageButtons[0] <> nil) then
begin
{Right:}
iX := Self.Width - FPageButtons[1].Width - 1;
iY := Self.Height - FPageButtons[1].Height - 1;
Canvas.Draw(iX, iY, FPageButtons[1]);
{Down}
iX := iX - FPageButtons[3].Width;
Canvas.Draw(iX, iY, FPageButtons[3]);
{Up}
Canvas.Draw(iX, iY - FPageButtons[2].Height, FPageButtons[2]);
{Left}
iX := iX - FPageButtons[0].Width;
Canvas.Draw(iX, iY, FPageButtons[0]);
end;
if Assigned(FOnAfterPaint) then
OnAfterPaint(Self, Canvas);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DrawInstructions
Description: draws the instructions
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: tell the user what to do
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DrawInstructions;
var
FontHeight,
iX,
iY,
i: Integer;
{$IFDEF LINUX}
//ARect: TRect;
{$ENDIF}
begin
{The Instructions are usually an instruction to the user.
As such, it does not need to be copied or printed,
so it is placed here, rather than in the "Draw" method:}
if (FInstructions.Count > 0) then
begin
Canvas.Font.Assign(Font);
FontHeight := Canvas.TextHeight('Wp');
{Adjust the Position appropriately:}
iX := BevelGap + 5;
iY := Height - BevelGap - FontHeight;
{how many lines ?}
for i := FInstructions.Count-1 downto 0 do
begin
{Output the text:}
{$IFDEF MSWINDOWS}
Canvas.TextOut(iX, iY, FInstructions[i]);
{$ENDIF}
{$IFDEF LINUX}
Canvas.TextOut(iX, iY{ + Abs(Canvas.Font.Height)}, FInstructions[i]);
//Canvas.TextRect(ARect, iX, iY, FInstructions[i], TOPLEFT_ALIGN);
{$ENDIF}
Dec(iY, FontHeight);
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.Draw
Description: painting the graph
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: draws the graph on a canvas: graphics and printers call this procedure directly
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.Draw(
ACanvas: TCanvas);
var
FontHeight,
FontWidth,
i,
iX,
iY,
SeriesIncrement: Integer;
OldIgnoreChanges: Boolean;
begin
{$IFDEF DELPHI3_UP}
Assert(ACanvas <> nil, sDrawError);
{$ENDIF}
if Assigned(FOnBeforeDraw) then
OnBeforeDraw(Self, ACanvas);
OldIgnoreChanges := IgnoreChanges;
IgnoreChanges := TRUE;
FTitle.Draw(ACanvas);
if (FResult.Visible) and (Length(FResult.Caption) > 0) then
begin
ACanvas.Font.Assign(FResult.Font);
FontHeight := Abs(ACanvas.Font.Height);
FontWidth := ACanvas.TextWidth(FResult.Caption);
{calculate the caption dimensions:}
FResult.Right := FResult.Left + FontWidth;
FResult.Bottom := FResult.Top + FontHeight;
{output text to screen:}
ACanvas.TextOut(FResult.Left, FResult.Top, FResult.Caption);
{now draw the line itself:}
{Y = Intercept + Slope * X <=> X = (Y - Intercept) / Slope}
ACanvas.Pen.Style := psDot;
ACanvas.Pen.Color := Font.Color;
iX := FXAxis.FofX(XAxis.Min);
iY := FYAxis.FofY(Intercept + Slope * XAxis.Min);
if (iY < Border.Top) then
begin
iY := Border.Top;
iX := FXAxis.FofX((FYAxis.YofF(iY) - Intercept)/Slope);
end
else if (iY > Border.Bottom) then
begin
iY := Border.Bottom;
iX := FXAxis.FofX((FYAxis.YofF(iY) - Intercept)/Slope);
end;
ACanvas.MoveTo(iX, iY);
iX := FXAxis.FofX(XAxis.Max);
iY := FYAxis.FofY(Intercept + Slope * XAxis.Max);
if (iY < Border.Top) then
begin
iY := Border.Top;
iX := FXAxis.FofX((FYAxis.YofF(iY) - Intercept)/Slope);
end
else if (iY > Border.Bottom) then
begin
iY := Border.Bottom;
iX := FXAxis.FofX((FYAxis.YofF(iY) - Intercept)/Slope);
end;
Canvas.LineTo(iX, iY);
end; {Result Visible}
if (FGrid > gtNone) then
begin
if (FPlotType <= ptBubble) then
DrawGrid(ACanvas);
if (FPlotType >= pt3DContour) then
DrawWalls(ACanvas);
end;
FXAxis.Draw(ACanvas, FYAxis.Top);
for i := 1 to FAxisList.Count-1 do
TAxis(FAxisList[i]).Draw(ACanvas, FXAxis.Right);
if ((FPlotType = ptError) or
(FPlotType = ptBubble)) then
SeriesIncrement := 2
else
SeriesIncrement := 1;
FLegend.Draw(ACanvas, SeriesIncrement);
ACanvas.Font.Assign(FHighFont);
case FPlotType of
ptXY:
begin
if (FDisplayMode < dmHistory) then
FSeriesList.Draw(ACanvas, FXYFastAt)
else
FSeriesList.DrawHistory(ACanvas, FDisplayHistory);
end;
ptError:
begin
if (FDisplayMode < dmHistory) then
FSeriesList.DrawError(ACanvas);
end;
ptMultiple:
begin
if (FDisplayMode < dmHistory) then
begin
FSeriesList.DrawMultiple(ACanvas,
FMultiplicity,
FMultiplePen,
FMultiJoin1, FMultiJoin2);
end
else
begin
FSeriesList.DrawHistory(ACanvas, FDisplayHistory);
ACanvas.Pen.Assign(FMultiplePen);
FSeriesList.DrawHistoryMultiple(ACanvas, FMultiplicity);
end;
end;
ptBubble:
begin
if (FDisplayMode < dmHistory) then
FSeriesList.DrawBubble(ACanvas, FBubbleSize);
{else
FSeriesList.DrawHistory(ACanvas, FDisplayHistory);}
end;
ptColumn:
begin
if (FDisplayMode < dmHistory) then
FSeriesList.DrawColumns(ACanvas, FColumnGap);
{else
FSeriesList.DrawHistory(ACanvas, FDisplayHistory);}
end;
ptStack:
if (FDisplayMode < dmHistory) then
FSeriesList.DrawStack(ACanvas, FColumnGap);
{else
FSeriesList.DrawHistory(ACanvas, FDisplayHistory);}
ptNormStack:
if (FDisplayMode < dmHistory) then
FSeriesList.DrawNormStack(ACanvas, FColumnGap);
{else
FSeriesList.DrawHistory(ACanvas, FDisplayHistory);}
ptPie:
if (FDisplayMode < dmHistory) then
begin
FSeriesList.DrawPie(ACanvas, FBorder, FPieRowCount);
end;
{else
FSeriesList.DrawHistory(ACanvas, FDisplayHistory);}
ptPolar:
if (FDisplayMode < dmHistory) then
FSeriesList.DrawPolar(ACanvas, FPolarRange);
{else
FSeriesList.DrawHistory(ACanvas, FDisplayHistory);}
ptLineContour:
begin
if (FDisplayMode < dmHistory) then
FSeriesList.DrawLineContour(ACanvas, FContourStart, FContourInterval, FContourDetail);
end;
ptContour:
begin
if (FDisplayMode < dmHistory) then
FSeriesList.DrawContour(ACanvas, FContourDetail);
end;
pt3DContour:
begin
if (FDisplayMode < dmHistory) then
FSeriesList.Draw3DContour(ACanvas, FZAxis, FContourDetail, FContourWireFrame);
//DrawContourColors(ACanvas);
end;
pt3DWire:
begin
if (FDisplayMode < dmHistory) then
FSeriesList.Draw3DWire(ACanvas, FZAxis, FZLink);
end;
pt3DColumn:
begin
if (FDisplayMode < dmHistory) then
FSeriesList.Draw3DColumn(ACanvas, FZAxis, FColumnGap)
end;
{pt3DSurface:
begin
if (FDisplayMode < dmHistory) then
FSeriesList.Draw3DSurface(ACanvas, FZAxis);
end;}
end;
for i := NoBasicScreenObjects to ScreenObjectList.Count-1 do
begin
if (TObject(ScreenObjectList.Items[i]) is TNote) then
TNote(ScreenObjectList.Items[i]).Draw(ACanvas);
end;
if Assigned(FOnAfterDraw) then
OnAfterDraw(Self, ACanvas);
IgnoreChanges := OldIgnoreChanges;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DrawGrid
Description: painting the graph
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: draws the grid for xy-type plots
Comments:
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DrawGrid(
ACanvas: TCanvas);
var
iX, iY: Integer;
X, Y: Single;
begin
ACanvas.Pen.Color := FGridColor;
ACanvas.Pen.Width := 1;
ACanvas.Pen.Style := FGridStyle;
{do the verticals:}
if (FGrid > gtHorizontal) then
begin
X := FXAxis.StepStart;
while (X < FXAxis.Max) do
begin
iX := FXAxis.FofX(X);
if (iX <> FYAxis.MidX) then
begin
ACanvas.MoveTo(iX, FYAxis.Bottom);
ACanvas.LineTo(iX, FYAxis.Top);
end;
X := FXAxis.GetNextXValue(X);
end;
end;
{do the horizontals:}
if ((FGrid = gtHorizontal) or (FGrid = gtBoth)) then
begin
Y := FYAxis.StepStart;
while (Y < FYAxis.Max) do
begin
iY := FYAxis.FofY(Y);
if (iY <> FXAxis.MidY) then
begin
ACanvas.MoveTo(FXAxis.Left, iY);
ACanvas.LineTo(FXAxis.Right, iY);
end;
Y := FYAxis.GetNextXValue(Y);
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DrawWalls
Description: painting the graph
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: draws the grids for 3D plots
Comments:
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DrawWalls(
ACanvas: TCanvas);
var
iX, iY: Integer;
X, Y, Z: Single;
dZ,
TheTickStart: TPoint;
TheWall: array[0..3] of TPoint;
begin
ACanvas.Pen.Style := psClear;
ACanvas.Brush.Style := bsSolid;
dZ.x := FZAxis.EndX - FZAxis.Left;
dZ.y := FZAxis.EndY - FZAxis.Top;
{Calculate the XY wall:}
TheWall[0].x := FBorder.Left;
TheWall[0].y := FBorder.Top;
TheWall[1].x := TheWall[0].x;
TheWall[1].y := FBorder.Bottom;
TheWall[2].x := FBorder.Right;
TheWall[2].y := TheWall[1].y;
TheWall[3].x := TheWall[2].x;
TheWall[3].y := TheWall[0].y;
{Draw the XY wall:}
ACanvas.Brush.Color := FWallColor;
ACanvas.Polygon(TheWall);
{Calculate the YZ wall:}
if (FZAxis.Angle >= 180) then
begin
TheWall[2].x := TheWall[0].x + dZ.x;
TheWall[2].y := TheWall[1].y + dZ.y;
TheWall[3].x := TheWall[2].x;
TheWall[3].y := TheWall[2].y - FYAxis.Height;
end
else
begin
TheWall[0].x := FBorder.Right;
TheWall[0].y := FBorder.Top;
TheWall[1].x := TheWall[0].x;
TheWall[1].y := FBorder.Bottom;
TheWall[2].x := TheWall[0].x + dZ.x;
TheWall[2].y := TheWall[1].y + dZ.y;
TheWall[3].x := TheWall[2].x;
TheWall[3].y := TheWall[2].y - FYAxis.Height;
end;
{Draw the YZ left wall:}
ACanvas.Brush.Color := Misc.GetDarkerColor(FWallColor, 80);
ACanvas.Polygon(TheWall);
{Calculate the XZ floor:}
TheWall[0].x := FBorder.Left;
TheWall[0].y := FBorder.Bottom;
{These four are repeated because if angle < 180 ...}
TheWall[1].x := TheWall[0].x + dZ.x;
TheWall[1].y := TheWall[0].y + dZ.y;
TheWall[2].x := TheWall[1].x + FBorder.Width;
TheWall[2].y := TheWall[1].y;
TheWall[3].x := FBorder.Right;
TheWall[3].y := TheWall[0].y;
{Draw the XZ left wall:}
ACanvas.Brush.Color := GetDarkerColor(FWallColor, 50);
ACanvas.Polygon(TheWall);
{reset pen:}
//ACanvas.Pen.Style := psSolid;
ACanvas.Brush.Style := bsClear;
ACanvas.Pen.Color := FGridColor;
ACanvas.Pen.Width := 1;
ACanvas.Pen.Style := FGridStyle;
{do the XY and XZ grids:}
if (FGrid > gtHorizontal) then
begin
X := FXAxis.StepStart;
while (X <= FXAxis.Max) do
begin
iX := FXAxis.FofX(X);
{XY: vertical |||}
ACanvas.MoveTo(iX, FBorder.Top);
ACanvas.LineTo(iX, FBorder.Bottom);
{XZ: vertical ///}
//ACanvas.MoveTo(iX, FYAxis.Bottom);
ACanvas.LineTo(iX + dZ.x, FBorder.Bottom + dZ.y);
X := FXAxis.GetNextXValue(X);
end;
end;
{do the XY and YZ grids:}
if ((FGrid = gtHorizontal) or (FGrid = gtBoth)) then
begin
Y := FYAxis.StepStart;
while (Y < FYAxis.Max) do
begin
iY := FYAxis.FofY(Y);
if (iY <> FXAxis.MidY) then
begin
if (FZAxis.Angle >= 180) then
begin
{XY: horizontal ---}
ACanvas.MoveTo(FBorder.Right, iY);
ACanvas.LineTo(FBorder.Left, iY);
{YZ: horizontal ///}
ACanvas.LineTo(FBorder.Left + dZ.x, iY + dZ.y);
end
else
begin
{XY: horizontal ---}
ACanvas.MoveTo(FBorder.Left, iY);
ACanvas.LineTo(FBorder.Right, iY);
{YZ: horizontal ///}
ACanvas.LineTo(FBorder.Right + dZ.x, iY + dZ.y);
end;
end;
Y := FYAxis.GetNextXValue(Y);
end;
end;
{do the horizontal Xs and vertical Zs:}
Z := FZAxis.StepStart;
while (Z < FZAxis.Max) do
begin
TheTickStart := FZAxis.dFofZ(Z);
Inc(TheTickStart.x, FBorder.Left);
Inc(TheTickStart.y, FBorder.Bottom);
{XZ: horizontal: ---}
if ((FGrid = gtHorizontal) or (FGrid = gtBoth)) then
begin
ACanvas.MoveTo(TheTickStart.x + FXAxis.Width, TheTickStart.y);
ACanvas.LineTo(TheTickStart.x, TheTickStart.y);
end;
{YZ: vertical}
if (FGrid > gtHorizontal) then
begin
if (FZAxis.Angle >= 180) then
begin
ACanvas.MoveTo(TheTickStart.x, TheTickStart.y);
ACanvas.LineTo(TheTickStart.x, TheTickStart.y - FBorder.Height);
end
else
begin
ACanvas.MoveTo(TheTickStart.x + FBorder.Width, TheTickStart.y);
ACanvas.LineTo(TheTickStart.x + FBorder.Width, TheTickStart.y - FBorder.Height);
end;
end;
Z := FZAxis.GetNextXValue(Z);
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.Trace
Description: This traces all series: useful for Oscilloscopes
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Draws all Series in erasable mode
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.Trace;
var
i: Integer;
begin
{$IFDEF DELPHI3_UP}
Assert(Canvas <> nil, sTraceError);
{$ENDIF}
for i := 0 to FSeriesList.Count-1 do
begin
TSeries(FSeriesList.Items[i]).Trace(Canvas);
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.Resize
Description: overrides ancestor's ReSize
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: responds to a resize of the Plot
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.Resize;
var
OldIgnoreChanges: Boolean;
begin
OldIgnoreChanges := IgnoreChanges;
IgnoreChanges := TRUE;
FBorder.RightEx := Width;
FBorder.BottomEx := Height;
IgnoreChanges := OldIgnoreChanges;
SetAxisDimensions;
//DoStyleChange(Self);
inherited Resize;
{Required for 3D walls to display properly:}
if (FGrid > gtNone) then
if (FPlotType >= pt3DContour) then
begin
Application.ProcessMessages;
Refresh;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.StyleChange
Description: target of all of the sub-component OnStyleChange events
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: responds to changes in sub-components
Known Issues: get up to 3 screen re-draws
------------------------------------------------------------------------------}
{procedure TCustomPlot.StyleChange(
Sender: TObject);
begin
if (IgnoreChanges) then exit;
SetAxisDimensions;
DoStyleChange(Self);
end;}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DataChange
Description: target of TSeriesList (TSeries) OnDataChange event
Author: Mat Ballard
Date created: 03/07/2001
Date modified: 03/07/2001 by Mat Ballard
Purpose: responds to changes in sub-components
Known Issues:
------------------------------------------------------------------------------}
{procedure TCustomPlot.DataChange(
Sender: TObject);
begin
if (IgnoreChanges) then exit;
DoDataChange;
end;}
{Mousey stuff -----------------------------------------------------------------}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DblClick
Description: overrides ancestor's DblClick
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: activates in-place editing of titles
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DblClick;
var
i: Integer;
TheRect: TRect;
TheCaption: TCaption;
TheRight: Integer;
begin
{get rid of the mouse moving timer:}
MouseTimer.Enabled := FALSE;
if (FEditable) then
begin
if ((ClickedObjectType = soTitle) or
(ClickedObjectType = soXAxisTitle) or
(ClickedObjectType = soYAxisTitle) or
(ClickedObjectType = soNote)) then
begin
FScreenJob := sjFlashEdit;
TheCaption := TCaption(pClickedObject);
{create the in-place editor:}
CreateFlashEditor;
{... and initialize it:}
if (ClickedObjectType = soNote) then
FFlashEdit.Text := TheCaption.Caption
else
FFlashEdit.Text := TTitle(pClickedObject).FullCaption;
FFlashEdit.Height := TheCaption.Height + 10;
FFlashEdit.Width := 2 * TheCaption.Width;
if (FFlashEdit.Height > FFlashEdit.Width) then
begin
{height > width, so it is a vertical caption:}
i := FFlashEdit.Height;
FFlashEdit.Height := FFlashEdit.Width;
FFlashEdit.Width := i;
end;
FFlashEdit.Top := TheCaption.Top;
{Have to check that the edit box is on-screen:}
TheRight := TheCaption.Left + FFlashEdit.Width;
if (TheRight > Width) then
FFlashEdit.Left := TheCaption.Right - FFlashEdit.Width
else
FFlashEdit.Left := TheCaption.Left;
FFlashEdit.Tag := Ord(ClickedObjectType);
FFlashEdit.Font.Assign(TheCaption.Font);
FFlashEdit.Visible := TRUE;
FFlashEdit.SetFocus;
end {Title or axis caption}
else if (ClickedObjectType = soLegend) then
begin
FScreenJob := sjFlashEdit;
{create the in-place editor:}
CreateFlashEditor;
TheSeries := FLegend.GetHit(Selection.Left, Selection.Top, TheRect);
FFlashEdit.Height := FLegend.FontHeight + 2;
FFlashEdit.Width := FLegend.ItemWidth;
FFlashEdit.Left := TheRect.Left;
FFlashEdit.Top := TheRect.Top - 1;
FFlashEdit.Tag := Ord(soLegend);
{we use HelpContext because MouseDown is called after DblClick, which nukes TheSeries:}
FFlashEdit.HelpContext := TheSeries;
FFlashEdit.Font.Assign(FLegend.Font);
FFlashEdit.Text := TSeries(FSeriesList[TheSeries]).Name;
FFlashEdit.Visible := TRUE;
FFlashEdit.SetFocus;
end; {Legend}
end; {editable}
inherited DblClick;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CreateFlashEditor
Description: Creates the FlashEdit in-place editor
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: caption management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.CreateFlashEditor;
{create the in-place editor:}
begin
if (FFlashEdit = nil) then
begin
FFlashEdit := TEdit.Create(nil);
FFlashEdit.Parent := Self;
FFlashEdit.OnKeyDown := FlashEditKeyDown;
FFlashEdit.OnExit := FlashEditExit;
FFlashEdit.Hint := sFlashEditHint;
FFlashEdit.ShowHint := TRUE;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.FlashEditKeyDown
Description: KeyDown event handler of FFlashEdit in-place editor
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Cancel the FFlashEditor if Esc pressed, or save the changed Title.
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.FlashEditKeyDown(
Sender: TObject;
var Key: Word;
Shift: TShiftState);
begin
if (Key = VK_ESCAPE) then //4096
begin
FFlashEdit.Visible := FALSE;
Key := 0;
end;
if (Key = VK_RETURN) then //4100
begin
{this will throw an exception if Tag is not a valid TObjectType:}
case TObjectType(FFlashEdit.Tag) of
soTitle: FTitle.Caption := FFlashEdit.Text;
{soXAxis, soYAxis}
soXAxisTitle: FXAxis.Title.Caption := FFlashEdit.Text;
soYAxisTitle: TTitle(pClickedObject).Caption := FFlashEdit.Text;
{soXAxisLabel, soYAxisLabel, soYAxis2Label,
soLeftBorder, soTopBorder, soRightBorder, soBottomBorder}
{we use HelpContext because MouseDown is called after DblClick, which nukes TheSeries:}
soLegend: TSeries(FSeriesList[FFlashEdit.HelpContext]).Name := FFlashEdit.Text;
soNote: TNote(pClickedObject).Caption := FFlashEdit.Text;
end;
FFlashEdit.Visible := FALSE;
Key := 0;
DoStyleChange(Self);
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.FlashEditExit
Description: Exit event handler of FFlashEdit in-place editor
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: hide the FFlashEditor
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.FlashEditExit(
Sender: TObject);
begin
FFlashEdit.Visible := FALSE;
FFlashEdit.Text := '';
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.KeyDown
Description: KeyDown event handler
Author: Mat Ballard
Date created: 04/22/2001
Date modified: 04/22/2001 by Mat Ballard
Purpose: This processes certain key strokes.
Known Issues: Does not work: a CustomPanel does not seem to be able to gain focus.
------------------------------------------------------------------------------}
{procedure TCustomPlot.KeyDown(var Key: Word; Shift: TShiftState);
var
OldVar, Gap: Single;
begin
case Key of
VK_LEFT:
begin
if (ssCtrl in Shift) then
begin
if (FXAxis.Min > FSeriesList.Xmin) then
begin
OldVar := FXAxis.Min;
Gap := FXAxis.Max - FXAxis.Min;
FXAxis.Min := FXAxis.Min - Gap;
FXAxis.Max := FXAxis.Max - Gap;
end;
end;
end;
VK_RIGHT:
begin
if (ssCtrl in Shift) then
begin
if (FXAxis.Max < FSeriesList.Xmax) then
begin
OldVar := FXAxis.Max;
Gap := FXAxis.Max - FXAxis.Min;
FXAxis.Max := FXAxis.Max + Gap;
FXAxis.Min := FXAxis.Min + Gap;
end;
end;
end;
end;
inherited KeyDown(Key, Shift);
end;}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.MouseDown
Description: MouseDown event handler
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 08/31/2000 by Mat Ballard
Purpose: The start of all mouse routines
Known Issues: MouseDown gets called AFTER DblClick !
Changes: GetTheClickedObject now moved to within the 'if (FScreenJob = sjNone) then'
------------------------------------------------------------------------------}
procedure TCustomPlot.MouseDown(
Button: TMouseButton;
Shift: TShiftState;
X,
Y: Integer);
begin
{Nuke any Caption:}
FInstructions.Clear;
{record the beginning:}
MouseStart.x := X;
MouseStart.y := Y;
{set the moving object co-ordinates:}
Selection.MoveTo(X, Y);
Selection.Height := 1;
Selection.Width := 1;
{ if (FScreenJob <> sjFlashEdit) then
FFlashEdit.Visible := FALSE;}
{if no ScreenJob has been set yet, it could be several things:}
if (FScreenJob = sjNone) then
begin
{no job yet}
{what got clicked ?}
GetTheClickedObject(X, Y);
if (Button = mbLeft) then
begin
{left click:}
if (ssShift in Shift) then
begin
{We want to zoom in:}
FScreenJob := sjZoomIn;
end
else if ((ClickedObjectType <> soNone) and
(FMovable)) then
begin
{left clicks can lead to click and drag:}
MouseTimer.Enabled := TRUE;
end;
end; {left button}
{NOTE: if it is the right button, then the popup menu will be displayed
at the end of the MouseUp}
end; {if sjNone}
case FScreenJob of
{sjNone: already done}
{sjDrag: set by MouseTimeOut
sjRightDrag: set in MouseMove}
sjHide: HideClick(Self);
sjZoomIn:
begin
Screen.Cursor := crSize;
OutlineTheClickedObject;
end;
{sjEditAxis:}
{sjTouchNote:}
sjMoveNotePointer: ZeroScreenStuff;
{sjEditFont:
sjEditPoint:
sjEditSeries:
sjCopySeries: ;
sjDisplace: ;
sjCloneSeries: ;
sjDeleteSeries: all done by popupmenu or option}
sjPosition: PositionClick(Self);
sjNearestPoint: NearestPointClick(Self);
sjLinearize,
sjZero,
sjAverage,
sjContractSeries,
sjContractAllSeries,
{sjSplineSeries: ;
sjHighs,
sjLows,
sjMovingAverage,
sjSmoothSeries: ;
sjSortSeries: ;
sjDifferentiate: ;
sjIntegrate: all done by popupmenu or option}
sjIntegral,
sjLineOfBestFit,
sjDualLineBestFit1,
sjDualLineBestFit2,
sjSelection,
sjDualSelection1,
sjDualSelection2:
begin
Screen.Cursor := crSize;
Selection.Outline(Canvas);
end;
end;
inherited MouseDown(Button, Shift, X, Y);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.MouseMove
Description: MouseMove event handler
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Moves the dashed outline around the screen; how it moves depends on the object
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.MouseMove(
Shift: TShiftState;
X,
Y: Integer);
var
Gap,
NewLeft,
NewTop,
dx, dy: Integer;
Ptr: Pointer;
begin
MouseTimer.Enabled := FALSE;
if (FScreenJob = sjMoveNotePointer) then
TNote(pClickedObject).TracePointerTo(Canvas, X, Y);
if (ssLeft in Shift) then
begin
case FScreenJob of
{sjNone:}
sjDrag:
case ClickedObjectType of
soTitle:
begin
if (X < (FBorder.Left + FBorder.MidX) div 2) then
NewLeft := FBorder.Left
else if (X > (FBorder.Right + FBorder.MidX) div 2) then
NewLeft := FBorder.Right - Selection.Width
else
NewLeft := FBorder.MidX - Selection.Width div 2;
if (Y > FXAxis.MidY) then
NewTop := Height - BevelGap - FTitle.Height
else
NewTop := BevelGap;
MoveTheClickedObjectTo(NewLeft, NewTop);
end;
soXAxis, soTopBorder, soBottomBorder:
begin
MoveTheClickedObjectTo(
TRectangle(pClickedObject).Left,
Y - ClickedObjectOffset.y);
end;
soYAxis, soLeftBorder, soRightBorder:
begin
MoveTheClickedObjectTo(
X - ClickedObjectOffset.x,
TRectangle(pClickedObject).Top);
end;
soZAxis:
begin
dx := X - MouseStart.x;
dy := Y - MouseStart.y;
if (Abs(dx) >= Abs(dy)) then
MoveTheClickedObjectTo(
X - ClickedObjectOffset.x,
TRectangle(pClickedObject).Top)
else
MoveTheClickedObjectTo(
TRectangle(pClickedObject).Left,
Y - ClickedObjectOffset.y);
end;
soXAxisTitle:
begin
if (X < (FBorder.Left + FBorder.MidX) div 2) then
NewLeft := FBorder.Left
else if (X > (FBorder.Right + FBorder.MidX) div 2) then
NewLeft := FBorder.Right - Selection.Width
else
NewLeft := FBorder.MidX - Selection.Width div 2;
Gap := Abs(FXAxis.Title.MidY - FXAxis.MidY);
if (Y > FXAxis.MidY) then
NewTop := FXAxis.MidY + Gap - FXAxis.Title.Height div 2
else
NewTop := FXAxis.MidY - Gap - FXAxis.Title.Height div 2;
MoveTheClickedObjectTo(NewLeft, NewTop);
end;
soYAxisTitle:
begin
{Which Y Axis owns this Title ?}
Ptr := TRectangle(pClickedObject).Owner;
Gap := Abs(TRectangle(pClickedObject).MidX - TAxis(Ptr).MidX);
if (X < TAxis(Ptr).MidX) then
NewLeft := TAxis(Ptr).MidX - Gap - TRectangle(pClickedObject).Width div 2
else
NewLeft := TAxis(Ptr).MidX + Gap - TRectangle(pClickedObject).Width div 2;
if (Y < (FBorder.Top + FBorder.MidY) div 2) then
NewTop := FBorder.Top
else if (Y > (FBorder.Bottom + FBorder.MidY) div 2) then
NewTop := FBorder.Bottom - Selection.Height
else
NewTop := FBorder.MidY - Selection.Height div 2;
MoveTheClickedObjectTo(NewLeft, NewTop);
end;
soXAxisLabel:
begin
Gap := Abs(FXAxis.Labels.MidY - FXAxis.MidY);
if (Y < FXAxis.MidY) then
MoveTheClickedObjectTo(Selection.Left,
FXAxis.MidY - Gap - FXAxis.Labels.Height div 2)
else
MoveTheClickedObjectTo(Selection.Left,
FXAxis.MidY + Gap - FXAxis.Labels.Height div 2);
end;
soYAxisLabel:
begin
{Which Y Axis owns this Title ?}
Ptr := TRectangle(pClickedObject).Owner;
Gap := Abs(TRectangle(pClickedObject).MidX - TAxis(Ptr).MidX);
if (X < TAxis(Ptr).MidX) then
MoveTheClickedObjectTo(
TAxis(Ptr).MidX - Gap - TRectangle(pClickedObject).Width div 2,
Selection.Top)
else
MoveTheClickedObjectTo(
TAxis(Ptr).MidX + Gap - TRectangle(pClickedObject).Width div 2,
Selection.Top);
end;
soLegend, soResult, soNote:
begin {both of these can move freely:}
MoveTheClickedObjectTo(
X - ClickedObjectOffset.x,
Y - ClickedObjectOffset.y);
end;
soSeries:
begin
pSeries.MoveBy(Canvas, FPlotType, X-Selection.Left, Y-Selection.Top, FOutlineWidth);
Selection.MoveTo(X, Y);
end;
end; {end case sjDrag}
{sjHide:}
sjZoomIn:
StretchTheClickedObjectTo(X, Y);
{sjEditAxis: ;}
{sjEditFont: ;
sjEditPoint: ;
sjEditSeries: ;
sjCopySeries: ;
sjDisplace: ;
sjCloneSeries: ;
sjDeleteSeries: all done by popupmenu or option}
{sjPosition: already done, or by popupmenu}
{sjNearestPoint: already done, or by popupmenu}
sjLinearize,
sjZero,
sjAverage,
sjContractSeries,
sjContractAllSeries,
{sjSplineAxis: ;
sjHighs,
sjLows,
sjMovingAverage,
sjSmoothSeries: ;
sjSortSeries: ;
sjDifferentiate: ;
sjIntegrate: all done by popupmenu or option}
sjIntegral,
sjLineOfBestFit,
sjDualLineBestFit1,
sjDualLineBestFit2,
sjSelection,
sjDualSelection1,
sjDualSelection2:
StretchTheClickedObjectTo(X, Y);
end;
end {if (ssLeft in Shift)}
else if (ssRight in Shift) then
begin {aha ! a right click and drag operation !}
FScreenJob := sjRightDrag;
StretchTheClickedObjectTo(X, Y);
end;
inherited MouseMove(Shift, X, Y);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.MouseUp
Description: MouseUp event handler
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 05/30/2001 by Mat Ballard
Purpose: Reacts to the user finishing an action with the mouse
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.MouseUp(
Button: TMouseButton;
Shift: TShiftState;
X,
Y: Integer);
var
Point: TPoint;
begin
MouseTimer.Enabled := FALSE;
if (Button = mbLeft) then
begin
case FScreenJob of
{sjNone:}
sjDrag:
begin
OutlineTheClickedObject;
if (SecondClickedObjectType = soNone) then
begin
MoveTheClickedObjectClick(Self);
end
else
begin
Point.x := X;
Point.y := Y;
Point := ClientToScreen(Point);
if (pClickedObject <> nil) then
WhichPopUpItems[0].Caption := sMoveThe +
TRectangle(pClickedObject).Name;
if (pSecondClickedObject <> nil) then
WhichPopUpItems[1].Caption := sMoveThe +
TRectangle(pSecondClickedObject).Name;
WhichPopUpMenu.Popup(Point.x, Point.y);
end;
end;
{sjHide:}
sjZoomIn:
begin
OutlineTheClickedObject;
SwapEnds;
ZoomInClick(Self);
end;
{sjEditAxis: ;}
sjMoveNotePointer: ZeroScreenStuff;
{sjEditFont: ;
sjEditPoint: ;
sjEditSeries: ;
sjCopySeries: ;
sjDisplace: ;
sjCloneSeries: ;
sjDeleteSeries: ;}
{sjPosition: already done, or by popupmenu}
{sjNearestPoint: already done, or by popupmenu}
sjAverage:
begin
Selection.Outline(Canvas);
SwapEnds;
AverageClick(Self);
end;
sjLinearize:
begin
Selection.Outline(Canvas);
SwapEnds;
LinearizeClick(Self);
end;
sjZero:
begin
Selection.Outline(Canvas);
SwapEnds;
ZeroClick(Self);
end;
sjContractSeries:
begin
Selection.Outline(Canvas);
SwapEnds;
ContractSeriesClick(Self);
end;
sjContractAllSeries:
begin
Selection.Outline(Canvas);
SwapEnds;
ContractAllSeriesClick(Self);
end;
{sjSplineSeries: ;
sjHighs,
sjLows,
sjMovingAverage,
sjSmoothSeries: ;
sjSortSeries: ;
sjDifferentiate: ;
sjIntegrate: ;}
sjIntegral:
begin
Selection.Outline(Canvas);
SwapEnds;
IntegralClick(Self);
end;
sjLineOfBestFit:
begin
Selection.Outline(Canvas);
SwapEnds;
LineBestFitClick(Self);
end;
sjDualLineBestFit1:
begin
Selection.Outline(Canvas);
SwapEnds;
TwoRegionLineBestFitClick(Self);
end;
sjDualLineBestFit2:
begin
Selection.Outline(Canvas);
SwapEnds;
LineBestFitClick(Self);
end;
sjSelection:
begin
Selection.Outline(Canvas);
SwapEnds;
Selection.AssignToRect(Sel1);
DoSelection(Sel1);
end;
sjDualSelection1:
begin
Selection.Outline(Canvas);
SwapEnds;
Selection.AssignToRect(Sel1);
ScreenJob := sjDualLineBestFit2;
FInstructions.Clear;
FInstructions.Add(sDualInstruction);
DoStyleChange(Self);
end;
sjDualSelection2:
begin
Selection.Outline(Canvas);
SwapEnds;
Selection.AssignToRect(Sel2);
DoDualSelection(Sel1, Sel2);
end;
end; {end case}
DoStyleChange(Self);
end {end Left Button}
else
begin {Right Button}
OutlineTheClickedObject;
{$IFNDEF DELPHI1}
{what does that do to menu visibility ?}
DetermineMenuVisibility;
{$ENDIF}
{we no longer let the ancestor run the popup:
see note above on 'property PopupMenu':}
Point.x := X;
Point.y := Y;
Point := ClientToScreen(Point);
if (FScreenJob = sjRightDrag) then
FDragPopUpMenu.Popup(Point.x, Point.y)
else
FPlotPopUpMenu.Popup(Point.x, Point.y);
end; {end Right Button}
{inherited runs the popup if neccessary:}
inherited MouseUp(Button, Shift, X, Y);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DoSelection
Description: Fires the Selection event
Author: Mat Ballard
Date created: 09/07/2000
Date modified: 09/07/2000 by Mat Ballard
Purpose:
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DoSelection(Sel1: TRect);
begin
if Assigned(FOnSelection) then
OnSelection(Self, Sel1);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DoDualSelection
Description: Fires the DualSelection event
Author: Mat Ballard
Date created: 09/07/2000
Date modified: 09/07/2000 by Mat Ballard
Purpose:
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DoDualSelection(Sel1, Sel2: TRect);
begin
if Assigned(FOnDualSelection) then
OnDualSelection(Self, Sel1, Sel2);
end;
{$IFNDEF DELPHI1}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DetermineMenuVisibility
Description: Sets the visibility of Axis-related menus
Author: Mat Ballard
Date created: 04/17/2000
Date modified: 04/17/2000 by Mat Ballard
Purpose: menu management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DetermineMenuVisibility;
var
i: Integer;
SeriesVisibility: Boolean;
begin
{$IFDEF SHOWALLMENUS}
exit;
{$ENDIF}
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuPaste)].Enabled := CanPaste;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuHide)].Visible := TRUE;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditAxis)].Visible := FALSE;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditFont)].Visible := FALSE;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuMoveNotePointer)].Visible := FALSE;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteNote)].Visible := FALSE;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuLegend)].Visible := FALSE;
SeriesVisibility := FALSE;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuClearOverlays)].Visible :=
(FirstOverlay >= 0);
case ClickedObjectType of
soTitle,
soXAxisTitle, soYAxisTitle,
soXAxisLabel, soYAxisLabel,
soResult:
begin
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuHide)].Visible := TRUE;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditFont)].Visible := TRUE;
end;
soNote:
begin
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuHide)].Visible := TRUE;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditFont)].Visible := TRUE;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuMoveNotePointer)].Visible :=
(NoteCount > 0);
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteNote)].Visible :=
(NoteCount > 0);
end;
soLegend:
begin
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuHide)].Visible := TRUE;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditFont)].Visible := TRUE;
if (FSeriesList.Count > 1) then
begin
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuLegend)].Visible := TRUE;
end;
end;
soXAxis, soYAxis, soZAxis:
begin
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuHide)].Visible := TRUE;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditAxis)].Visible := TRUE;
end;
soSeries:
begin
//pSeries.OutlineSeries(FOutlineWidth, Canvas);
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuHide)].Visible := TRUE;
SeriesVisibility := TRUE;
end;
else
{soLeftBorder, soTopBorder, soRightBorder, soBottomBorder:}
begin
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuHide)].Visible := FALSE;
end;
end;
SetSeriesVisibility(SeriesVisibility);
for i := 0 to Ord(High(TMainMenus)) do
FPlotPopUpMenu.Items[i].Visible :=
FPlotPopUpMenu.Items[i].Visible and
(TMainMenus(i) in FPopupOptions.Menu);
for i := 0 to Ord(High(TFileMenus)) do
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[i].Visible :=
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[i].Visible and
(TFileMenus(i) in FPopupOptions.File_);
for i := 0 to Ord(High(TEditMenus)) do
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[i].Visible :=
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[i].Visible and
(TEditMenus(i) in FPopupOptions.Edit);
for i := 0 to Ord(High(TViewMenus)) do
FPlotPopUpMenu.Items[Ord(mnuView)].Items[i].Visible :=
FPlotPopUpMenu.Items[Ord(mnuView)].Items[i].Visible and
(TViewMenus(i) in FPopupOptions.View);
for i := 0 to Ord(High(TCalcMenus)) do
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[i].Visible :=
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[i].Visible and
(TCalcMenus(i) in FPopupOptions.Calc);
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDisplaceDiv)].Visible :=
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDisplace)].Visible;
{NewSeries means that this divider is now always visible:
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditSeriesDiv)].Visible :=
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditSeries)].Visible;}
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalcAverageDiv)].Visible :=
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalcAverage)].Visible;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuLineOfBestFitDiv)].Visible :=
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuLineOfBestFit)].Visible;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetSeriesVisibility
Description: Sets the visibility of Axis-related menus
Author: Mat Ballard
Date created: 04/17/2000
Date modified: 04/17/2000 by Mat Ballard
Purpose: menu management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetSeriesVisibility(Value: Boolean);
begin
{Can't do anything to Series if there is no data:}
Value := Value and (FSeriesList.TotalNoPts > 0);
{The following are independent of whether or not a Series has been selected:}
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSave)].Visible :=
(FSeriesList.TotalNoPts > 0) and FSeriesList.DataChanged;
FPlotPopUpMenu.Items[Ord(mnuFile)].Items[Ord(mnuSaveAs)].Visible :=
(FSeriesList.TotalNoPts > 0);
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteY2Axis)].Visible :=
(FAxisList.Count > 2);
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuNearestPoint)].Visible :=
(FSeriesList.TotalNoPts > 0);
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCompressAllSeries)].Visible :=
(FSeriesList.TotalNoPts > 20);
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuContractAllSeries)].Visible :=
(FSeriesList.TotalNoPts > 20);
{$IFDEF FUNCTIONS}
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuFunction)].Visible := (FSeriesList.Count > 0);
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuFunctionDiv)].Visible := (FSeriesList.Count > 0);
{$ENDIF}
{The following DO DEPEND on whether or not a Series has been selected:}
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopyHTML)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopySeries)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDisplace)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuResetDisplacement)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCloneSeries)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditPoint)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditData)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditSeries)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteSeries)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuLinearize)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuEdit)].Items[Ord(mnuZero)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalcAverage)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCompressSeries)].Visible :=
Value and
(FSeriesList.TotalNoPts > 20) and
(pSeries <> nil) and
(not ((pSeries.ExternalXSeries) or (pSeries.XDataRefCount > 0)));
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuContractSeries)].Visible :=
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCompressSeries)].Visible;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCubicSpline)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuHighs)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuMovingAverage)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuSmoothSeries)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuSortSeries)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalculusDiv)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuDifferentiate)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuIntegrate)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuIntegral)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuLineOfBestFit)].Visible := Value;
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuTwoRegionLineOfBestFit)].Visible := Value;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DetermineMenuEnabledness
Description: Sets the Enabledness of Axis-related menus
Author: Mat Ballard
Date created: 04/17/2000
Date modified: 04/17/2000 by Mat Ballard
Purpose: menu management
Known Issues: called from TPlotMenu.HandleClunk
Because we have added a "Reopen" sub-submenu, we have to
kludge and add "1" to the index of all mnuFile menuitems.
------------------------------------------------------------------------------}
procedure TCustomPlot.DetermineMenuEnabledness(TheMenu: TMenu);
begin
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuPaste)].Enabled :=
CanPaste;
SetSeriesEnabledness(TheMenu);
{Note Reopen kludge: "1+"}
TheMenu.Items[Ord(mnuFile)].Items[1+Ord(mnuClearOverlays)].Enabled :=
(FirstOverlay >= 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteY2Axis)].Enabled :=
(FAxisList.Count > 2);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuMoveNotePointer)].Enabled :=
(NoteCount > 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteNote)].Enabled :=
(NoteCount > 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditFont)].Enabled := TRUE;
TheMenu.Items[Ord(mnuView)].Items[Ord(mnuHide)].Enabled := TRUE;
TheMenu.Items[Ord(mnuView)].Items[Ord(mnuLegend)].Enabled :=
(FSeriesList.Count > 1);
TheMenu.Items[Ord(mnuView)].Items[Ord(mnuNormal)].Enabled :=
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuNormal)].Enabled;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetSeriesEnabledness
Description: Sets the Enabledness of Axis-related menus
Author: Mat Ballard
Date created: 04/17/2000
Date modified: 04/17/2000 by Mat Ballard
Purpose: menu management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetSeriesEnabledness(TheMenu: TMenu);
begin
{Note Reopen kludge: "1+"}
TheMenu.Items[Ord(mnuFile)].Items[1+Ord(mnuSave)].Enabled :=
(FSeriesList.TotalNoPts > 0) and FSeriesList.DataChanged;
TheMenu.Items[Ord(mnuFile)].Items[1+Ord(mnuSaveAs)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuNearestPoint)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCompressAllSeries)].Enabled :=
(FSeriesList.TotalNoPts > 20);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuContractAllSeries)].Enabled :=
(FSeriesList.TotalNoPts > 20);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopyHTML)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCopySeries)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDisplaceDiv)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDisplace)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuResetDisplacement)].Enabled :=
(FSeriesList.TotalNoPts > 0);
{NewSeries means that this divider is now always visible:
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditSeriesDiv)].Enabled :=
(FSeriesList.TotalNoPts > 0);}
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuCloneSeries)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditPoint)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditData)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuEditSeries)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuDeleteSeries)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuLinearize)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuEdit)].Items[Ord(mnuZero)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalcAverageDiv)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalcAverage)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCompressSeries)].Enabled :=
(FSeriesList.TotalNoPts > 20);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuContractSeries)].Enabled :=
(FSeriesList.TotalNoPts > 20);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCubicSpline)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuHighs)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuMovingAverage)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuSmoothSeries)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuSortSeries)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuCalculusDiv)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuDifferentiate)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuIntegrate)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuIntegral)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuLineOfBestFitDiv)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuLineOfBestFit)].Enabled :=
(FSeriesList.TotalNoPts > 0);
TheMenu.Items[Ord(mnuCalc)].Items[Ord(mnuTwoRegionLineOfBestFit)].Enabled :=
(FSeriesList.TotalNoPts > 0);
{$IFDEF FUNCTIONS}
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuFunctionDiv)].Visible := (FSeriesList.Count > 0);
FPlotPopUpMenu.Items[Ord(mnuCalc)].Items[Ord(mnuFunction)].Visible := (FSeriesList.Count > 0);
{$ENDIF}
end;
{$ENDIF}
{------------------------------------------------------------------------------
Procedure: SwapEnds
Description: Swaps the selection's Left-Right and Top-Bottom if needed
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: manageing region selections
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SwapEnds;
var
iX: Integer;
begin
{swap Left and Right:}
if (Selection.Left > Selection.Right) then
begin
iX := Selection.Left;
Selection.Left := Selection.Right;
Selection.Right := iX;
end;
{swap Top and Bottom:}
if (Selection.Top > Selection.Bottom) then
begin
iX := Selection.Top;
Selection.Top := Selection.Bottom;
Selection.Bottom := iX;
end;
end;
{------------------------------------------------------------------------------
Procedure: SetResult
Description: Performs calculations on Screen Data
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Finishes off Line of Best Fit determinations
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetResult(
Slope,
Intercept,
Rsq: Single);
begin
if (pSeries.XAxis.LogScale) then
FResult.Caption := 'Ln(' + pSeries.XAxis.Title.Caption + ') = '
else
FResult.Caption := pSeries.XAxis.Title.Caption + ' = ';
FResult.Caption := FResult.Caption + FloatToStrF(Intercept, ffGeneral, 5, 3) + ' + ';
if (pSeries.XAxis.LogScale) then
FResult.Caption := FResult.Caption + FloatToStrF(Slope, ffGeneral, 5, 3) +
' ╫ ' + sLn + '(' + pSeries.YAxis.Title.Caption + '), ' + sRSquare + ' = '
else
FResult.Caption := FResult.Caption + FloatToStrF(Slope, ffGeneral, 5, 3) +
' ╫ ' + pSeries.YAxis.Title.Caption + ', ' + sRSquare + ' = ';
FResult.Caption := FResult.Caption + FloatToStrF(Rsq, ffGeneral, 5, 3);
ClipBoard.AsText := FResult.Caption;
FResult.Font.Color := pSeries.Pen.Color;
FResult.MoveTo(Selection.Left, Selection.Top);
FResult.Visible := TRUE;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.MouseTimeOut
Description: responds to the mouse button being held down
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Frees the timer, identifies the clicked object, outlines it, and prepares to move it
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.MouseTimeOut(
Sender: TObject);
{If this is fired, then the user has held the mouse still for one second
on a screen object: this is a cue for a move.}
begin
MouseTimer.Enabled := FALSE;
if (ClickedObjectType = soNone) then exit;
if (FScreenJob = sjTouchNotePointer) then
begin
{$IFDEF COMPILER3_UP}
Screen.Cursor := crScope;
{$ENDIF}
FScreenJob := sjMoveNotePointer;
end
else
begin
FScreenJob := sjDrag;
{$IFDEF COMPILER3_UP}
Screen.Cursor := crHandPoint;
{$ENDIF}
if (ClickedObjectType = soSeries) then
begin
pSeries.Outline(Self.Canvas, FPlotType, FOutlineWidth);
end
else
begin
{This is fascinating: the following call attempts to assign all the TAxis
properties of pClickedObject to Selection - which of course pukes:
Selection.Assign(TRectangle(pClickedObject));
So we have to assign position manually:}
if (pClickedObject <> nil) then
begin
if (pClickedObject = FZAxis) then
Selection.SetNewGeometry(Point(
FZAxis.Left,
FZAxis.Top),
FZAxis.Angle,
FZAxis.Length,
FZAxis.Width div 4)
else
Selection.SetNewGeometry(Point(
TRectangle(pClickedObject).Left,
TRectangle(pClickedObject).Top + TRectangle(pClickedObject).Height div 2),
90,
TRectangle(pClickedObject).Width,
TRectangle(pClickedObject).Height);
end;
OutlineTheClickedObject;
end;
end; {sjTouchNote}
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.GetTheClickedObject
Description: identifies the object(s) that was clicked on
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets ClickedObjectType and SecondClickedObjectType, and TheSeries if it was a Axis.
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.GetTheClickedObject(
X,
Y: Integer);
var
i: Integer;
MinDistance: Single;
ANote: TNote;
TheRect: TRect;
begin
pClickedObject := nil;
pSecondClickedObject := nil;
ClickedObjectType := soNone;
{page control while zoomed in ?}
if (FPageButtons[0] <> nil) then
begin
if ((X > Self.Width - 3*FPageButtons[0].Width) and
(Y > Self.Height - 2*FPageButtons[0].Height)) then
begin
{ x2x
031 is the layout:}
if (Y > Self.Height - FPageButtons[0].Height) then
begin
if (X < Self.Width - 2*FPageButtons[0].Width) then
PageButtonClick(0)
else if (X < Self.Width - FPageButtons[0].Width) then
PageButtonClick(3)
else
PageButtonClick(1);
end
else
begin
if ((X >= Self.Width - 2*FPageButtons[0].Width) and
(X < Self.Width - FPageButtons[0].Width)) then
PageButtonClick(2);
end;
end;
end;
for i := 1 to ScreenObjectList.Count-1 do
begin
{identify the clicked-on object:}
if (ScreenObjectList.Items[i] <> nil) then
begin
if (TRectangle(ScreenObjectList.Items[i]).ClickedOn(X, Y)) then
begin
if (pClickedObject = nil) then
begin
pClickedObject := ScreenObjectList.Items[i];
ClickedObjectType := TObjectType(TRectangle(pClickedObject).Tag);
ClickedObjectOffset.x := X - TRectangle(pClickedObject).Left;
ClickedObjectOffset.y := Y - TRectangle(pClickedObject).Top;
if ((ClickedObjectType = soXAxis) or
(ClickedObjectType = soYAxis) or
(ClickedObjectType = soZAxis)) then
begin
pAxis := TAxis(pClickedObject);
TheAxis := FAxisList.IndexOf(pAxis);
end;
end
else
begin
{there are two objects under the mouse: usually an axis and a border:}
pSecondClickedObject := ScreenObjectList.Items[i];
SecondClickedObjectType := TObjectType(TRectangle(pSecondClickedObject).Tag);
exit;
end;
end;
end; {clicked on object i}
end; {for}
if (ClickedObjectType = soLegend) then
begin
FLegend.GetHit(X, Y, TheRect);
end;
if (ClickedObjectType = soNone) then
begin
{was it a note end ?}
for i := NoBasicScreenObjects to ScreenObjectList.Count-1 do
begin
if (TObject(ScreenObjectList.Items[i]) is TNote) then
begin
ANote := TNote(ScreenObjectList.Items[i]);
if ((Abs(ANote.ArrowLeft - X) < FOutlineWidth) or
(Abs(ANote.ArrowTop - Y) < FOutlineWidth)) then
begin
ClickedObjectType := soNote;
pClickedObject := ANote;
FScreenJob := sjTouchNotePointer;
end;
end;
end;
end;
{If nothing yet clicked on ...}
if (ClickedObjectType = soNone) then
begin
if ((FPlotType = ptXY) or
(FPlotType = ptError) or
(FPlotType = ptMultiple) or
(FPlotType = ptBubble) or
(FPlotType = ptColumn) or
(FPlotType = ptStack) or
(FPlotType = ptNormStack) or
(FPlotType = ptPie)) then
begin
{was it a Series ?}
ThePointNumber := FSeriesList.GetNearestPoint(
FPlotType,
FColumnGap,
X, Y, //Selection.Left, Selection.Top,
TheSeries,
MinDistance,
pSeries);
{give it a wide hit range:}
if (MinDistance < (FOutlineWidth)) then
begin
ClickedObjectType := soSeries;
if (FPlotType <= ptBubble) then
pSeries.GenerateXYOutline;
end;
end; {FPlotType}
end; {ClickedObjectType = soNone}
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ProcessClickedObject
Description: Adjusts the geometry of a moved (clicked and dragged) object
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets appropriate property(ies) of the object that has been manipulated on screen
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ProcessClickedObject(
pObject: Pointer;
TheObjectType: TObjectType);
var
NewMousePoint: TPoint;
begin
case TheObjectType of
soTitle:
begin
if (Selection.Left = FBorder.Left) then
FTitle.Alignment := taLeftJustify
else if (Selection.Right = FBorder.Right) then
FTitle.Alignment := taRightJustify
else
FTitle.Alignment := taCenter;
if (Selection.Top < FBorder.MidY) then
FTitle.Orientation := orLeft
else
FTitle.Orientation := orRight;
end;
soLegend:
begin
FLegend.MoveTo(Selection.Left, Selection.Top);
end;
soResult:
begin
FResult.MoveTo(Selection.Left, Selection.Top);
end;
soXAxis:
begin
FXAxis.Intercept := FYAxis.YofF(Selection.MidY);
end;
soZAxis:
begin
FZAxis.Intercept := FXAxis.XofF(Selection.Origin.x);
FZAxis.ZInterceptY := FYAxis.YofF(Selection.Origin.y);
end;
soXAxisTitle:
begin
if (Selection.Left = FBorder.Left) then
FXAxis.Title.Alignment := taLeftJustify
else if (Selection.Right = FBorder.Right) then
FXAxis.Title.Alignment := taRightJustify
else
FXAxis.Title.Alignment := taCenter;
if (Selection.Top < FXAxis.MidY) then
FXAxis.Title.Orientation := orLeft
else
FXAxis.Title.Orientation := orRight;
end;
soXAxisLabel:
begin
if (Selection.Top < FXAxis.MidY) then
FXAxis.TickDirection := orLeft
else
FXAxis.TickDirection := orRight;
end;
soYAxis:
begin
TAxis(pObject).Intercept := FXAxis.XofF(Selection.MidX);
Resize;
end;
soYAxisTitle:
begin
if (Selection.Left < TAxis(TTitle(pObject).Owner).MidX) then
TTitle(pObject).Orientation := orLeft
else
TTitle(pObject).Orientation := orRight;
if (Selection.Top = FBorder.Top) then
TTitle(pObject).Alignment := taRightJustify
else if (Selection.Bottom = FBorder.Bottom) then
TTitle(pObject).Alignment := taLeftJustify
else
TTitle(pObject).Alignment := taCenter;
end;
soYAxisLabel:
begin
if (Selection.Left < TAxis(TAxisLabel(pObject).Owner).MidX) then
TAxis(TAxisLabel(pObject).Owner).TickDirection := orLeft
else
TAxis(TAxisLabel(pObject).Owner).TickDirection := orRight;
end;
soLeftBorder: FBorder.Left := Selection.MidX;
soRightBorder: FBorder.Right := Selection.MidX;
soTopBorder: FBorder.Top := Selection.MidY;
soBottomBorder: FBorder.Bottom := Selection.MidY;
soNote:
begin
TNote(pObject).MoveTo(Selection.Left, Selection.Top);
{now lets move the note pointer:}
{$IFDEF COMPILER3_UP}
Screen.Cursor := crScope;
{$ENDIF}
FScreenJob := sjMoveNotePointer;
NewMousePoint.x := TNote(pObject).ArrowLeft;
NewMousePoint.Y := TNote(pObject).ArrowTop;
ClientToScreen(NewMousePoint);
{$IFDEF BCB}
SetCursorPos(NewMousePoint.x, NewMousePoint.y);
{$ELSE} {BCB doesn't like:}
Mouse.CursorPos := ClientToScreen(NewMousePoint);
{$ENDIF}
exit;
end;
soSeries: { already moved by direct change of DeltaX and DeltaY properties}
begin
end;
end; {case TheObjectType}
ZeroScreenStuff;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.OutlineTheClickedObject
Description: Outlines The Clicked Object
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: gives the user a guide to what they are manipulating with the mouse
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.OutlineTheClickedObject;
begin
if (ClickedObjectType = soSeries) then
pSeries.Outline(Self.Canvas, FPlotType, FOutlineWidth)
else
Selection.Outline(Self.Canvas);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.MoveTheClickedObjectTo
Description: This moves the clicked object outline TO (X, Y)
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: gives the user a guide to what they are moving with the mouse
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.MoveTheClickedObjectTo(
X,
Y: Integer);
begin
if ((Selection.Left = X) and (Selection.Top = Y)) then exit;
{erase the old outline:}
OutlineTheClickedObject;
{re-initialize the Selection:}
Selection.MoveTo(X, Y);
{create the new outline:}
OutlineTheClickedObject;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.StretchTheClickedObjectTo
Description: Stretch The Clicked Object To
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: gives the user a guide to what they are selecting with the mouse
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.StretchTheClickedObjectTo(
X,
Y: Integer);
{This moves the far (right, bottom) point of the Stretched object outline TO (X, Y).}
begin
if ((Selection.Right = X) and (Selection.Bottom = Y)) then
exit;
{erase the old outline:}
//OutlineTheSelection;
Selection.Outline(Canvas);
{re-initialize the Selection:}
Selection.Right := X;
Selection.Bottom := Y;
{create the new outline:}
//OutlineTheSelection;
Selection.Outline(Canvas);
end;
{------------------------------------------------------------------------------
Procedure: MoveTheClickedObjectClick
Description: deals with the end of a screen operation at MouseUp
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Processes the first Clicked Object
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.MoveTheClickedObjectClick(
Sender: TObject);
begin
ProcessClickedObject(pClickedObject, ClickedObjectType);
end;
{------------------------------------------------------------------------------
Procedure: MoveSecondClickedObjectClick
Description: deals with the end of a screen operation at MouseUp
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Processes the SECOND Clicked Object
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.MoveSecondClickedObjectClick(
Sender: TObject);
begin
ProcessClickedObject(pSecondClickedObject, SecondClickedObjectType);
end;
{General public methods -----------------------------------------------------}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.AddData
Description: Add data to the graph
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: adds data to all Axis simultaneously, avoiding re-drawing the data
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.AddData(
NoPoints: Integer;
XYArray: pXYArray);
var
i: Integer;
begin
if ((NoPoints > 0) and (NoPoints <= FSeriesList.Count)) then
begin
if (FDisplayMode <> dmHistory) then
begin
for i := 0 to NoPoints-1 do
begin
TSeries(FSeriesList.Items[i]).AddDrawPoint(XYArray^[i].X, XYArray^[i].Y, Canvas);
end;
end
else
begin
case FPlotType of
ptXY:
begin
{erase the old curve:}
FSeriesList.DrawHistory(Canvas, FDisplayHistory);
for i := 0 to NoPoints-1 do
begin
TSeries(FSeriesList.Items[i]).AddPoint(XYArray^[i].X, XYArray^[i].Y, FALSE, FALSE);
end;
{draw the new one:}
FSeriesList.DrawHistory(Canvas, FDisplayHistory);
end;
ptMultiple:
begin
{erase the old curve:}
FSeriesList.DrawHistory(Canvas, FDisplayHistory);
Canvas.Pen.Assign(FMultiplePen);
FSeriesList.DrawHistoryMultiple(Canvas, FMultiplicity);
for i := 0 to NoPoints-1 do
begin
TSeries(FSeriesList.Items[i]).AddPoint(XYArray^[i].X, XYArray^[i].Y, FALSE, FALSE);
end;
{draw the new one:}
FSeriesList.DrawHistory(Canvas, FDisplayHistory);
Canvas.Pen.Assign(FMultiplePen);
FSeriesList.DrawHistoryMultiple(Canvas, FMultiplicity);
end;
ptColumn:
begin
end;
{ptPipeLine:
begin
end;}
end;
end;
end
else
EMathError.CreateFmt(sAddDataError, [FSeriesList.Count]);
end;
{------------------------------------------------------------------------------
Function: TCustomPlot.AddSeries
Description: wrapper for TSeriesList.Add
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Adds a new, empty data Series to the graph
Return Value: the Index of the new Series
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.AddSeries(
XSeriesIndex: Integer): Integer;
begin
AddSeries := FSeriesList.Add(XSeriesIndex);
end;
{------------------------------------------------------------------------------
Function: TCustomPlot.AddExternal
Description: wrapper for TSeriesList.AddExternal
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Adds a new data Series that is maintained elsewhere to the graph
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.AddExternalSeries(
XPointer,
YPointer: pSingleArray;
NumberOfPoints: Integer): Integer;
begin
AddExternalSeries := FSeriesList.AddExternal(XPointer, YPointer, NumberOfPoints);
end;
{------------------------------------------------------------------------------
Function: TCustomPlot.AddInternal
Description: wrapper for TSeriesList.AddInternal
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Adds a new data Series from elsewhere to the graph, and saves it internally
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.AddInternalSeries(
XPointer,
YPointer: pSingleArray;
NumberOfPoints: Integer): Integer;
begin
AddInternalSeries := FSeriesList.AddInternal(XPointer, YPointer, NumberOfPoints);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CloneSeries
Description: wrapper for TSeriesList.CloneSeries
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Clones the specified Series
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.CloneSeries(
TheSeries: Integer): Integer;
begin
CloneSeries := FSeriesList.CloneSeries(TheSeries);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DeleteSeries
Description: wrapper for TSeriesList.DeleteSeries
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Deletes the specified Series
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DeleteSeries(
Index: Integer);
begin
FSeriesList.DeleteSeries(Index, not(csDesigning in ComponentState));
end;
{Responding to user (right) click menus -------------------------------------}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CopyClick
Description: The public copying method
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: copies the graph to the clipboard, in all formats simultaneously
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.CopyClick(
Sender: TObject);
begin
{$IFDEF MSWINDOWS}
ClipBoardFormatForHTML := RegisterClipboardFormat('cfHTML');
ClipBoard.Open;
try
{copy all three formats to the clipboard at once:}
CopyText;
CopyHTML(ClipBoardFormatForHTML);
CopyBitmap;
CopyDrawing(TRUE);
finally
ClipBoard.Close;
end;
{$ENDIF}
{$IFDEF LINUX}
CopyText;
CopyHTML(ClipBoardFormatForHTML);
CopyBitmap;
{$ENDIF}
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.HideClick
Description: Hides part of the graph
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: makes the selected object invisible
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.HideClick(
Sender: TObject);
begin
if (Sender is TPlotMenu) then
begin
FInstructions.Clear;
FInstructions.Add(sHideInstruction);
ScreenJob := sjHide;
DoStyleChange(Self);
exit;
end;
case ClickedObjectType of
soTitle: FTitle.Visible := FALSE;
soLegend: FLegend.Visible := FALSE;
soResult: FResult.Visible := FALSE;
soNote: TNote(pClickedObject).Visible := FALSE;
soXAxis: FXAxis.Visible := FALSE;
soYAxis: TAxis(pClickedObject).Visible := FALSE;
soXAxisTitle: FXAxis.Title.Visible := FALSE;
soYAxisTitle: TTitle(pClickedObject).Visible := FALSE;
soXAxisLabel: FXAxis.Labels.Visible := FALSE;
soYAxisLabel: TAxisLabel(pClickedObject).Visible := FALSE;
soSeries: pSeries.Visible := FALSE;
end;
DoStyleChange(Self);
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.PrintClick
Description: The public printing method
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Print the graph
Known Issues: We kludge this one a bit by creating a metafile, then playing it
on the printer canvas. It would be nicer to draw directly on the
printer canvas.
------------------------------------------------------------------------------}
procedure TCustomPlot.PrintClick(
Sender: TObject);
var
i,
Copies: Integer;
//Copies: Integer; currently ignored by the Qt dialog
PrintBorder: TRect;
{$IFDEF MSWINDOWS}
PrintDialog: TPrintDialog;
HorzSizeMM, VertSizeMM: Integer;
{$ENDIF}
{$IFDEF LINUX}
ThePrinter: TPrinter;
{$ENDIF}
begin
{$IFDEF LINUX}
ThePrinter := Printer;
ThePrinter.Orientation := FPrintOrientation;
if (ThePrinter.ExecuteSetup) then
begin
ThePrinter.Title := ExtractFileName(Application.ExeName) + ' - ' + FTitle.Caption;
{with ThePrinter do
begin
ShowMessageFmt(ThePrinter.Printers.Text + #10 +
'Copies = %d (%d)' + #10 +
'Orientation = %d' + #10 +
'PageWidth = %d' + #10 +
'PageHeight = %d' + #10 +
'Margins = (%d, %d)' + #10 +
'XDPI = %d' + #10 +
'YDPI = %d' + #10 +
'OutputDevice: ' + OutputDevice + #10 +
'Title: ' + Title,
[Copies, ThePrinter.PrintAdapter.Copies, Ord(Orientation),
PageWidth, PageHeight, Margins.cx, Margins.cy, XDPI, YDPI]);
end;}
if (ThePrinter.Copies < 1) then
ThePrinter.Copies := 1;
{i like 1" borders:}
PrintBorder.Left := 1 * ThePrinter.XDPI;
PrintBorder.Top := 1 * ThePrinter.YDPI;
PrintBorder.Right := ThePrinter.PageWidth - 1 * ThePrinter.XDPI;
PrintBorder.Bottom := ThePrinter.PageHeight - 1 * ThePrinter.YDPI;
ThePrinter.BeginDoc;
for i := 1 to ThePrinter.Copies do
begin
if (i > 1) then
ThePrinter.NewPage;
ThePrinter.Canvas.Start(TRUE);
ThePrinter.Canvas.StretchDraw(PrintBorder, Self.Drawing);
//ThePrinter.PrintAdapter.Canvas.StretchDraw(PrintBorder, Self.Drawing);
ThePrinter.Canvas.Pen.Color := clBlack;
ThePrinter.Canvas.Pen.Width := 9;
ThePrinter.Canvas.Pen.Style := psSolid;
ThePrinter.Canvas.MoveTo(PrintBorder.Left, PrintBorder.Top);
ThePrinter.Canvas.LineTo(PrintBorder.Right, PrintBorder.Bottom);
ThePrinter.Canvas.MoveTo(PrintBorder.Right, PrintBorder.Top);
ThePrinter.Canvas.LineTo(PrintBorder.Left, PrintBorder.Bottom);
ThePrinter.Canvas.Stop;
end;
ThePrinter.EndDoc;
end;
{$ENDIF}
{$IFDEF MSWINDOWS}
Printer.Orientation := FPrintOrientation;
PrintDialog := TPrintDialog.Create(Self);
PrintDialog.Options := [poPrintToFile, poWarning];
if (PrintDialog.Execute) then
begin
if (PrintDialog.Copies > 1) then
Copies := PrintDialog.Copies
else
Copies := 1;
Printer.Title := Application.ExeName + ' - ' + FTitle.Caption;
HorzSizeMM := GetDeviceCaps(Printer.Handle, HORZSIZE);
VertSizeMM := GetDeviceCaps(Printer.Handle, VERTSIZE);
{Set the margins to 25 mm:}
PrintBorder.Left := 25 * (Printer.PageWidth div HorzSizeMM);
PrintBorder.Top := 25 * (Printer.PageHeight div VertSizeMM);
PrintBorder.Right := Printer.PageWidth - PrintBorder.Left;
PrintBorder.Bottom := Printer.PageHeight - PrintBorder.Top;
{note: the D4 TPrinter has a Copies property, but not all printers support it,
so do printing the slow way:}
Printer.BeginDoc;
for i := 1 to Copies do
begin
if (i > 1) then
Printer.NewPage;
Printer.Canvas.StretchDraw(PrintBorder, Self.Drawing);
end;
Printer.EndDoc;
//DoStyleChange(Self);
end; {PrintDialog}
PrintDialog.Free;
{$ENDIF}
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ShowAllClick
Description: Shows/reveals all screen objects
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: makes everything visible.
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ShowAllClick(
Sender: TObject);
var
i: Integer;
begin
for i := 0 to FSeriesList.Count-1 do
TSeries(FSeriesList[i]).Visible := TRUE;
for i := 0 to ScreenObjectList.Count-1 do
TRectangle(ScreenObjectList.Items[i]).Visible := TRUE;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.PositionClick
Description: Where the hell are we ?
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Displays (and copies) the current mouse click position, in USER units
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.PositionClick(
Sender: TObject);
var
Msg: String;
begin
if (Sender is TPlotMenu) then
{came via }
begin
ScreenJob := sjPosition;
Screen.Cursor := crScope;
FInstructions.Clear;
FInstructions.Add(sPosition1);
DoStyleChange(Self);
end
else
begin
Msg := Format(sPosition2,
[Selection.Left, Selection.Top]) + CRLF +
sPosition3 +
FXAxis.LabelToStrF(FXAxis.XofF(Selection.Left));
if (Length(FXAxis.Title.Units) > 0) then
Msg := Msg + ' ' + FXAxis.Title.Units;
Msg := Msg + ', ' +
FYAxis.LabelToStrF(FYAxis.YofF(Selection.Top));
if (Length(FYAxis.Title.Units) > 0) then
Msg := Msg + ' ' + FYAxis.Title.Units;
Msg := Msg + ').';
ShowMessage(Msg);
ClipBoard.AsText := Msg;
ZeroScreenStuff;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.NearestPointClick
Description: Where the hell is it ?
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: finds the nearest point of the nearest Axis
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.NearestPointClick(
Sender: TObject);
var
NearestiX,
NearestiY: Integer;
MinDistance: Single;
Msg: String;
begin
if (Sender is TPlotMenu) then
{came via }
begin
ScreenJob := sjNearestPoint;
Screen.Cursor := crX;
FInstructions.Clear;
FInstructions.Add(sClickNear);
DoStyleChange(Self);
end
else
begin
ThePointNumber := FSeriesList.GetNearestPoint(
FPlotType,
FColumnGap,
Selection.Left, Selection.Top,
TheSeries,
MinDistance,
pSeries);
Msg := sTheNearestPointIs + IntToStr(ThePointNumber) + ' in ' +
pSeries.Name + CRLF + sAt + ' (' +
FXAxis.LabelToStrF(pSeries.XData^[ThePointNumber]);
if (Length(FXAxis.Title.Units) > 0) then
Msg := Msg + ' ' + FXAxis.Title.Units;
Msg := Msg + ', ' +
FYAxis.LabelToStrF(pSeries.YData^[ThePointNumber]);
if (Length(FYAxis.Title.Units) > 0) then
Msg := Msg + ' ' + FYAxis.Title.Units;
Msg := Msg + ').';
Canvas.Pen.Color := clRed;
Canvas.Pen.Mode := pmNotXOR;
Canvas.Pen.Style := psSolid;
Canvas.Pen.Width := 2;
NearestiX := pSeries.XAxis.FofX(pSeries.XData^[ThePointNumber]);
NearestiY := pSeries.YAxis.FofY(pSeries.YData^[ThePointNumber]);
Canvas.Ellipse(NearestiX-10, NearestiY-10, NearestiX+10, NearestiY+10);
ShowMessage(Msg);
ClipBoard.AsText := Msg;
{Pen.Color := clBlack;
Pen.Mode := pmNotXOR;
Pen.Style := psSolid;}
Canvas.Ellipse(NearestiX-10, NearestiY-10, NearestiX+10, NearestiY+10);
ZeroScreenStuff;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DeleteSeriesClick
Description: wrapper for TSeriesList.DeleteSeries
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Deletes the selected Series
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DeleteSeriesClick(
Sender: TObject);
begin
if (GetSeriesFromUser) then
begin
FSeriesList.DeleteSeries(TheSeries, not(csDesigning in ComponentState));
DoStyleChange(Self);
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CopySeriesClick
Description: wrapper for TSeriesList.CopySeries
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Copies the selected Series (as text)
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.CopySeriesClick(
Sender: TObject);
begin
if (GetSeriesFromUser) then
pSeries.CopyToClipBoard;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.NewSeriesClick
Description: wrapper for TSeriesList.AddSeries
Author: Mat Ballard
Date created: 04/16/2001
Date modified: 04/16/2001 by Mat Ballard
Purpose: Adds a new Series
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.NewSeriesClick(
Sender: TObject);
var
Index,
TheNewSeries: Integer;
pXSeries: TSeries;
OptionsDlg: TOptionsDlg;
begin
OptionsDlg := TOptionsDlg.Create(nil);
OptionsDlg.FormTitle := sNewSeries1;
OptionsDlg.Question := sNewSeries2;
OptionsDlg.OptionList.Add(sNewSeries3);
for Index := 0 to FSeriesList.Count-1 do
OptionsDlg.OptionList.Add(TSeries(FSeriesList.Items[Index]).Name);
Index := OptionsDlg.Execute - 1;
OptionsDlg.Free;
if (Index >= 0) then
begin
if (Index = 0) then
begin
TheNewSeries := FSeriesList.Add(-1);
end
else
begin
pXSeries := TSeries(FSeriesList.Items[Index]);
if (pXSeries.ExternalXSeries) then
pXSeries := pXSeries.XDataSeries;
Index := FSeriesList.IndexOf(pXSeries);
TheNewSeries := FSeriesList.Add(Index);
end;
TSeries(FSeriesList.Items[TheNewSeries]).EditData(FHelpFile);
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CloneSeriesClick
Description: wrapper for TSeriesList.CloneSeries
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Clones the selected Series
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.CloneSeriesClick(
Sender: TObject);
begin
if (GetSeriesFromUser) then
begin
FSeriesList.CloneSeries(TheSeries);
DoStyleChange(Self);
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ModeClick
Description: Changes how the graph appears and reacts to new data
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets the DisplayMode property
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ModeClick(
Sender: TObject);
var
Index: Integer;
DisplayHistoryStr: String;
OptionsDlg: TOptionsDlg;
begin
OptionsDlg := TOptionsDlg.Create(nil);
OptionsDlg.FormTitle := sMode1;
OptionsDlg.Question := sMode2;
OptionsDlg.OptionList.Add(sMode3);
OptionsDlg.OptionList.Add(sMode4);
OptionsDlg.OptionList.Add(sMode5);
OptionsDlg.OptionList.Add(sMode6);
Index := OptionsDlg.Execute - 1;
OptionsDlg.Free;
if (Index >= 0) then
begin
if (Index = Ord(dmHistory)) then
begin
DisplayHistoryStr := FloatToStr(FDisplayHistory);
if (InputQuery(sHistoryRange, '', DisplayHistoryStr)) then
FDisplayHistory := StrToFloat(DisplayHistoryStr);
end;
SetDisplayMode(TDisplayMode(Index));
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CanPaste
Description: Can we paste data from the Clipboard into TPlot ?
Author: Mat Ballard
Date created: 11/28/1999
Date modified: 11/28/2000 by Mat Ballard
Purpose: check in with the clipboard, looking for text data
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.CanPaste: Boolean;
{$IFDEF LINUX}
var
FormatList: TStringList;
i: Integer;
{$ENDIF}
begin
{$IFDEF MSWINDOWS}
CanPaste := (ClipBoard.HasFormat(CF_TEXT));
{$ENDIF}
{$IFDEF LINUX}
CanPaste := FALSE;
FormatList := TStringList.Create;
Clipboard.SupportedFormats(FormatList);
for i := 0 to FormatList.Count-1 do
begin
if (Pos('text/plain', FormatList.Strings[i]) > 0) then
begin
CanPaste := TRUE;
exit;
end;
end;
FormatList.Free;
{$ENDIF}
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.PasteSeriesClick
Description: Pastes data from the Clipboard
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Collects the data from the Clipboard and runs the ParseData method on it.
Known Issues: limited to 32 K under D1. Can be fixed with messy memory management.
------------------------------------------------------------------------------}
procedure TCustomPlot.PasteClick(
Sender: TObject);
var
TheData: TStringList;
{$IFDEF DELPHI1}
LongStr: PChar;
{$ENDIF}
begin
TheData := TStringList.Create;
{$IFDEF DELPHI1}
GetMem(LongStr, 32767);
Clipboard.GetTextBuf(LongStr, 32767);
TheData.SetText(LongStr);
FreeMem(LongStr, 32767);
{$ELSE}
TheData.Text := Clipboard.AsText;
{$ENDIF}
FSeriesList.ParseData(TheData, FHelpFile);
TheData.Free;
ZoomOutClick(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.LineBestFitClick
Description: Initiates a Line of Best Fit.
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 05/30/2001 by Mat Ballard
Purpose: Sets the Instructions and the ScreenJob
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.LineBestFitClick(
Sender: TObject);
var
{Variables used in least-squares fitting:}
NoLeastSquarePts: Integer;
SumX, SumY, SumXsq, SumXY, SumYsq: Double;
Rsq: Single;
{ Slope, Intercept: Single; - are globals to allow drawing of line}
procedure InitializeFit;
begin
{Initialize the fit parameters:}
NoLeastSquarePts := 0;
SumX := 0;
SumY := 0;
SumXsq := 0;
SumXY := 0;
SumYsq := 0;
end;
begin
if (GetSeriesFromUser) then
begin
if ((FScreenJob = sjRightDrag) or
(FScreenJob = sjLineOfBestFit)) then
begin
InitializeFit;
pSeries.LineBestFit(XAxis.XofF(Selection.Left), XAxis.XofF(Selection.Right),
NoLeastSquarePts,
SumX, SumY, SumXsq, SumXY, SumYsq,
Slope, Intercept, Rsq);
SetResult(Slope, Intercept, Rsq);
ZeroScreenStuff;
end
else if (FScreenJob = sjDualLineBestFit2) then
begin
InitializeFit;
pSeries.LineBestFit(XAxis.XofF(Sel1.Left), XAxis.XofF(Sel1.Right),
NoLeastSquarePts,
SumX, SumY, SumXsq, SumXY, SumYsq,
Slope, Intercept, Rsq);
pSeries.LineBestFit(XAxis.XofF(Selection.Left), XAxis.XofF(Selection.Right),
NoLeastSquarePts,
SumX, SumY, SumXsq, SumXY, SumYsq,
Slope, Intercept, Rsq);
SetResult(Slope, Intercept, Rsq);
ZeroScreenStuff;
end
else
begin
FInstructions.Clear;
FInstructions.Add(sLBF);
ScreenJob := sjLineOfBestFit;
FResult.Visible := False;
DoStyleChange(Self);
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.TwoRegionLineBestFitClick
Description: Initiates a Two Region Line of Best Fit.
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 05/30/2001 by Mat Ballard
Purpose: Sets the FInstructions and the ScreenJob
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.TwoRegionLineBestFitClick(Sender: TObject);
begin
if (GetSeriesFromUser) then
begin
if ((FScreenJob = sjRightDrag) or
(FScreenJob = sjDualLineBestFit1)) then
begin
Selection.AssignToRect(Sel1);
{Sel1.Left := Selection.Left;
Sel1.Top := Selection.Top;
Sel1.Right := Selection.Right;
Sel1.Bottom := Selection.Bottom;}
ScreenJob := sjDualLineBestFit2;
FInstructions.Clear;
FInstructions.Add(sDualInstruction + ' ' + sToFit);
DoStyleChange(Self);
end
else
begin
FInstructions.Clear;
FInstructions.Add(s2RLBF);
ScreenJob := sjDualLineBestFit1;
FResult.Visible := False;
DoStyleChange(Self);
end;
end;
end;
{$IFDEF FUNCTIONS}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.FunctionClick
Description: Creates a new series which is a function of existing series
Author: Mat Ballard
Date created: 04/03/2001
Date modified: 04/03/2001 by Mat Ballard
Purpose: data manipulation
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.FunctionClick(Sender: TObject);
begin
FSeriesList.FunctionSeries;
ZoomOutClick(Self);
end;
{$ENDIF}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SmoothSeriesClick
Description: Smoothes the selected data Series
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Obtains the Smoothing Order then runs the selected Series' Smooth method
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SmoothSeriesClick(
Sender: TObject);
var
SmoothOrder: Integer;
SmoothStr: String;
begin
if (GetSeriesFromUser) then
begin
SmoothStr := '10';
if (InputQuery(sSmoothing1 + pSeries.Name,
sSmoothing2,
SmoothStr)) then
begin
try
SmoothOrder := StrToInt(SmoothStr);
pSeries.Smooth(SmoothOrder);
DoStyleChange(Self);
except
ShowMessage(sSmoothFail);
end;
end;
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SortClick
Description: sorts the selected data
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: data management and manipulation
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SortClick(Sender: TObject);
begin
if (GetSeriesFromUser) then
begin
pSeries.Sort;
DoStyleChange(Self);
end;
ZeroScreenStuff;
end;
procedure TCustomPlot.SplineClick(Sender: TObject);
begin
if (GetSeriesFromUser) then
begin
Self.Spline(TheSeries);
DoStyleChange(Self);
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Function: TCustomPlot.Spline
Description: wrapper for TSeriesList.Spline
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Adds a new, empty data Series to the graph
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.Spline(ASeries: Integer): Integer;
var
Density: Word;
pSplineSeries: TSeries;
TheString: String;
begin
Spline := -1;
{if it isn't already ...}
pSeries := TSeries(FSeriesList.Items[ASeries]);
TheString := '1';
if (InputQuery(sSpline1, sSpline2, TheString)) then
begin
Density := StrToInt(TheString);
ASeries := FSeriesList.Add(-1);
pSplineSeries := TSeries(FSeriesList.Items[ASeries]);
pSplineSeries.AllocateNoPts(pSeries.NoPts * (Density + 1));
pSeries.DoSpline(Density, pSplineSeries);
pSplineSeries.Name := sSpline3 + pSeries.Name;
pSplineSeries.Pen.Style := psDot;
pSplineSeries.Visible := TRUE;
Spline := ASeries;
{should we call pSeries.ClearSpline ?}
DoStyleChange(Self);
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CompressSeriesClick
Description: Reduces the number of data points of the selected Series by averaging the data
Author: Mat Ballard
Date created: 10/15/2000
Date modified: 10/15/2000 by Mat Ballard
Purpose: data management and manipulation
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.CompressSeriesClick(
Sender: TObject);
var
CompressRatio: Integer;
CompressStr: String;
begin
if (GetSeriesFromUser) then
begin
if (pSeries.XDataRefCount > 0) then raise
EComponentError.CreateFmt(
sCompress1 + CRLF + sCompress2,
[pSeries.Name, pSeries.XDataRefCount]);
if (pSeries.ExternalXSeries) then raise
EComponentError.CreateFmt(
sCompress1 + CRLF + sCompress3,
[pSeries.Name, pSeries.XDataSeries.Name]);
CompressStr := '10';
if (InputQuery(sCompress4 + pSeries.Name,
sCompress5,
CompressStr)) then
begin
try
CompressRatio := StrToInt(CompressStr);
pSeries.Compress(CompressRatio);
except
ShowMessage(sCompress6);
end;
end;
DoStyleChange(Self);
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CompressAllSeriesClick
Description: Reduces the number of data points in ALL Series by averaging the data
Author: Mat Ballard
Date created: 10/15/2000
Date modified: 10/15/2000 by Mat Ballard
Purpose: data management and manipulation
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.CompressAllSeriesClick(
Sender: TObject);
var
CompressRatio: Integer;
CompressStr: String;
i: Integer;
begin
CompressStr := '10';
if (InputQuery(sCompressAll1,
sCompress5,
CompressStr)) then
begin
try
CompressRatio := StrToInt(CompressStr);
for i := 0 to FSeriesList.Count-1 do
TSeries(FSeriesList.Items[i]).Compress(CompressRatio);
except
ShowMessage(sCompress6);
end;
end;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ContractSeriesClick
Description: Reduces the number of data points of the selected Series by throwing away the ends
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 05/30/2001 by Mat Ballard
Purpose: data management and manipulation
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ContractSeriesClick(
Sender: TObject);
var
TheLeft,
TheRight: Integer;
begin
if (GetSeriesFromUser) then
begin
if (pSeries.XDataRefCount > 0) then raise
EComponentError.CreateFmt(
sContract1 + CRLF + sCompress2,
[pSeries.Name, pSeries.XDataRefCount]);
if (pSeries.ExternalXSeries) then raise
EComponentError.CreateFmt(
sContract1 + CRLF + sCompress3,
[pSeries.Name, pSeries.XDataSeries.Name]);
if ((FScreenJob = sjRightDrag) or
(FScreenJob = sjContractSeries)) then
begin
TheLeft := pSeries.GetNearestPointToFX(Selection.Left);
TheRight := pSeries.GetNearestPointToFX(Selection.Right);
pSeries.Contract(TheLeft, TheRight);
ZeroScreenStuff;
end
else
begin
FScreenJob := sjContractSeries;
FInstructions.Clear;
FInstructions.Add(sContract2);
FInstructions.Add(sContract3);
DoStyleChange(Self);
end;
DoStyleChange(Self);
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ContractAllSeriesClick
Description: Reduces the number of data points of the selected Series by throwing away the ends
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 05/30/2001 by Mat Ballard
Purpose: data management and manipulation
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ContractAllSeriesClick(
Sender: TObject);
var
TheLeft,
TheRight: Integer;
i: Integer;
begin
if ((FScreenJob = sjRightDrag) or
(FScreenJob = sjContractAllSeries)) then
begin
TheLeft := TSeries(FSeriesList.Items[0]).GetNearestPointToFX(Selection.Left);
TheRight := TSeries(FSeriesList.Items[0]).GetNearestPointToFX(Selection.Right);
for i := 0 to FSeriesList.Count-1 do
TSeries(FSeriesList.Items[i]).Contract(TheLeft, TheRight);
ZeroScreenStuff;
end
else
begin
FScreenJob := sjContractAllSeries;
FInstructions.Clear;
FInstructions.Add(sContract2);
FInstructions.Add(sContract3);
DoStyleChange(Self);
end;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.LegendClick
Description: Sets the Legend Direction
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose:
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.LegendClick(
Sender: TObject);
var
Index: Integer;
OptionsDlg: TOptionsDlg;
begin
OptionsDlg := TOptionsDlg.Create(nil);
OptionsDlg.FormTitle := sLegend;
OptionsDlg.Question := sLegend2;
OptionsDlg.OptionList.Add(sHorizontally);
OptionsDlg.OptionList.Add(sVertically);
Index := OptionsDlg.Execute - 1;
OptionsDlg.Free;
if (Index >= 0) then
begin
FLegend.Direction := TDirection(Index);
end;
ZeroScreenStuff;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.EditAxisClick
Description: Runs the Axis Editor of the selected Axis
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 06/28/2000 by Mat Ballard
Purpose:
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.EditAxisClick(
Sender: TObject);
var
i: Integer;
AxisEditor: TAxisEditorForm;
AXP: TAxisProperty;
begin
if (GetAxisFromUser(0)) then
begin
AxisEditor := TAxisEditorForm.Create(nil);
AxisEditor.ThePlot := TObject(Self);
if (FDisplayMode = dmHistory) then
AxisEditor.HistoryMode := TRUE;
{Iterate over all axes:}
for i := 0 to FAxisList.Count-1 do
begin
pAxis := TAxis(FAxisList.Items[i]);
AXP.LabelFormat := pAxis.Labels.NumberFormat;
AXP.LabelDigits := pAxis.Labels.Digits;
AXP.LabelPrecision := pAxis.Labels.Precision;
AXP.LabelDirection := pAxis.Labels.Direction;
AXP.PenColor := pAxis.Pen.Color;
AXP.PenWidthIndex := pAxis.Pen.Width;
AXP.PenStyleIndex := Ord(pAxis.Pen.Style);
AXP.TickSize := pAxis.TickSize;
AXP.TickDirection := pAxis.TickDirection;
AXP.TickStepSize := pAxis.StepSize;
AXP.TickMinors := pAxis.TickMinor;
AXP.ScaleMin := pAxis.Min;
AXP.ScaleMax := pAxis.Max;
AXP.ScaleIntercept := pAxis.Intercept;
AXP.ScaleAuto := pAxis.AutoScale;
AXP.ScaleLog := pAxis.LogScale;
AXP.ArrowSize := pAxis.ArrowSize;
AXP.ArrowDirection := pAxis.Alignment;
AXP.Visible := pAxis.Visible;
AXP.LimitLower := pAxis.LimitLower;
AXP.LimitUpper := pAxis.LimitUpper;
AXP.LimitsVisible := pAxis.LimitsVisible;
if (TObject(FAxisList.Items[i]) is TAngleAxis) then
begin
AXP.ZAngle := TAngleAxis(pAxis).Angle;
AXP.ZLength := TAngleAxis(pAxis).Length;
AXP.ZInterceptY := TAngleAxis(pAxis).ZInterceptY;
end
else
begin
AXP.ZAngle := 0;
AXP.ZLength := 0;
end;
AxisEditor.AddAxis(pAxis.Title.Caption, AXP);
end;
if (TheAxis >= 0) then
AxisEditor.NoComboBox.ItemIndex := TheAxis;
AxisEditor.SelectAxis(TheAxis);
AxisEditor.HelpFile := FHelpFile;
if (AxisEditor.ShowModal = mrOK) then
ApplyAxisChange(AxisEditor);
AxisEditor.Free;
ZeroScreenStuff;
end; {GetAxisFrom User}
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ApplyAxisChange
Description: This applies changes from the PropertiesDialog.
Author: Mat Ballard
Date created: 03/28/2001
Date modified: 03/28/2001 by Mat Ballard
Purpose: User interface management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ApplyAxisChange(Sender: TObject);
var
i: Integer;
pAXP: ^TAxisProperty;
begin
for i := 0 to FAxisList.Count-1 do
begin
pAXP := TAxisEditorForm(Sender).AxisPropertyList.Items[i];
pAxis := TAxis(FAxisList.Items[i]);
pAxis.Title.Caption := TAxisEditorForm(Sender).AxisNames.Strings[i];
pAxis.Labels.NumberFormat := pAXP^.LabelFormat;
pAxis.Labels.Digits := pAXP^.LabelDigits;
pAxis.Labels.Precision := pAXP^.LabelPrecision;
pAxis.Labels.Direction := pAXP^.LabelDirection;
pAxis.Pen.Color := pAXP^.PenColor;
pAxis.Pen.Width := pAXP^.PenWidthIndex;
pAxis.Pen.Style := TPenStyle(pAXP^.PenStyleIndex);
pAxis.TickSize := pAXP^.TickSize;
pAxis.TickDirection := pAXP^.TickDirection;
pAxis.TickMinor := pAXP^.TickMinors;
pAxis.AutoScale := pAXP^.ScaleAuto;
pAxis.StepSize := pAXP^.TickStepSize;
pAxis.Min := pAXP^.ScaleMin;
pAxis.Max := pAXP^.ScaleMax;
pAxis.Intercept := pAXP^.ScaleIntercept;
pAxis.LogScale := pAXP^.ScaleLog;
pAxis.ArrowSize := pAXP^.ArrowSize;
pAxis.Alignment := pAXP^.ArrowDirection;
pAxis.LimitLower := pAXP^.LimitLower;
pAxis.LimitUpper := pAXP^.LimitUpper;
pAxis.LimitsVisible := pAXP^.LimitsVisible;
if (TObject(FAxisList.Items[i]) is TAngleAxis) then
begin
TAngleAxis(pAxis).Angle := pAXP^.ZAngle;
TAngleAxis(pAxis).Length := pAXP^.ZLength;
TAngleAxis(pAxis).ZInterceptY := pAXP^.ZInterceptY;
end;
pAxis.Visible := pAXP^.Visible;
pAxis.ReScale;
end; {for}
{DoStyleChange(Self);}
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.NewNoteClick
Description: Creates a new note
Author: Mat Ballard
Date created: 11/1/2000
Date modified: 11/1/2000 by Mat Ballard
Purpose: appearance management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.NewNoteClick(Sender: TObject);
var
ANote: TNote;
begin
ANote := TNote.Create(Self);
ANote.MoveTo(Selection.Left, Selection.Top);
ANote.ArrowLeft := Selection.Left + 1;
ANote.ArrowTop := Selection.Top + 1;
ANote.Tag := Ord(soNote);
ScreenObjectList.Add(ANote);
Inc(NoteCount);
//NoteList.Add(ANote);
pClickedObject := ANote;
Screen.Cursor := crScope;
ScreenJob := sjMoveNotePointer;
FInstructions.Clear;
FInstructions.Add(sNewNoteClick1);
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DeleteNoteClick
Description: Moves a note pointer
Author: Mat Ballard
Date created: 11/22/2000
Date modified: 11/22/2000 by Mat Ballard
Purpose: appearance management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.MoveNotePointerClick(Sender: TObject);
begin
if (GetNoteFromUser) then
FScreenJob := sjMoveNotePointer;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DeleteNoteClick
Description: Deletes a note
Author: Mat Ballard
Date created: 11/14/2000
Date modified: 11/14/2000 by Mat Ballard
Purpose: appearance management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DeleteNoteClick(Sender: TObject);
begin
if (GetNoteFromUser) then
begin
ScreenObjectList.Remove(pClickedObject);
Dec(NoteCount);
TNote(pClickedObject).Free;
DoStyleChange(Self);
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.EditFontClick
Description: Edits the font of the selected Axis
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs the Font common Dialog box, and applies the results to the selected object
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.EditFontClick(
Sender: TObject);
var
TheFont: TFont;
FontDialog: TFontDialog;
OptionsDlg: TOptionsDlg;
TheResult: Integer;
begin
{has the user already selected an object ?}
if ((ClickedObjectType = soNone) or
(ClickedObjectType = soXAxis) or
(ClickedObjectType = soYAxis) or
(ClickedObjectType = soLeftBorder) or
(ClickedObjectType = soTopBorder) or
(ClickedObjectType = soRightBorder) or
(ClickedObjectType = soBottomBorder)) then
begin
{get the user to select an object:}
OptionsDlg := TOptionsDlg.Create(nil);
OptionsDlg.FormTitle := sEditFont1;
OptionsDlg.Question := sEditFont2;
OptionsDlg.OptionList.Add(sEditFont3);
OptionsDlg.OptionList.Add(sEditFont4);
OptionsDlg.OptionList.Add(sEditFont5);
OptionsDlg.OptionList.Add(sEditFont6);
OptionsDlg.OptionList.Add(sEditFont7);
OptionsDlg.OptionList.Add(sEditFont8);
OptionsDlg.OptionList.Add(sEditFont9);
OptionsDlg.OptionList.Add(sEditFont10);
OptionsDlg.OptionList.Add(sEditFont11);
TheResult := OptionsDlg.Execute;
case TheResult of
1: ClickedObjectType := soTitle;
2: ClickedObjectType := soXAxisTitle;
3: ClickedObjectType := soYAxisTitle;
5: ClickedObjectType := soXAxisLabel;
6: ClickedObjectType := soYAxisLabel;
8: ClickedObjectType := soLegend;
9: ClickedObjectType := soResult;
end;
OptionsDlg.Free;
end; {if object selected}
FontDialog := TFontDialog.Create(Self);
case ClickedObjectType of
soTitle: TheFont := FTitle.Font;
soXAxisTitle: TheFont := FXAxis.Title.Font;
soYAxisTitle: TheFont := TTitle(pClickedObject).Font;
soXAxisLabel: TheFont := FXAxis.Labels.Font;
soYAxisLabel: TheFont := TAxisLabel(pClickedObject).Font;
soLegend: TheFont := FLegend.Font;
soResult: TheFont := FResult.Font;
soNote: TheFont := TNote(pClickedObject).Font;
else
{assign TheFont:}
//TheFont := nil;
FontDialog.Free;
{don't like bugging out here, but is most elegant solution:}
exit;
end;
FontDialog.Font.Assign(TheFont);
if (FontDialog.Execute) then
begin
TheFont.Assign(FontDialog.Font);
DoStyleChange(Self);
end;
ZeroScreenStuff;
FontDialog.Free;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.EditPropertiesClick
Description: Edits the other properties of the Plot
Author: Mat Ballard
Date created: 10/10/2000
Date modified: 10/10/2000 by Mat Ballard
Purpose: Runs the Properties Dialog box, and applies the results to the selected objects
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.EditPropertiesClick(
Sender: TObject);
var
PlotPropertyEditor: TPlotPropertyEditorForm;
begin
PlotPropertyEditor := TPlotPropertyEditorForm.Create(nil);
PlotPropertyEditor.ThePlot := TObject(Self);
PlotPropertyEditor.HelpFile := FHelpFile;
PlotPropertyEditor.PlotTypeComboBox.ItemIndex := Ord(FPlotType);
PlotPropertyEditor.BackColorEdit.Color := Self.Color;
PlotPropertyEditor.BackColorEdit.Text := ColorToString(Self.Color);
PlotPropertyEditor.BubbleSizeNEdit.AsInteger := FBubbleSize;
PlotPropertyEditor.ClickAndDragDelayNEdit.AsInteger := MouseTimer.Interval;
PlotPropertyEditor.ColumnGapNEdit.AsInteger := FColumnGap;
PlotPropertyEditor.ContourDetailComboBox.ItemIndex := Ord(FContourDetail);
PlotPropertyEditor.ContourIntervalNEdit.AsReal := FContourInterval;
PlotPropertyEditor.ContourStartNEdit.AsReal := FContourStart;
PlotPropertyEditor.ContourWireFrameCheckBox.Checked := FContourWireFrame;
PlotPropertyEditor.GridComboBox.ItemIndex := Ord(FGrid);
PlotPropertyEditor.GridStyleComboBox.ItemIndex := Ord(FGridStyle);
PlotPropertyEditor.GridColorEdit.Color := FGridColor;
PlotPropertyEditor.GridColorEdit.Text := ColorToString(FGridColor);
PlotPropertyEditor.LinkZSeriesCheckBox.Checked := FZLink;
PlotPropertyEditor.MultiplicityComboBox.ItemIndex := FMultiplicity - 1;
PlotPropertyEditor.MultiJoinEdit.Text := GetMultiJoin;
PlotPropertyEditor.PenColorEdit.SetColour(FMultiplePen.Color);
PlotPropertyEditor.PenWidthComboBox.ItemIndex := FMultiplePen.Width;
PlotPropertyEditor.PenStyleComboBox.ItemIndex := Ord(FMultiplePen.Style);
PlotPropertyEditor.PolarRangeNEdit.AsReal := FPolarRange;
PlotPropertyEditor.PieRowCountComboBox.ItemIndex := FPieRowCount - 1;
PlotPropertyEditor.PrintOrientationComboBox.ItemIndex := Ord(FPrintOrientation);
PlotPropertyEditor.WallColorEdit.Color := FWallColor;
PlotPropertyEditor.WallColorEdit.Text := ColorToString(FWallColor);
PlotPropertyEditor.XYFastAtNEdit.AsInteger := FXYFastAt;
PlotPropertyEditor.ZAxisAngleNEdit.AsInteger := ZAngle;
PlotPropertyEditor.ZLengthNEdit.AsInteger := ZLength;
{$IFDEF DELPHI1}
PlotPropertyEditor.CreatedByEdit.Visible := FALSE;
PlotPropertyEditor.DescriptionEdit.Visible := FALSE;
{$ELSE}
PlotPropertyEditor.CreatedByEdit.Text := FCreatedBy;
PlotPropertyEditor.DescriptionEdit.Text := FDescription;
{$ENDIF}
if (PlotPropertyEditor.ShowModal = mrOK) then
ApplyPropertiesChange(PlotPropertyEditor);
PlotPropertyEditor.Free;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ApplyPropertiesChange
Description: This applies changes from the PropertiesDialog.
Author: Mat Ballard
Date created: 03/28/2001
Date modified: 03/28/2001 by Mat Ballard
Purpose: User interface management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ApplyPropertiesChange(Sender: TObject);
var
OldIgnoreChanges: Boolean;
begin
with TPlotPropertyEditorForm(Sender) do
begin
OldIgnoreChanges := IgnoreChanges;
IgnoreChanges := TRUE;
MouseTimer.Interval := ClickAndDragDelayNEdit.AsInteger;
Self.Color := BackColorEdit.Color;
FBubbleSize := BubbleSizeNEdit.AsInteger;
FColumnGap := ColumnGapNEdit.AsInteger;
FContourDetail := TContourDetail(ContourDetailComboBox.ItemIndex);
FContourInterval := ContourIntervalNEdit.AsReal;
FContourStart := ContourStartNEdit.AsReal;
FContourWireFrame := ContourWireFrameCheckBox.Checked;
FGrid := TGridType(GridComboBox.ItemIndex);
FGridStyle := TPenStyle(GridStyleComboBox.ItemIndex);
FGridColor := GridColorEdit.Color;
FMultiplePen.Width := PenWidthComboBox.ItemIndex;
FMultiplePen.Style := TPenStyle(PenStyleComboBox.ItemIndex);
FMultiplicity := MultiplicityComboBox.ItemIndex + 1;
FMultiplePen.Color := PenColorEdit.Color;
SetMultiJoin(MultiJoinEdit.Text);
FPieRowCount := PieRowCountComboBox.ItemIndex + 1;
FPolarRange := PolarRangeNEdit.AsReal;
FPrintOrientation := TPrinterOrientation(PrintOrientationComboBox.ItemIndex);
FWallColor := WallColorEdit.Color;
FXYFastAt := XYFastAtNEdit.AsInteger;
ZAngle := ZAxisAngleNEdit.AsInteger;
ZLength := ZLengthNEdit.AsInteger;
FZLink := LinkZSeriesCheckBox.Checked;
{$IFNDEF DELPHI1}
FCreatedBy := CreatedByEdit.Text;
FDescription := DescriptionEdit.Text;
{$ENDIF}
PlotType := TPlotType(PlotTypeComboBox.ItemIndex);
IgnoreChanges := OldIgnoreChanges;
DoStyleChange(Self);
{Required for 3D walls to display properly:}
if (FGrid > gtNone) then
if (FPlotType >= pt3DContour) then
begin
Application.ProcessMessages;
Refresh;
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.EditPointClick
Description: Runs the Point Editor of the selected data point
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose:
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.EditPointClick(
Sender: TObject);
begin
if (GetSeriesFromUser) then
begin
pSeries.EditPoint(ThePointNumber, FHelpFile);
//DoStyleChange(Self);
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.GetNoteFromUser
Description: Gets the user to select (if not already done so) a Axis
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: user interface management
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetNoteFromUser: Boolean;
var
OptionsDlg: TOptionsDlg;
i: Integer;
TheNote: Integer;
begin
{has the user already selected an object ?}
if (ClickedObjectType <> soNote) then
begin
if (NoteCount = 1) then
begin
{there is only one Note:}
ClickedObjectType := soNote;
for i := NoBasicScreenObjects to ScreenObjectList.Count-1 do
begin
if (TObject(ScreenObjectList.Items[i]) is TNote) then
begin
pClickedObject := ScreenObjectList.Items[i];
break;
end;
end;
end;
if (ClickedObjectType <> soNote) then
{still no Note selected:}
begin
{get the user to select an object:}
OptionsDlg := TOptionsDlg.Create(nil);
OptionsDlg.FormTitle := sWhichNote;
OptionsDlg.Question := sWhichNoteDel;
for i := NoBasicScreenObjects to ScreenObjectList.Count-1 do
begin
if (TObject(ScreenObjectList.Items[i]) is TNote) then
OptionsDlg.OptionList.AddObject(
TNote(ScreenObjectList.Items[i]).Caption,
TNote(ScreenObjectList.Items[i]));
end;
TheNote := OptionsDlg.Execute - 1;
if (TheNote >= 0) then
begin
ClickedObjectType := soNote;
pClickedObject :=
OptionsDlg.OptionList.Objects[TheNote];
//ScreenObjectList.Items[NoBasicScreenObjects + TheNote];
end;
OptionsDlg.Free;
end; {if object selected}
end; {if clicked object is Series}
GetNoteFromUser := (ClickedObjectType = soNote);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.GetSeriesFromUser
Description: Gets the user to select (if not already done so) a Axis
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: user interface management
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetSeriesFromUser: Boolean;
var
OptionsDlg: TOptionsDlg;
i: Integer;
begin
{has the user already selected an object ?}
if (ClickedObjectType <> soSeries) then
begin
ThePointNumber := 0;
if (FSeriesList.Count = 1) then
begin
{there is only one Series:}
ClickedObjectType := soSeries;
TheSeries := 0;
pSeries := TSeries(FSeriesList.Items[0]);
end;
if (ClickedObjectType <> soSeries) then
{still no Series selected:}
begin
{get the user to select an object:}
OptionsDlg := TOptionsDlg.Create(nil);
OptionsDlg.FormTitle := sWhichSeries;
OptionsDlg.Question := sWhichSeries2;
for i := 0 to FSeriesList.Count-1 do
begin
OptionsDlg.OptionList.Add(TSeries(FSeriesList.Items[i]).Name);
end;
TheSeries := OptionsDlg.Execute - 1;
if (TheSeries >= 0) then
begin
ClickedObjectType := soSeries;
pSeries := TSeries(FSeriesList.Items[TheSeries]);
end;
OptionsDlg.Free;
end; {if object selected}
end; {if clicked object is Series}
GetSeriesFromUser := (TheSeries >= 0);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.GetAxisFromUser
Description: Gets the user to select (if not already done so) a Axis
Author: Mat Ballard
Date created: 06/25/1999
Date modified: 06/25/2000 by Mat Ballard
Purpose: user interface management
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetAxisFromUser(StartAxis: Word): Boolean;
var
OptionsDlg: TOptionsDlg;
i,
TheResult: Integer;
begin
{has the user already selected an object ?}
{see GetTheClickedObject}
if ((TheAxis >= StartAxis) and (pAxis <> nil)) then
begin
GetAxisFromUser := TRUE;
exit;
end;
if (StartAxis = FAxisList.Count - 1) then
begin
{there is only one Axis that it could be:}
ClickedObjectType := soYAxis;
{NB: the Y Axes are numbered 1, 2..N:}
TheAxis := StartAxis;
pAxis := TAxis(FAxisList.Items[TheAxis]);
GetAxisFromUser := TRUE;
exit;
end;
{still no Axis selected:}
{get the user to select an object:}
OptionsDlg := TOptionsDlg.Create(nil);
OptionsDlg.FormTitle := sWhichAxis;
OptionsDlg.Question := sWhichAxis2;
for i := StartAxis to FAxisList.Count-1 do
begin
OptionsDlg.OptionList.Add(TAxis(FAxisList.Items[i]).Name);
end;
TheResult := OptionsDlg.Execute;
if (TheResult > 0) then
begin
TheAxis := StartAxis + TheResult - 1; {Execute = -1, 1,2,3}
if (TheAxis = 0) then
ClickedObjectType := soXAxis;
if (TheAxis > 0) then
ClickedObjectType := soYAxis;
pAxis := TAxis(FAxisList.Items[TheAxis]);
end;
OptionsDlg.Free;
if (TheAxis >= 0) then
GetAxisFromUser := TRUE
else
GetAxisFromUser := FALSE;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.EditDataClick
Description: Runs the Data Editor for the selected Series
Author: Mat Ballard
Date created: 03/13/2001
Date modified: 03/13/2001 by Mat Ballard
Purpose:
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.EditDataClick(
Sender: TObject);
begin
if (GetSeriesFromUser) then
begin
pSeries.EditData(FHelpFile);
end; {GetSeries}
ZeroScreenStuff;
Refresh;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.EditSeriesClick
Description: Runs the Series Editor of the selected data Series
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose:
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.EditSeriesClick(
Sender: TObject);
var
i: Integer;
SeriesEditor: TSeriesEditorForm;
ASP: TSeriesProperty;
pSeries: TSeries;
begin
if (GetSeriesFromUser) then
begin
SeriesEditor := TSeriesEditorForm.Create(nil);
SeriesEditor.ThePlot := TObject(Self);
{Load the Y Axis Combo Box:}
for i := 1 to FAxisList.Count-1 do
begin
SeriesEditor.YAxisComboBox.Items.Add(TAxis(FAxisList.Items[i]).Title.Caption);
end;
{Iterate over all series:}
for i := 0 to FSeriesList.Count-1 do
begin
pSeries := TSeries(FSeriesList.Items[i]);
{returns 0..MY_COLORS_MAX}
ASP.PenColor := pSeries.Pen.Color;
ASP.PenWidthIndex := pSeries.Pen.Width;
ASP.PenStyleIndex := Ord(pSeries.Pen.Style);
ASP.BrushColor := pSeries.Brush.Color;
ASP.BrushStyleIndex := Ord(pSeries.Brush.Style);
ASP.SymbolIndex := Ord(pSeries.Symbol);
ASP.SymbolSize := pSeries.SymbolSize;
ASP.YAxisIndex := pSeries.YAxisIndex;
ASP.DeltaX := pSeries.DeltaX;
ASP.DeltaY := pSeries.DeltaY;
ASP.XDataIndependent := not pSeries.ExternalXSeries;
ASP.ExternalXSeries := pSeries.ExternalXSeries;
ASP.Visible := pSeries.Visible;
ASP.ShadeLimits := pSeries.ShadeLimits;
SeriesEditor.AddSeries(pSeries.Name, ASP);
end;
SeriesEditor.NoComboBox.ItemIndex := TheSeries;
SeriesEditor.SelectSeries(TheSeries);
SeriesEditor.HelpFile := FHelpFile;
if (SeriesEditor.ShowModal = mrOK) then
ApplySeriesChange(SeriesEditor);
SeriesEditor.Free;
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ApplySeriesChange
Description: This applies changes from the SeriesEditor Dialog.
Author: Mat Ballard
Date created: 03/28/2001
Date modified: 03/28/2001 by Mat Ballard
Purpose: User interface management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ApplySeriesChange(Sender: TObject);
var
i: Integer;
pSeries: TSeries;
pASP: ^TSeriesProperty;
begin
for i := 0 to FSeriesList.Count-1 do
begin
pASP := TSeriesEditorForm(Sender).SeriesPropertyList.Items[i];
pSeries := TSeries(FSeriesList.Items[i]);
pSeries.Pen.Color := pASP^.PenColor;
pSeries.Pen.Width := pASP^.PenWidthIndex;
pSeries.Pen.Style := TPenStyle(pASP^.PenStyleIndex);
pSeries.Brush.Color := pASP^.BrushColor;
pSeries.Brush.Style := TBrushStyle(pASP.BrushStyleIndex);
pSeries.Symbol := TSymbol(pASP^.SymbolIndex);
pSeries.SymbolSize := pASP^.SymbolSize;
pSeries.YAxisIndex := pASP^.YAxisIndex;
pSeries.DeltaX := pASP^.DeltaX;
pSeries.DeltaY := pASP^.DeltaY;
pSeries.Visible := pASP^.Visible;
pSeries.Name := TSeriesEditorForm(Sender).SeriesNames.Strings[i];
pSeries.ShadeLimits := pASP^.ShadeLimits;
if ((pASP^.XDataIndependent) and (pSeries.ExternalXSeries)) then
begin
{this series did depend on X Data in another series,
but user wants to make it independent:}
pSeries.MakeXDataIndependent;
end;
end; {for}
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ResetDisplacementClick
Description: Puts the selected Axis back where it came from
Author: Mat Ballard
Date created: 12/1/1999
Date modified: 02/25/2000 by Mat Ballard
Purpose: sets the DeltaX and DeltaY properties of the selected Axis to ZeroScreenStuff
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ResetDisplacementClick(
Sender: TObject);
begin
if (GetSeriesFromUser) then
begin
pSeries.DeltaX := 0;
pSeries.DeltaY := 0;
DoStyleChange(Self);
end;
ZeroScreenStuff;
end;
{File manipulation ------------------------------------------------------------}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.NewClick
Description: Creates a new, blank Graph
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: data management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.NewClick(
Sender: TObject);
begin
Self.Clear(TRUE);
end;
{------------------------------------------------------------------------------
Procedure: TPlot.Notification
Description: needed for D1
Author: Mat Ballard
Date created: 09/07/2000
Date modified: 09/07/2000 by Mat Ballard
Purpose:
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.Notification(AComponent: TComponent;
Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
{if (Operation = opRemove) and (AComponent = Plot) then
begin
Plot := nil;
end;}
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.OpenClick
Description: Opens a file on disk
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs the File Open common dialog then the LoadFromFile method
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.OpenClick(
Sender: TObject);
var
OpenDialog: TOpenDialog;
begin
{We have to display a File Open Dialog:}
OpenDialog := TOpenDialog.Create(Self);
OpenDialog.Title := sOpen;
OpenDialog.Filter := FileTypes;
OpenDialog.Options := [ofOverwritePrompt];
if (Length(FFileName) = 0) then
begin
FileName := '*.' + FDefaultExtension;
end;
OpenFilterIndex := GetFilterIndex(GetFileExtension);
OpenDialog.FilterIndex := OpenFilterIndex;
OpenDialog.FileName := '*.' + GetFileExtension;
if (Length(OpenDriveDir) > 0) then
OpenDialog.InitialDir := ExtractFileName(OpenDriveDir)
else
OpenDialog.InitialDir := GetFileDriveDir;
if (OpenDialog.Execute) then
begin
OpenFile(OpenDialog.FileName);
OpenFilterIndex := OpenDialog.FilterIndex;
end;
OpenDialog.Free;
//ZoomOutClick(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.OpenFile
Description: Opens a file on disk
Author: Mat Ballard
Date created: 08/12/2000
Date modified: 08/12/2000 by Mat Ballard
Purpose: Called from TPlotMenu.HandleFileClick
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.OpenFile(
TheFile: String);
begin
if (FileExists(TheFile)) then
begin
{Delete any existing Series:}
Clear(FALSE);
FileName := TheFile;
OpenDriveDir := ExtractFilePath(FFileName);
{Finally, Open it:}
LoadFromFile(FFileName);
DoFileOpen(FFileName);
end;
ZoomOutClick(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DoFileOpen
Description: Fires the OnFileOpen event
Author: Mat Ballard
Date created: 09/07/2000
Date modified: 09/07/2000 by Mat Ballard
Purpose:
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DoFileOpen(AFileName: String);
begin
if Assigned(FOnFileOpen) then
OnFileOpen(Self, AFileName);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ClearOverlaysClick
Description: Gets rid of the overlaid data
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs the FSeriesList.Delete method for each overlaid Axis
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ClearOverlaysClick(
Sender: TObject);
var
i: Integer;
begin
if (FirstOverlay < 0) then raise
EComponentError.Create(sClearOverlaysClick1);
for i := FSeriesList.Count-1 downto FirstOverlay do
begin
TSeries(FSeriesList.Items[i]).Free;
FSeriesList.Delete(i);
end;
FirstOverlay := -1;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.OverlayDataClick
Description: Overlays data
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs the Open common dialog, then LoadFromFile the selected files
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.OverlayClick(
Sender: TObject);
var
i: Integer;
OverlayDialog: TOpenDialog;
begin
{We have to display a File Overlay Dialog:}
OverlayDialog := TOpenDialog.Create(Self);
OverlayDialog.Title := sOverlay1;
OverlayDialog.Filter := FileTypes;
OverlayDialog.Options :=
[ofFileMustExist, ofPathMustExist, ofAllowMultiSelect];
OverlayDialog.FileName := '*.' + FDefaultExtension;
OverlayDialog.FilterIndex := OpenFilterIndex;
if (Length(OverlayDriveDir) > 0) then
OverlayDialog.InitialDir := ExtractFileName(OpenDriveDir)
else
OverlayDialog.InitialDir := GetFileDriveDir;
if (OverlayDialog.Execute) then
begin
FirstOverlay := FSeriesList.Count;
for i := 0 to OverlayDialog.Files.Count - 1 do
begin
OverlayDriveDir := ExtractFileName(OverlayDialog.Files.Strings[i]);
{Finally, Overlay it:}
Self.LoadFromFile(OverlayDialog.Files.Strings[i]);
end;
end;
OverlayDialog.Free;
ZoomOutClick(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SaveImageClick
Description: saves the current plot as an image
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: responds to "Save Image" menu selection
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SaveImageClick(Sender: TObject);
var
SaveImageDialog: TSaveDialog;
Extension, ImageName: String;
begin
{We have to display a File Save Dialog:}
SaveImageDialog := TSaveDialog.Create(Self);
SaveImageDialog.Title := sSaveImage1;
SaveImageDialog.Filter := PICTURE_TYPES;
SaveImageDialog.Options := [ofOverwritePrompt];
if (Length(ImageDriveDir) = 0) then
if (Length(FFileName) > 0) then
ImageDriveDir := GetFileDriveDir;
SaveImageDialog.FilterIndex := ImageFilterIndex;
{which starts off at zero, then may change}
if (Length(FFileName) > 0) then
begin
SaveImageDialog.FileName :=
GetFileRoot + '.' + ImageExtensions[ImageFilterIndex-1];
end
else
begin
SaveImageDialog.FileName :=
'*.' + ImageExtensions[ImageFilterIndex-1];
end;
SaveImageDialog.InitialDir := ImageDriveDir;
if (SaveImageDialog.Execute) then
begin
ImageName := SaveImageDialog.FileName;
ImageDriveDir := ExtractFilePath(ImageName);
Extension := LowerCase(ExtractFileExt(ImageName));
if (Length(Extension) = 0) then
begin
Extension := '.' +
ImageExtensions[SaveImageDialog.FilterIndex-1];
ImageName := ImageName + Extension;
end;
{Finally, save it:}
{We base this on the extension, rather than FilterIndex:}
if (Extension = '.bmp') then
begin
ImageFilterIndex := 3;
SaveAsBitMap(ImageName);
end;
{.$ IFDEF MSWINDOWS}
if (Extension = '.wmf') then
begin
ImageFilterIndex := 1;
SaveAsDrawing(ImageName);
end
else if (Extension = '.emf') then
begin
ImageFilterIndex := 2;
SaveAsDrawing(ImageName);
end;
{.$ ENDIF}
{$IFDEF GIF}
if (Extension = '.gif') then
begin
ImageFilterIndex := 4;
SaveAsGIF(ImageName);
end;
{$ENDIF}
{$IFDEF PNG}
if (Extension = '.png') then
begin
ImageFilterIndex := 5;
SaveAsPNG(ImageName);
end;
{$ENDIF}
end;
SaveImageDialog.Free;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SaveClick
Description: Saves the graph
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs SaveToFile or SaveAsClick
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SaveClick(Sender: TObject);
begin
if (Length(FFileName) > 0) then
SaveToFile(FFileName)
else
SaveAsClick(Sender);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SaveAsClick
Description: Saves the data to disk
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs the Save common dialog box then SaveToFile
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SaveAsClick(Sender: TObject);
var
Ext: String;
SaveDialog: TSaveDialog;
begin
{We have to display a File Save Dialog:}
SaveDialog := TSaveDialog.Create(Self);
SaveDialog.Title := sSaveAs1;
SaveDialog.Filter := FileTypes;
SaveDialog.Options := [ofOverwritePrompt];
if (Length(FFileName) = 0) then
begin
FileName := '*.' + FDefaultExtension;
end;
SaveFilterIndex := GetFilterIndex(GetFileExtension);
SaveDialog.FilterIndex := SaveFilterIndex;
SaveDialog.InitialDir := GetFileDriveDir;
SaveDialog.FileName := ExtractFileName(FFileName);
if (SaveDialog.Execute) then
begin
FileName := SaveDialog.FileName;
Ext := GetFileExtension;
if (Length(Ext) = 0) then
begin
Ext := FileExtensions[SaveDialog.FilterIndex];
FileName := FileName + '.' + Ext;
end;
{Double-whammy problem: save with 'plot'extension, but different filter,
should save in that (text) format.
Save with other extension, but FilterIndex=0 (plot type), then extension
should override, so also save in text.}
if ((Ext = FileExtensions[0]) and (SaveDialog.FilterIndex = 1)) then
begin {.plot}
SaveFilterIndex := 1;
FAsText := FALSE or (soAsText in FSaveOptions);
end {.plot}
else if ((Ext = FileExtensions[0]) and (SaveDialog.FilterIndex > 1)) then
begin {'plot' extension, text type}
SaveFilterIndex := 1;
FAsText := TRUE;
end {'plot' extension, text type}
else if (Ext = FileExtensions[1]) then
begin {.csv}
SaveFilterIndex := 2;
FAsText := TRUE;
end {.csv}
else if (Ext = FileExtensions[2]) then
begin
SaveFilterIndex := 3;
FAsText := TRUE;
end {.txt}
else
begin
SaveFilterIndex := 4;
FAsText := TRUE;
end; {.*}
{Finally, save it:}
Self.SaveToFile(FFileName);
SaveFilterIndex := SaveDialog.FilterIndex;
end;
SaveDialog.Free;
end;
{Saving data to disk --------------------------------------------------------}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.LoadFromFile
Description: Opens data on disk
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Opens the data and feeds it into LoadFromStream
Known Issues: Can be called by either OpenClick or OverlayClick
------------------------------------------------------------------------------}
procedure TCustomPlot.LoadFromFile(
AFileName: String);
var
TheStream: TMemoryStream;
begin
TheStream := TMemoryStream.Create;
try
TheStream.LoadFromFile(AFileName);
Self.LoadFromStream(TheStream);
finally
TheStream.Free;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.LoadFromStream
Description: Opens data on disk
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Opens data, parses it, fires the OnHeader event, and runs ConvertTextData,
or decides to run it through ParseData instead
Known Issues: Can be called by either OpenClick or OverlayClick
------------------------------------------------------------------------------}
procedure TCustomPlot.LoadFromStream(
AStream: TMemoryStream);
var
TheResult: Boolean;
TheStrings: TStringList;
OldIgnoreChanges: Boolean;
function IsPlotFile: Boolean;
var
FileVersion: Integer;
TheLine: String;
begin
IsPlotFile := FALSE;
{Line the first:}
TheLine := ReadLine(AStream);
if (Pos('TPlot', TheLine) = 0) then exit;
{Line the second:}
TheLine := ReadLine(AStream);
if (Pos('FileFormat', TheLine) = 0) then exit;
GetWord(TheLine, '=');
FileVersion := StrToInt(TheLine);
if (FileVersion > MAX_FILE_VERSION) then exit;
FTitle.Caption := ReadLine(AStream);
{Now comes the developer-defined header:}
DoHeader(AStream);
TheLine := ReadLine(AStream);
if (TheLine <> SUBHEADER) then
begin
{either a stuffed file, or the developer has done a naughty
and overrun his own header; we therefore try to find it from the beginning,
then reset the srteam position:}
AStream.Position := 0;
if (not (FindStringInStream(SUBHEADER, AStream))) then exit;
TheLine := ReadLine(AStream);
end;
IsPlotFile := TRUE;
end;
begin
OldIgnoreChanges := IgnoreChanges;
IgnoreChanges := TRUE;
if (IsPlotFile) then
begin
TheResult := FSeriesList.LoadFromStream(AStream, FAsText);
end
else
begin
{maybe it's just a text file:}
AStream.Seek(0, soFromBeginning);
TheStrings := TStringList.Create;
try
TheStrings.LoadFromStream(AStream);
TheResult := FSeriesList.ParseData(TheStrings, FHelpFile);
{FAsText := TRUE;}
finally
if (TheStrings <> nil) then
TheStrings.Free;
end;
end; {IsPlotFile}
if (TheResult) then OpenProperties('');
IgnoreChanges := OldIgnoreChanges;
ZoomOutClick(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DoHeader
Description: Informs the user of a user-defined file header
Author: Mat Ballard
Date created: 09/07/2000
Date modified: 09/07/2000 by Mat Ballard
Purpose: Fires the OnHeader event
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DoHeader(TheStream: TMemoryStream);
begin
if assigned(FOnHeader) then
OnHeader(Self, TheStream);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SaveToFile
Description: Saves the data as text
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 03/07/2001 by Mat Ballard
Purpose: Fires the OnHeaderRequest event, then the GetData of SeriesList
Known Issues:
Comment: Note that we now use a TStream.
------------------------------------------------------------------------------}
procedure TCustomPlot.SaveToFile(
AFileName: String);
var
TheStream: TMemoryStream;
begin
TheStream := TMemoryStream.Create;
{create the data in binary or text format:}
Self.SaveToStream(TheStream);
{determine the file name:}
if (Length(AFileName) > 0) then
SetFileName(AFileName);
{save it:}
TheStream.SaveToFile(FFileName);
TheStream.Free;
if (soProperties in FSaveOptions) then
SaveTheProperties('');
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SaveToStream
Description: Saves the data as text
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 03/07/2001 by Mat Ballard
Purpose: Fires the OnHeaderRequest event, then the GetData of SeriesList
Known Issues:
Comment: Note that we now use a TStream.
------------------------------------------------------------------------------}
procedure TCustomPlot.SaveToStream(var TheStream: TMemoryStream);
var
pLine: array [0..1023] of char;
begin
if (TheStream = nil) then
TheStream := TMemoryStream.Create;
{D1 does not like Pointer(TheLine)^:
TheLine := 'TPlot=' + IntToStr(TPLOT_VERSION) + CRLF;
TheStream.Write(Pointer(TheLine)^, Length(TheLine));
so:}
StrPCopy(pLine, 'TPlot=' + IntToStr(TPLOT_VERSION) + CRLF);
TheStream.Write(pLine, StrLen(pLine));
StrPCopy(pLine, 'FileFormat=' + IntToStr(FILE_FORMAT_VERSION) + CRLF);
TheStream.Write(pLine, StrLen(pLine));
StrPCopy(pLine, FTitle.Caption + CRLF);
TheStream.Write(pLine, StrLen(pLine));
DoHeaderRequest(TheStream);
StrPCopy(pLine, SUBHEADER + CRLF);
TheStream.Write(pLine, StrLen(pLine));
{create the data in binary or text format:}
FSeriesList.GetStream(FAsText, ',', TheStream);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DoHeaderRequest
Description: Asks the user for a header
Author: Mat Ballard
Date created: 09/07/2000
Date modified: 09/07/2000 by Mat Ballard
Purpose: Fires the OnHeaderRequest event
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DoHeaderRequest(TheStream: TMemoryStream);
begin
if assigned(FOnHeaderRequest) then
OnHeaderRequest(Self, TheStream);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.OpenProperties
Description: Opens the properties of this instance of TPlot
Author: Mat Ballard
Date created: 08/03/2000
Date modified: 08/03/2000 by Mat Ballard
Purpose: Saves the appearance of the Plot
Known Issues:
Comment: Note that if AFileName is blank, we use a name generated from
the FileName property (in SetFileName).
------------------------------------------------------------------------------}
procedure TCustomPlot.OpenProperties(AFileName: String);
var
FileStream: TFileStream;
OldIgnoreChanges: Boolean;
begin
if (Length(AFileName) > 0) then
PropsFileName := AFileName;
if (FileExists(PropsFileName)) then
begin
OldIgnoreChanges := IgnoreChanges;
IgnoreChanges := TRUE;
FileStream := TFileStream.Create(PropsFileName, fmOpenRead + fmShareDenyWrite);
try
{This is what causes multiple screen redraws. But why ?}
FileStream.ReadComponent(Self);
{The following dont work; TAxis descends from TPersistent !
for i := 2 to FAxisList.Count-1 do
begin
TAxis(FAxisList[i]).ReadComponent(TAxis(FAxisList[i]));
end;}
finally
IgnoreChanges := OldIgnoreChanges;
FileStream.Free;
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SaveTheProperties
Description: Saves the properties of this instance of TPlot
Author: Mat Ballard
Date created: 08/03/2000
Date modified: 08/03/2000 by Mat Ballard
Purpose: Saves the appearance of the Plot
Known Issues:
Comment: Note that if AFileName is blank, we use a name generated from
the FileName property (in SetFileName).
------------------------------------------------------------------------------}
procedure TCustomPlot.SaveTheProperties(AFileName: String);
var
FileStream: TFileStream;
begin
if (Length(AFileName) > 0) then
PropsFileName := AFileName;
FileStream := TFileStream.Create(PropsFileName, fmCreate or fmShareExclusive);
FileStream.WriteComponent(Self);
{The following dont work; TAxis descends from TPersistent !
for i := 2 to FAxisList.Count-1 do
begin
TAxis(FAxisList[i]).WriteComponent(TAxis(FAxisList[i]));
end;}
FileStream.Free;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.AppendToFile
Description: Appends the data to FileName
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs the GetData method of SeriesList, then the Append method of the new TFileList
Known Issues: Needs work on GetData and testing
------------------------------------------------------------------------------}
procedure TCustomPlot.AppendToFile;
var
TheStream: TMemoryStreamEx;
begin
if (FileExists(FFileName)) then
begin
{create the FileList, an extension of TStringList:}
TheStream := TMemoryStreamEx.Create;
{create the data in text format:}
FSeriesList.AppendStream((soAsText in FSaveOptions), ',', TheStream);
{save it:}
TheStream.AppendToFile(FFileName);
TheStream.Free;
end
else
begin
EComponentError.Create('TCustomPlot.AppendToFile: ' + FFileName + sDoesNoTExist);
end;
end;
{Copying data to the clipboard ----------------------------------------------}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CopyHTML
Description: Copies data as HTML to Clipboard
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Creates a Header, fires the OnHTMLHeaderRequest event, then runs
the DataAsHTMLTable method of SeriesList
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.CopyHTML(Format: Word);
var
i: Integer;
TheData,
TheHeader: TStringList;
{$IFDEF DELPHI1}
pLine: array [0..1023] of char;
{$ENDIF}
{$IFDEF MSWINDOWS}
Size,
LineLength: LongInt;
pText,
TextPtr: PChar;
TextHandle: THandle;
{$ENDIF}
begin
TheHeader := TStringList.Create;
TheHeader.Add('<html>');
TheHeader.Add('<head>');
TheHeader.Add('<title>' + FTitle.Caption + '</title>');
TheHeader.Add('</head>');
TheHeader.Add('<body bgcolor="white">');
TheHeader.Add('<h1>' + FTitle.Caption + '</h1>');
TheHeader.Add('<p>');
DoHTMLHeaderRequest(TheHeader);
TheData := TStringList.Create;
{create the data in text format:}
FSeriesList.DataAsHTMLTable(TheData);
{insert the header:}
for i := 0 to TheHeader.Count-1 do
TheData.Insert(0, TheHeader[i]);
{$IFDEF MSWINDOWS}
{Calculate the size:}
Size := 8;
for i := 0 to TheData.Count-1 do
Inc(Size, Length(TheData[i])+2);
{save it:}
TextHandle := GlobalAlloc(GMEM_MOVEABLE, Size);
TextPtr := GlobalLock(TextHandle);
pText := TextPtr;
for i := 0 to TheData.Count - 1 do
begin
LineLength := Length(TheData[i]);
if LineLength <> 0 then
begin
{$IFDEF DELPHI1}
StrPCopy(pLine, TheData[i]);
System.Move(pLine, pText^, LineLength);
{$ELSE}
{for some unknown reason, this Move works !}
System.Move(Pointer(TheData[i])^, pText^, LineLength);
{$ENDIF}
Inc(pText, LineLength);
end;
pText^ := #13;
Inc(pText);
pText^ := #10;
Inc(pText);
end;
{we need to use SetAsHandle because Format may be CF_HTML:}
ClipBoard.SetAsHandle(Format, TextHandle);
GlobalUnlock(TextHandle);
{$ENDIF}
{$IFDEF LINUX}
Clipboard.AsText := TheData.Text;
{$ENDIF}
TheHeader.Free;
TheData.Free;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DoHTMLHeaderRequest
Description: Asks the user for their HTML header data
Author: Mat Ballard
Date created: 09/07/2000
Date modified: 09/07/2000 by Mat Ballard
Purpose: fires the OnHTMLHeaderRequest event
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DoHTMLHeaderRequest(TheHeader: TStringList);
begin
if assigned(FOnHTMLHeaderRequest) then
OnHTMLHeaderRequest(Self, TheHeader);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CopyText
Description: Copies data as tab-delimited text to Clipboard
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Creates a Header, fires the OnHeaderRequest event, then runs the GetData method of SeriesList
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.CopyText;
var
TheStream: TMemoryStream;
pLine: array [0..1023] of char;
{$IFDEF MSWINDOWS}
TextPtr: Pointer;
TextHandle: THandle;
{$ENDIF}
{$IFDEF LINUX}
TheText: TStringList;
{$ENDIF}
begin
StrPCopy(pLine, FTitle.Caption + CRLF);
TheStream := TMemoryStream.Create;
TheStream.Write(pLine, StrLen(pLine));
DoHeaderRequest(TheStream);
{create the data in TEXT format:}
FSeriesList.GetStream(TRUE, #9, TheStream);
{save it:}
{$IFDEF MSWINDOWS}
TextHandle := GlobalAlloc(GMEM_MOVEABLE, TheStream.Size+1);
TextPtr := GlobalLock(TextHandle);
{for some unknown reason, this Move works !}
System.Move(TheStream.Memory^, TextPtr^, TheStream.Size);
ClipBoard.SetAsHandle(CF_TEXT, TextHandle);
GlobalUnlock(TextHandle);
{$ENDIF}
{$IFDEF LINUX}
TheText := TStringList.Create;
TheText.LoadFromStream(TheStream);
ClipBoard.AsText := TheText.Text;
TheText.Free;
{$ENDIF}
TheStream.Free;
end;
{Copying picture to the clipboard -------------------------------------------}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CopyBitmap
Description: Copies a picture of the graph as a bitmap to the Clipboard
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs Draw method over Bitmap then copies Bitmap
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.CopyBitmap;
begin
ClipBoard.Assign(Self.BitMap);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.GetBitmap
Description: Returns a picture of the graph as a bitmap
Author: Mat Ballard
Date created: 04/25/2001
Date modified: 04/25/2001 by Mat Ballard
Purpose: Runs Draw method over Bitmap
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetBitmap: TBitmap;
var
Rect: TRect;
begin
Rect := GetClientRect;
Result := TBitMap.Create;
Result.Height := Rect.Bottom - Rect.Top;
Result.Width := Rect.Right - Rect.Left;
Draw(Result.Canvas);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SaveAsBitmap
Description: Saves a picture of the graph as a bitmap
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs Draw method over Bitmap then saves Bitmap
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SaveAsBitmap(
AFileName: String);
begin
Self.Bitmap.SaveToFile(AFileName);
end;
{------------------------------------------------------------------------------
Function: TCustomPlot.GetDrawing
Description: Returns a picture of the graph as a Windows Metafile to the Clipboard
Author: Mat Ballard
Date created: 05/16/2001
Date modified: 05/16/2001 by Mat Ballard
Purpose: developer rendering image of TPlot
Known Issues:
------------------------------------------------------------------------------}
{$IFDEF MSWINDOWS}
function TCustomPlot.GetDrawing: TMetafile;
var
AMetafileCanvas: TMetafileCanvas;
Rect: TRect;
begin
Rect := GetClientRect;
Result := TMetafile.Create;
{$IFDEF COMPILER3_UP}
Result.Enhanced := TRUE;
{$ENDIF}
Result.Height := Rect.Bottom - Rect.Top;
Result.Width := Rect.Right - Rect.Left;
{$IFDEF DELPHI1}
{create the metafile canvas to draw on:}
AMetafileCanvas :=
TMetafileCanvas.Create(Result, 0);
{$ELSE}
SetMetafileDescription;
{create the metafile canvas to draw on:}
AMetafileCanvas :=
TMetafileCanvas.CreateWithComment(Result, 0, FCreatedBy, FDescription);
{$ENDIF}
{draw the graph on the metafile:}
Draw(AMetafileCanvas);
AMetafileCanvas.Free;
end;
{$ENDIF}
{$IFDEF LINUX}
function TCustomPlot.GetDrawing: TDrawing;
var
Rect: TRect;
begin
Rect := GetClientRect;
Result := TDrawing.Create;
Result.Height := Rect.Bottom - Rect.Top;
Result.Width := Rect.Right - Rect.Left;
Result.Canvas.Start;
try
Draw(Result.Canvas);
finally
Result.Canvas.Stop;
end;
end;
{$ENDIF}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CopyDrawing
Description: Copies a picture of the graph as a Windows Metafile to the Clipboard
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs Draw method over AMetafileCanvas then copies Metafile
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.CopyDrawing(Enhanced: Boolean);
{$IFDEF MSWINDOWS}
var
AFormat: Word;
AData: THandle;
APalette: HPALETTE;
begin
Self.Drawing.SaveToClipboardFormat(AFormat, AData, APalette);
ClipBoard.SetAsHandle(AFormat, AData);
{$ENDIF}
{$IFDEF LINUX}
begin
Clipboard.Assign(Self.Drawing);
{$ENDIF}
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SaveAsDrawing
Description: Saves a picture of the graph as a Windows Metafile
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs Draw method over Metafile Canvas then saves Metafile
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SaveAsDrawing(
AFileName: String);
begin
Self.Drawing.SaveToFile(AFileName);
end;
{$IFDEF GIF}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SaveAsGIF
Description: Saves a picture of the graph as a GIF file
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs Draw method over ABitmap of AGifImage then saves AGifImage
Known Issues: 1. Requires Anders Melander's TGifImage
2. Package dependency problems means that it is easier to let end users add this functionality
------------------------------------------------------------------------------}
function TCustomPlot.GetGIF: TGIFImage;
var
Rect: TRect;
ABitMap: TBitMap;
begin
Rect := GetClientRect;
ABitMap := TBitMap.Create;
ABitMap.PixelFormat := pf24bit;
ABitMap.Height := Rect.Bottom - Rect.Top;
ABitMap.Width := Rect.Right - Rect.Left;
Self.Draw(ABitMap.Canvas);
Result := TGIFImage.Create;
Result.Assign(ABitMap);
ABitMap.Free;
end;
procedure TCustomPlot.SaveAsGIF(
AFileName: String);
begin
Self.GIF.SaveToFile(AFileName);
end;
{$ENDIF}
{$IFDEF PNG}
{$IFDEF MSWINDOWS}
function TCustomPlot.GetPNG: TPngimage;
var
Rect: TRect;
ABitmap: TBitmap;
begin
Rect := GetClientRect;
ABitmap := TBitmap.Create;
{We need 24 bit otherwise the 8 bit PNG renders white as black !}
ABitmap.PixelFormat := pf24bit;
ABitmap.Height := Rect.Bottom - Rect.Top;
ABitmap.Width := Rect.Right - Rect.Left;
Draw(ABitmap.Canvas);
Result := TPngimage.Create;
Result.Title := FTitle.Caption;
Result.Author := FCreatedBy;
Result.Description := FDescription;
Result.Software := ExtractFileName(Application.ExeName);
Result.CopyFromBmp(ABitmap);
ABitmap.Free;
end;
{$ENDIF}
{$IFDEF LINUX}
function TCustomPlot.GetPNG: TBitmap;
var
Rect: TRect;
begin
Rect := GetClientRect;
Result := TBitMap.Create;
Result.Format := 'PNG';
Result.Height := Rect.Bottom - Rect.Top;
Result.Width := Rect.Right - Rect.Left;
Draw(Result.Canvas);
end;
{$ENDIF}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SaveAsPNG
Description: Saves a picture of the graph as a PNG file
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs Draw method over ABitmap of APngImage then saves APngImage
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SaveAsPng(
AFileName: String);
begin
Self.Png.SaveToFile(AFileName);
end;
{$ENDIF}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetAsNormalClick
Description: Defines the current view == Mins and Maxes of axes, as the Normal view.
Author: Mat Ballard
Date created: 08/12/2000
Date modified: 08/12/2000 by Mat Ballard
Purpose: Zoom == Axis Min/Max management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetAsNormalClick(Sender: TObject);
var
i: Integer;
pTheAxis: TAxis;
begin
for i := 0 to FAxisList.Count-1 do
begin
pTheAxis := TAxis(FAxisList.Items[i]);
pTheAxis.ZoomIntercept := pTheAxis.Intercept;
pTheAxis.ZoomMin := pTheAxis.Min;
pTheAxis.ZoomMax := pTheAxis.Max;
end;
FPlotPopUpMenu.Items[Ord(mnuView)].Items[Ord(mnuNormal)].Enabled := TRUE;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.NormalViewClick
Description: Zooms to the Normal view
Author: Mat Ballard
Date created: 08/12/2000
Date modified: 08/12/2000 by Mat Ballard
Purpose: Zoom == Axis Min/Max management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.NormalViewClick(Sender: TObject);
var
i: Integer;
pTheAxis: TAxis;
begin
for i := 0 to FAxisList.Count-1 do
begin
pTheAxis := TAxis(FAxisList.Items[i]);
if (pTheAxis.ZoomMin < pTheAxis.ZoomMax) then
begin
pTheAxis.Min := pTheAxis.ZoomMin;
pTheAxis.Max := pTheAxis.ZoomMax;
pTheAxis.Intercept := pTheAxis.ZoomIntercept;
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ManualZoomClick
Description: Manually Zooms In
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs the ZoomForm and adjusts Axes accordingly
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ManualZoomClick(Sender: TObject);
var
ZoomForm: TZoomForm;
begin
ZoomForm := TZoomForm.Create(Self);
ZoomForm.ThePlot := Self;
ZoomForm.XMinNEdit.AsReal := FXAxis.Min;
ZoomForm.XMaxNEdit.AsReal := FXAxis.Max;
ZoomForm.YMinNEdit.AsReal := FYAxis.Min;
ZoomForm.YMaxNEdit.AsReal := FYAxis.Max;
ZoomForm.HelpFile := FHelpFile;
if (ZoomForm.ShowModal = mrOK) then
ApplyZoom(ZoomForm);
ZoomForm.Free;
Refresh;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ApplyZoom
Description: Manually Zooms In
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Runs the ZoomForm and adjusts Axes accordingly
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ApplyZoom(Sender: TObject);
var
i,
PixelYMin,
PixelYMax: Integer;
pTheYAxis: TAxis;
begin
FXAxis.Min := TZoomForm(Sender).XMinNEdit.AsReal;
FXAxis.Max := TZoomForm(Sender).XMaxNEdit.AsReal;
FYAxis.Min := TZoomForm(Sender).YMinNEdit.AsReal;
FYAxis.Max := TZoomForm(Sender).YMaxNEdit.AsReal;
PixelYMin := FYAxis.FofY(FYAxis.Min);
PixelYMax := FYAxis.FofY(FYAxis.Max);
for i := 2 to FAxisList.Count-1 do
begin
pTheYAxis := TAxis(FAxisList[i]);
pTheYAxis.Min := pTheYAxis.YofF(PixelYMin);
pTheYAxis.Max := pTheYAxis.YofF(PixelYMax);
end;
Refresh;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ZoomOutClick
Description: Zooms out after Zooming In
Author: Mat Ballard
Date created: 02/25/2000
Date modified: 02/25/2000 by Mat Ballard
Purpose: Resets the axes Min and Max values to those of the Axis
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ZoomOutClick(Sender: TObject);
var
i: Integer;
pSeries: TSeries;
begin
FXAxis.Min := FSeriesList.Xmin;
FXAxis.Max := FSeriesList.Xmax;
FYAxis.Intercept := FXAxis.Min;
{ for i := 1 to FAxisList.Count-1 do
begin
TAxis(FAxisList[i]).Visible := FALSE;
end;}
case FPlotType of
ptXY, ptMultiple:
begin
for i := 0 to FSeriesList.Count-1 do
begin
pSeries := FSeriesList[i];
pSeries.YAxis.Min := pSeries.YMin;
pSeries.YAxis.Max := pSeries.YMax;
{if (pSeries.YAxis.Min > Round(pSeries.YMin - 0.999)) then
pSeries.YAxis.Min := Round(pSeries.YMin - 0.999);
if (pSeries.YAxis.Max < Round(pSeries.YMax + 0.999)) then
pSeries.YAxis.Max := Round(pSeries.YMax + 0.999);}
end;
end;
ptError, ptBubble:
begin
for i := 0 to FSeriesList.Count-1 do
begin
if ((i mod 2) = 0) then
begin {odd series are just error - not values}
pSeries := FSeriesList[i];
pSeries.YAxis.Min := pSeries.YMin;
pSeries.YAxis.Max := pSeries.YMax;
{if (pSeries.YAxis.Min > Round(FSeriesList.YErrorMin - 0.999)) then
pSeries.YAxis.Min := Round(FSeriesList.YErrorMin - 0.999);
if (pSeries.YAxis.Max < Round(FSeriesList.YErrorMax + 0.999)) then
pSeries.YAxis.Max := Round(FSeriesList.YErrorMax + 0.999);}
end;
end;
end;
ptColumn:
begin
for i := 1 to FAxisList.Count-1 do
TAxis(FAxisList[i]).Min := 0;
for i := 0 to FSeriesList.Count-1 do
begin
pSeries := FSeriesList[i];
if (pSeries.YAxis.Max < Round(pSeries.YMax + 0.999)) then
pSeries.YAxis.Max := Round(pSeries.YMax + 0.999);
end;
end;
ptStack:
begin
YAxis.Min := 0;
if (FSeriesList.TotalNoPts > 0) then
YAxis.Max := Round(FSeriesList.Count * FSeriesList.Ymax + 0.999);
end;
ptNormStack:
begin
for i := 1 to FAxisList.Count-1 do
begin
TAxis(FAxisList[i]).Min := 0;
TAxis(FAxisList[i]).Max := 100;
end;
end;
ptPolar:
begin
FXAxis.Min := Round(FSeriesList.Xmin - 0.999);
FXAxis.Max := Round(FSeriesList.Xmax + 0.999);
FYAxis.Min := Round(FSeriesList.Ymin - 0.999);
FYAxis.Max := Round(FSeriesList.Ymax + 0.999);
if (FXAxis.Min > -FXAxis.Max) then
FXAxis.Min := -FXAxis.Max;
if (FXAxis.Max < -FXAxis.Min) then
FXAxis.Max := -FXAxis.Min;
if (FYAxis.Min > -FYAxis.Max) then
FYAxis.Min := -FYAxis.Max;
if (FYAxis.Max < -FYAxis.Min) then
FYAxis.Max := -FYAxis.Min;
FXAxis.Intercept := 0;
FYAxis.Intercept := 0;
end;
ptLineContour:
begin
FContourStart := FSeriesList.Ymin;
FContourInterval := (FSeriesList.Ymax - FContourStart) / 10;
end;
pt3DContour, pt3DWire, pt3DColumn:
begin
FYAxis.Min := FSeriesList.Ymin;
FYAxis.Max := FSeriesList.Ymax;
FZAxis.Min := FSeriesList.Zmin;
FZAxis.Max := FSeriesList.Zmax;
end;
end; {case}
FXAxis.Intercept := FYAxis.Min;
DestroyPageButtons;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.CopyHTMLClick
Description: copys the data as HTML
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: ... in CF_TEXT format
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.CopyHTMLClick(Sender: TObject);
begin
CopyHTML(CF_TEXT);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.HandleClick
Description: fires the OnClick event of the menuitem with Tag Tag
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: allows the TPlotMenu component to function
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.HandleClick(Sender: TObject; TheTag: Integer);
var
i, j: Integer;
begin
{needed to handle Mode and Direction:}
FMenuTag := TheTag;
if (GetIndicesFromTag(TheTag, i, j)) then
{$IFDEF COMPILER2_UP}
if Assigned(FPlotPopUpMenu.Items[i].Items[j].OnClick) then
{$ENDIF}
FPlotPopUpMenu.Items[i].Items[j].OnClick(Sender);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.GetIndicesFromTag
Description: Gets the i and j indices from the Tag
Author: Mat Ballard
Date created: 05/25/2000
Date modified: 05/25/2000 by Mat Ballard
Purpose: interfacing with external components
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetIndicesFromTag(TheTag: Integer; var i, j: Integer): Boolean;
var
MenuIndex: Integer;
TheResult: Boolean;
begin
{TPlotToolBar throws some strange tags at this function:
if (TheTag <= TAG_BASE) then raise
ERangeError.CreateFmt('GetIndicesFromTag: ' + sInvalidTag, [Tag]);}
TheResult := FALSE;
MenuIndex := TheTag - TAG_BASE - Ord(High(TMainMenus)){mnuCalc} - 2;
if ((MenuIndex >= 0) and (MenuIndex <= Ord(High(TFileMenus)){mnuPrint})) then
begin
i := 0;
j := MenuIndex;
TheResult := TRUE;
end
else
begin
MenuIndex := MenuIndex - Ord(High(TFileMenus)){mnuPrint} - 1;
if ((MenuIndex >= 0) and (MenuIndex <= Ord(High(TEditMenus)))) then
begin
i := 1;
j := MenuIndex;
TheResult := TRUE;
end
else
begin
MenuIndex := MenuIndex - Ord(High(TEditMenus)){mnuEditProperties} - 1;
if ((MenuIndex >= 0) and (MenuIndex <= Ord(High(TViewMenus)))) then
begin
i := 2;
j := MenuIndex;
TheResult := TRUE;
end
else
begin
MenuIndex := MenuIndex - Ord(High(TViewMenus)) - 1;
if ((MenuIndex >= 0) and (MenuIndex <= Ord(High(TCalcMenus)))) then
begin
i := 3;
j := MenuIndex;
TheResult := TRUE;
{$IFDEF FINANCE}
end
else
begin
MenuIndex := MenuIndex - Ord(High(TCalcMenus)) - 1;
if ((MenuIndex >= 0) and (MenuIndex <= Ord(High(TFinanceMenus)))) then
begin
i := 4;
j := MenuIndex;
TheResult := TRUE;
end;
{$ENDIF}
end;
end;
end;
end;
GetIndicesFromTag := TheResult;
{$IFDEF DELPHI3_UP}
if (TheResult) then
Assert(FPlotPopUpMenu.Items[i].Items[j].Tag = TheTag,
'TCustomPlot.GetIndicesFromTag: ' + sTagNotMatch);
{$ENDIF}
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DisplaceClick
Description: runs the "Displacement" dialog box
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: responds to "Displace" menu selection
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DisplaceClick(Sender: TObject);
begin
if (GetSeriesFromUser) then
begin
pSeries.Displace(FHelpFile);
DoStyleChange(Self);
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ZoomInClick
Description: Zooms in using the mouse
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 05/30/2001 by Mat Ballard
Purpose: responds to "Zoom In" menu selection
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ZoomInClick(Sender: TObject);
var
i: Integer;
NewMin: Single;
begin
if ((FScreenJob = sjRightDrag) or
(FScreenJob = sjZoomIn)) then
begin
NewMin := FXAxis.XofF(Selection.Left);
FXAxis.SetMinMaxFromSeries(NewMin, FXAxis.XofF(Selection.Right));
for i := 1 to FAxisList.Count-1 do
begin
TAxis(FAxisList[i]).AutoScale := TRUE;
NewMin := TAxis(FAxisList[i]).YofF(Selection.Bottom);
FYAxis.SetMinMaxFromSeries(NewMin, TAxis(FAxisList[i]).YofF(Selection.Top));
end;
CreatePageButtons;
ZeroScreenStuff;
end
else
begin
FInstructions.Clear;
FInstructions.Add(sZoomInClick1);
FScreenJob := sjZoomIn;
DoStyleChange(Self);
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DifferentiateClick
Description: Replaces the selected Axis with its differential
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: responds to "Differential" menu selection
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DifferentiateClick(Sender: TObject);
begin
if (GetSeriesFromUser) then
begin
pSeries.Differentiate;
ZoomOutClick(Self);
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.IntegrateClick
Description: Replaces the selected Axis with its differential
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: responds to "Integrate" menu selection
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.IntegrateClick(Sender: TObject);
begin
if (GetSeriesFromUser) then
begin
pSeries.Integrate;
ZoomOutClick(Self);
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.IntegralClick
Description: calculates the integral of the selected Series over a selected range
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 05/30/2001 by Mat Ballard
Purpose: responds to "Integral" menu selection
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.IntegralClick(Sender: TObject);
var
Msg: String;
Sum,
TheLeft,
TheRight: Single;
begin
if (GetSeriesFromUser) then
begin
if ((FScreenJob = sjRightDrag) or
(FScreenJob = sjIntegral)) then
begin
TheLeft := FXAxis.XofF(Selection.Left);
TheRight := FXAxis.XofF(Selection.Right);
Sum := pSeries.Integral(TheLeft, TheRight);
Msg := sIntegral1 + pSeries.Name + sFrom + CRLF;
Msg := Msg + FXAxis.LabelToStrF(TheLeft) + sTo +
FXAxis.LabelToStrF(TheRight);
if (Length(FXAxis.Title.Units) > 0) then
Msg := Msg + ' ' + FXAxis.Title.Units;
Msg := Msg + sIs + CRLF +
Format('%g', [Sum]);
if ((Length(FXAxis.Title.Units) > 0) and
(Length(pSeries.YAxis.Title.Units) > 0)) then
begin
Msg := Msg + ' (' + pSeries.YAxis.Title.Units + '.' +
FXAxis.Title.Units + ')';
end
else if (Length(FXAxis.Title.Units) > 0) then
begin
Msg := Msg + ' (' + FXAxis.Title.Units + ')';
end
else if (Length(pSeries.YAxis.Title.Units) > 0) then
begin
Msg := Msg + ' (' + pSeries.YAxis.Title.Units + ')';
end;
ShowMessage(Msg);
ClipBoard.AsText := Msg;
ZeroScreenStuff;
end
else
begin
FScreenJob := sjIntegral;
FInstructions.Clear;
FInstructions.Add(sIntegral2);
DoStyleChange(Self);
end;
end;
end;
{------------------------------------------------------------------------------
Function: TCustomPlot.GetClickAndDragDelay
Description: standard property Get function
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: gets the value of the ClickAndDragDelay Property
Return value: Integer
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetClickAndDragDelay: Integer;
begin
GetClickAndDragDelay := MouseTimer.Interval;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ZeroScreenStuff
Description: cleans up after a menu event handler - XXXClick
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: mouse management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ZeroScreenStuff;
begin
FScreenJob := sjNone;
ClickedObjectType := soNone;
pClickedObject := nil;
SecondClickedObjectType := soNone;
pSecondClickedObject := nil;
TheSeries := -1;
pSeries := nil;
TheAxis := -1;
pAxis := nil;
FOnSelection := nil;
FOnDualSelection := nil;
Screen.Cursor := crDefault;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.HighsClick
Description: Calculates the Highs (peaks) and/or Lows (troughs) of a series
Author: Mat Ballard
Date created: 09/25/2000
Date modified: 09/25/2000 by Mat Ballard
Purpose: data processing
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.HighsClick(Sender: TObject);
var
OptionsDlg: TOptionsDlg;
begin
if (GetSeriesFromUser) then
begin
OptionsDlg := TOptionsDlg.Create(nil);
OptionsDlg.FormTitle := sHighLow1;
OptionsDlg.Question := sHighLow2;
OptionsDlg.OptionList.Add(sHighLow3);
OptionsDlg.OptionList.Add(sHighLow4);
OptionsDlg.OptionList.Add(sHighLow5);
OptionsDlg.OptionList.Add(sHighLow6);
case OptionsDlg.Execute of
1: pSeries.ClearHighsLows;
2:
begin
pSeries.FindHighsLows(0, pSeries.NoPts, 5);
pSeries.HighLow := pSeries.HighLow + [hlHigh];
end;
3:
begin
pSeries.FindHighsLows(0, pSeries.NoPts, 5);
pSeries.HighLow := pSeries.HighLow + [hlLow];
end;
4:
begin
pSeries.FindHighsLows(0, pSeries.NoPts, 5);
pSeries.HighLow := pSeries.HighLow + [hlLow, hlHigh];
end;
end;
OptionsDlg.Free;
DoStyleChange(Self);
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.MovingAverageClick
Description: Calculates and displays the Moving Average of a series
Author: Mat Ballard
Date created: 09/25/2000
Date modified: 09/25/2000 by Mat Ballard
Purpose: data smoothing
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.MovingAverageClick(Sender: TObject);
var
Span: Integer;
SpanStr: String;
begin
if (GetSeriesFromUser) then
begin
SpanStr := '10';
if (InputQuery(sMovingAverage1, sMovingAverage2, SpanStr)) then
begin
try
Span := StrToInt(SpanStr);
pSeries.MovingAverage(Span);
except
ShowMessage(sMovingAverage3);
end;
end;
DoStyleChange(Self);
end;
ZeroScreenStuff;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.AverageClick
Description: Calculates the Average of a series over a range
Author: Mat Ballard
Date created: 09/25/2000
Date modified: 05/30/2001 by Mat Ballard
Purpose: data processing
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.AverageClick(Sender: TObject);
var
Msg: String;
Sum,
TheLeft,
TheRight: Single;
begin
if (GetSeriesFromUser) then
begin
if ((FScreenJob = sjRightDrag) or
(FScreenJob = sjAverage)) then
begin
TheLeft := FXAxis.XofF(Selection.Left);
TheRight := FXAxis.XofF(Selection.Right);
Sum := pSeries.Average(TheLeft, TheRight);
Msg := sAverage1 + pSeries.Name + sFrom + CRLF;
Msg := Msg + FXAxis.LabelToStrF(TheLeft) + sTo +
FXAxis.LabelToStrF(TheRight);
if (Length(FXAxis.Title.Units) > 0) then
Msg := Msg + ' ' + FXAxis.Title.Units;
Msg := Msg + sIs + CRLF +
Format('%g', [Sum]);
if (Length(pSeries.YAxis.Title.Units) > 0) then
begin
Msg := Msg + ' (' + pSeries.YAxis.Title.Units + ')';
end;
ShowMessage(Msg);
ClipBoard.AsText := Msg;
ZeroScreenStuff;
end
else
begin
FScreenJob := sjAverage;
FInstructions.Clear;
FInstructions.Add(sAverage2);
DoStyleChange(Self);
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.LinearizeClick
Description: Linearizes Y data of a series over a range
Author: Mat Ballard
Date created: 05/30/2001
Date modified: 05/30/2001 by Mat Ballard
Purpose: data processing
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.LinearizeClick(Sender: TObject);
var
TheLeft,
TheRight: Single;
begin
if (GetSeriesFromUser) then
begin
if ((FScreenJob = sjRightDrag) or
(FScreenJob = sjLinearize)) then
begin
TheLeft := FXAxis.XofF(Selection.Left);
TheRight := FXAxis.XofF(Selection.Right);
pSeries.Linearize(TheLeft, TheRight);
ZeroScreenStuff;
Refresh;
end
else
begin
FScreenJob := sjLinearize;
FInstructions.Clear;
FInstructions.Add(sLinearizeClick1);
DoStyleChange(Self);
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ZeroClick
Description: Calculates the Zero of a series over a range
Author: Mat Ballard
Date created: 05/30/2001
Date modified: 05/30/2001 by Mat Ballard
Purpose: data processing
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ZeroClick(Sender: TObject);
var
TheLeft,
TheRight: Single;
begin
if (GetSeriesFromUser) then
begin
if ((FScreenJob = sjRightDrag) or
(FScreenJob = sjZero)) then
begin
TheLeft := FXAxis.XofF(Selection.Left);
TheRight := FXAxis.XofF(Selection.Right);
pSeries.Zero(TheLeft, TheRight);
ZeroScreenStuff;
Refresh;
end
else
begin
FScreenJob := sjZero;
FInstructions.Clear;
FInstructions.Add(sZeroClick1);
DoStyleChange(Self);
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.NewYAxisClick
Description: Adds a new axis, based on either the selected or last axis.
Author: Mat Ballard
Date created: 06/12/2000
Date modified: 06/12/2000 by Mat Ballard
Purpose: axis management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.NewYAxisClick(Sender: TObject);
var
TheTemplate: Integer;
NewAxis: TAxis;
begin
{has the user already selected an object ?}
{see GetTheClickedObject and ZeroScreenStuff}
TheTemplate := TheAxis;
if (TheTemplate <= 0) then
TheTemplate := FAxisList.Count - 1;
{NB: there is only ONE X Axis, otherwise things get TOO complicated,
so if the user right-clicks on the X Axis, it is effectively ignored}
NewAxis := TAxis.Create(Self);
FAxisList.Add(NewAxis);
NewAxis.Assign(TAxis(FAxisList[TheTemplate]));
NewAxis.OnChange := DoStyleChange;
{Move the new axis to the right:}
if (FAxisList.Count = 3) then
begin
{this new one is a secondary axis:}
NewAxis.AxisType := atSecondary;
NewAxis.Intercept := FXAxis.Max;
NewAxis.TickDirection := orRight;
NewAxis.Title.Orientation := orRight;
end
else
begin
NewAxis.AxisType := atTertiary;
{place the new axis half-way between the last and the right hand side:}
NewAxis.Intercept := FXAxis.XofF((NewAxis.MidX + Width) div 2);
end;
{if this over-runs the panel width, then wrap around:}
if (NewAxis.Left > Width) then
NewAxis.Left := NewAxis.Left - Width;
{... and rename it:}
NewAxis.Name := sCopy + ' ' + sOf + ' ' + NewAxis.Name;
NewAxis.Title.Caption := sCopy + ' ' + sOf + ' ' + NewAxis.Title.Caption;
NewAxis.Tag := Ord(soYAxis);
NewAxis.Labels.Tag := Ord(soYAxisLabel);
NewAxis.Title.Tag := Ord(soYAxisTitle);
{add this New Y Axis to the ScreenObjectList:}
ScreenObjectList.Insert(Ord(soLeftBorder), NewAxis.Labels);
ScreenObjectList.Insert(Ord(soLeftBorder), NewAxis.Title);
ScreenObjectList.Insert(Ord(soLeftBorder), NewAxis);
//Inc(NoBasicScreenObjects, 3);
{note that we insert: we do this in order to make Y Axes be found before
borders and series.}
{re-initialize:}
ZeroScreenStuff;
{we need to call re-size to force a SetAxisDimensions:}
Resize;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DeleteAxisClick
Description: Deletes an axis
Author: Mat Ballard
Date created: 06/12/2000
Date modified: 06/12/2000 by Mat Ballard
Purpose: axis management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DeleteAxisClick(Sender: TObject);
begin
if (GetAxisFromUser(2)) then
DeleteAxis(TheAxis, TRUE);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DeleteAxis
Description: Deletes the selected axis
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: axis management
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DeleteAxis(Index: Integer; Confirm: Boolean);
var
pAxisToDelete: TAxis;
begin
if ((Index <= 1) or
(Index >= FAxisList.Count)) then raise
ERangeError.CreateFmt(sDeleteAxis1, [Index, FAxisList.Count-1]);
pAxisToDelete := TAxis(FAxisList[Index]);
if (Confirm) then
begin
{Confirm := (IDNO = MessageBox(0,
'Are you sure you want to delete' + pAxisToDelete.Title.Caption,
'Delete Secondary Axis',
MB_YESNO + MB_ICONQUESTION));}
Confirm := (mrNo =
MessageDlg(
{$IFDEF LINUX}
sDeleteAxis2,
{$ENDIF}
sDeleteAxis3 + pAxisToDelete.Title.Caption,
mtWarning,
[mbYes, mbNo],
0));
end;
if (not Confirm) then
begin
{remove this Y Axis from the ScreenObjectList:}
ScreenObjectList.Delete(ScreenObjectList.IndexOf(pAxisToDelete));
ScreenObjectList.Delete(ScreenObjectList.IndexOf(pAxisToDelete.Title));
ScreenObjectList.Delete(ScreenObjectList.IndexOf(pAxisToDelete.Labels));
//Dec(NoBasicScreenObjects, 3);
{remove this Y Axis from the AxisList:}
FAxisList.Delete(Index);
{and remove it:}
pAxisToDelete.Free;
DoStyleChange(Self);
end;
end;
{$IFDEF FINANCE}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.ADLClick
Description: This runs the ADL financial calculation
Author: Mat Ballard
Date created: 07/25/2001
Date modified: 07/25/2001 by Mat Ballard
Purpose: standard Financial menu item event handler
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.ADLClick(Sender: TObject);
begin
ShowMessage('Sorry - Financial calculations are not yet enabled !');
end;
{$ENDIF}
{------------------------------------------------------------------------------
Function: TCustomPlot.GetNoSeries
Description: standard property Get function
Author: Mat Ballard
Date created: 25/25/2000
Date modified: 25/25/2000 by Mat Ballard
Purpose: gets the number of Series
Return Value: integer
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetNoSeries: Word;
begin
GetNoSeries := FSeriesList.Count;
end;
{------------------------------------------------------------------------------
Function: TCustomPlot.GetNoYAxes
Description: standard property Get function
Author: Mat Ballard
Date created: 06/25/2000
Date modified: 06/25/2000 by Mat Ballard
Purpose: gets the number of Y Axes
Return Value: integer
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetNoYAxes: Integer;
begin
GetNoYAxes := FAxisList.Count-1;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetNoYAxes
Description: standard property Set procedure
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: sets the number of Y Axes
Known Issues: it is a fairly brutal way of setting the number of Y Axes
------------------------------------------------------------------------------}
procedure TCustomPlot.SetNoYAxes(Value: Integer);
var
i: Integer;
begin
if (Value < 1) then exit;
if (Value = FAxisList.Count-1) then exit;
if (Value > 15) then raise
EComponentError.CreateFmt(sSetNoYAxes1, [Value]);
if (Value < FAxisList.Count-1) then
begin
{we need to delete some axes:}
for i := FAxisList.Count-1 downto Value+1 do
begin
DeleteAxis(i, FALSE);
end;
end
else
begin
{in order to avoid creating an extra axis when a 3D plot is loaded:}
if not (csLoading in ComponentState) then
{add some axes:}
for i := FAxisList.Count-1 to Value-1 do
begin
NewYAxisClick(Self);
end;
end;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetPlotType
Description: standard property Set procedure
Author: Mat Ballard
Date created: 09/20/2000
Date modified: 01/16/2001 by Mat Ballard
Purpose: sets the PlotType property
Known Issues: under development
------------------------------------------------------------------------------}
procedure TCustomPlot.SetPlotType(Value: TPlotType);
var
i: Integer;
OldIgnoreChanges: Boolean;
procedure AddZAxis;
begin
FZAxis := TAngleAxis.Create(Self);
FZAxis.AxisType := atZ;
FZAxis.Tag := Ord(soZAxis);
FZAxis.FireEvents := FALSE;
FZAxis.Name := 'Z';
FZAxis.Title.Caption := 'Z-' + sAxis;
{FZAxis.Left := FXAxis.Left;
FZAxis.Top := FXAxis.MidY;}
FZAxis.Length := FXAxis.Width div 3;
FAxisList.Add(FZAxis);
//ScreenObjectList.Add(FZAxis);
ScreenObjectList.Items[Ord(soZAxis)] := FZAxis;
ScreenObjectList.Items[Ord(soZAxisTitle)] := FZAxis.Title;
ScreenObjectList.Items[Ord(soZAxisLabel)] := FZAxis.Labels;
FBorder.Left := Self.Width div 3;
FBorder.BottomGap := Self.Height div 3;
FZAxis.OnChange := DoStyleChange;
end;
procedure RemoveZAxis;
begin
FZAxis.OnChange := nil;
FAxisList.Remove(FZAxis);
ScreenObjectList.Items[Ord(soZAxis)] := nil;
ScreenObjectList.Items[Ord(soZAxisTitle)] := nil;
ScreenObjectList.Items[Ord(soZAxisLabel)] := nil;
//Dec(NoBasicScreenObjects);
FZAxis.Free;
FZAxis := nil;
end;
begin
if (FPlotType = Value) then exit;
OldIgnoreChanges := IgnoreChanges;
IgnoreChanges := TRUE;
if (FZAxis <> nil) then
if (Value < pt3DContour) then
RemoveZAxis;
if (csDesigning in ComponentState) then
NoSeries := 2;
FPlotType := Value;
{clean up axes:}
for i := 0 to FAxisList.Count-1 do
begin
TAxis(FAxisList.Items[i]).FireEvents := FALSE;
TAxis(FAxisList.Items[i]).Visible := TRUE;
end;
FYAxis.Title.Visible := TRUE;
FXAxis.Title.Alignment := taCenter;
{clear previous Series pen settings:}
for i := 0 to FSeriesList.Count-1 do
begin
Series[i].Pen.Width := 1;
Series[i].Symbol := syNone;
end;
{re-scale the primary X Axis:}
if (FSeriesList.TotalNoPts > 0) then
begin
if (FSeriesList.Xmin >= 0) then
XAxis.Min := 0
else
XAxis.Min := Round(FSeriesList.Xmin - 0.999);
XAxis.Max := Round(FSeriesList.Xmax + 0.999);
end;
{re-scale the primary Y Axis:}
if (FSeriesList.TotalNoPts > 0) then
begin
if (FSeriesList.Ymin >= 0) then
YAxis.Min := 0
else
YAxis.Min := Round(FSeriesList.Ymin - 0.999);
YAxis.Max := Round(FSeriesList.Ymax + 0.999);
end;
FLegend.Visible := TRUE;
case FPlotType of
ptXY: ;
ptError:
begin
{if (csDesigning in ComponentState) then
MakeDummyData(20);}
i := 0;
while (i <= FSeriesList.Count-2) do
begin
Series[i].Symbol := TSymbol(1 + (i div 2) mod (Ord(High(TSymbol))-2));
Inc(i, 2);
end;
if (FSeriesList.TotalNoPts > 0) then
begin
YAxis.Min := Round(FSeriesList.YErrorMin - 0.999);
YAxis.Max := Round(FSeriesList.YErrorMax + 0.999);
end;
end;
ptMultiple:
begin
for i := 0 to FSeriesList.Count-1 do
begin
Series[i].Pen.Width := 0;
Series[i].Symbol := TSymbol(1 + i mod (Ord(High(TSymbol))-2));
end;
end;
ptColumn: YAxis.Min := 0;
ptStack:
begin
YAxis.Min := 0;
if (FSeriesList.TotalNoPts > 0) then
YAxis.Max := Round(FSeriesList.Count * FSeriesList.Ymax + 0.999);
end;
ptNormStack:
begin
YAxis.Min := 0;
YAxis.Max := 100;
end;
ptPie:
begin
for i := 0 to FAxisList.Count-1 do
TAxis(FAxisList.Items[i]).Visible := FALSE;
end;
ptPolar:
begin
if (FXAxis.Min > -FXAxis.Max) then
FXAxis.Min := -FXAxis.Max;
if (FXAxis.Max < -FXAxis.Min) then
FXAxis.Max := -FXAxis.Min;
if (FYAxis.Min > -FYAxis.Max) then
FYAxis.Min := -FYAxis.Max;
if (FYAxis.Max < -FYAxis.Min) then
FYAxis.Max := -FYAxis.Min;
FXAxis.Intercept := 0;
FYAxis.Intercept := 0;
FYAxis.Title.Visible := FALSE;
FXAxis.Title.Alignment := taRightJustify;
end;
ptLineContour, ptContour:
begin
if (csDesigning in ComponentState) then
begin
NoSeries := 10;
MakeDummyData(20);
end;
FLegend.Visible := FALSE;
end;
pt3DContour, pt3DWire, pt3DColumn{, pt3DSurface}:
begin
if (FZAxis = nil) then
AddZAxis;
if (csDesigning in ComponentState) then
begin
FBorder.Left := 3 * FBorder.Left div 2;
FBorder.BottomGap := 3 * FBorder.BottomGap div 2;
NoSeries := 10;
MakeDummyData(20);
end;
FLegend.Visible := FALSE;
end;
end;
{deal with axes:}
SetAxisDimensions;
for i := 0 to FAxisList.Count-1 do
begin
TAxis(FAxisList.Items[i]).Intercept := 0;
TAxis(FAxisList.Items[i]).FireEvents := TRUE;
end;
SetDefaults;
IgnoreChanges := OldIgnoreChanges;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetPolarRange
Description: standard property Set procedure
Author: Mat Ballard
Date created: 09/20/2000
Date modified: 01/16/2001 by Mat Ballard
Purpose: sets the PolarRange property
Known Issues: under development
------------------------------------------------------------------------------}
procedure TCustomPlot.SetPolarRange(Value: Single);
begin
if (FPolarRange = Value) then exit;
FPolarRange := Value;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetPopupOptions
Description: standard property Set procedure
Author: Mat Ballard
Date created: 09/25/2000
Date modified: 09/25/2000 by Mat Ballard
Purpose: sets the PopupOptions property, and informs any TPlotMenu and
TPlotToolBar of the change
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetPopupOptions(Value: TPopupOptions);
begin
FPopupOptions.Assign(Value);
if (Self.FPlotMenu <> nil) then
TPlotMenu(FPlotMenu).ApplyOptions(Value);
if (Self.FPlotToolBar <> nil) then
TPlotToolBar(FPlotToolBar).ApplyOptions(Value);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetPlotMenu
Description: standard property Set procedure
Author: Mat Ballard
Date created: 09/25/2000
Date modified: 09/25/2000 by Mat Ballard
Purpose: sets the PlotMenu property
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetPlotMenu(Value: TMainMenu);
begin
FPlotMenu := Value;
if (FPlotMenu <> nil) then
TPlotMenu(FPlotMenu).ApplyOptions(FPopupOptions);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetPlotToolBar
Description: standard property Set procedure
Author: Mat Ballard
Date created: 09/25/2000
Date modified: 04/25/2001 by Mat Ballard
Purpose: sets the PlotToolBar property
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetPlotToolBar(Value: TToolBar);
begin
FPlotToolBar := Value;
if (FPlotToolBar <> nil) then
TPlotToolBar(FPlotToolBar).ApplyOptions(FPopupOptions);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetPlotActionList
Description: standard property Set procedure
Author: Mat Ballard
Date created: 09/25/2000
Date modified: 09/25/2000 by Mat Ballard
Purpose: sets the PlotActionList property
Known Issues:
------------------------------------------------------------------------------}
{$IFDEF DELPHI4_UP}
{procedure TCustomPlot.SetPlotActionList(Value: TActionList);
begin
FPlotActionList := Value;
end;}
{$ENDIF}
{------------------------------------------------------------------------------
Procedure: TCustomPlot.Clear
Description: Saves any changed files (at user request) and then clears the SeriesList.
Author: Mat Ballard
Date created: 04/25/2000
Date modified: 04/25/2000 by Mat Ballard
Purpose: Series management: wraps TSeriesList.ClearSeries
Known Issues: it is a fairly brutal way of setting the number of Y Axes
------------------------------------------------------------------------------}
procedure TCustomPlot.Clear(Cancellable: Boolean);
var
TheResult: Integer;
TheMessage: String;
{$IFDEF MSWINDOWS}
pMessage: array[0..255] of Char;
{$ENDIF}
begin
if (csDesigning in ComponentState) then exit;
if (FSeriesList.Count > 0) then
begin
if (FSeriesList.DataChanged) then
begin
if (Length(FFileName) > 0) then
TheMessage := ExtractFileName(FFileName)
else
TheMessage := sThisFile;
TheMessage := sSaveClick1 + ' ' + TheMessage + ' ' + sBeforeClose;
{NB: MessageDlg provokes an access violation because the Window may have gone:}
{$IFDEF MSWINDOWS}
StrPCopy(pMessage, TheMessage);
if (Cancellable) then
TheResult := {Windows.}MessageBox(0, pMessage, pChar(sFileHasChanged), MB_YESNOCANCEL + MB_ICONQUESTION)
else
TheResult := {Windows.}MessageBox(0, pMessage, pChar(sFileHasChanged), MB_YESNO + MB_ICONQUESTION);
{$ENDIF}
{$IFDEF LINUX}
if (Cancellable) then
TheResult := MessageDlg(sSaveFile,
TheMessage,
mtWarning,
[mbYes, mbNo, mbCancel],
0)
else
TheResult := MessageDlg(sSaveFile,
TheMessage,
mtWarning,
[mbYes, mbNo],
0);
{$ENDIF}
case TheResult of
mrYes: SaveClick(Self);
mrNo: ;
mrCancel: Exit;
end;
end;
FSeriesList.ClearSeries;
if ((FPlotMenu <> nil) and (Length(FFileName) > 0)) then
TPlotMenu(FPlotMenu).AddHistory(FFileName);
DoFileClose(FFileName);
end;
FFileName := '';
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DoStyleChange
Description: informs the user of a change in the plot that requires a repaint
Author: Mat Ballard
Date created: 02/20/2001
Date modified: 02/20/2001 by Mat Ballard
Purpose: Fires the OnStyleChange event
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DoStyleChange(Sender: TObject);
begin
if (IgnoreChanges) then exit;
SetAxisDimensions;
if assigned(FOnStyleChange) then OnStyleChange(Sender);
Refresh;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DoDataChange
Description: informs the user of a change in the data of the plot that requires a repaint
Author: Mat Ballard
Date created: 03/07/2001
Date modified: 03/07/2001 by Mat Ballard
Purpose: Fires the OnDataChange event
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DoDataChange(Sender: TObject);
begin
if (IgnoreChanges) then exit;
if assigned(FOnDataChange) then OnDataChange(Sender);
Refresh;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.DoFileClose
Description: informs the user of a file close
Author: Mat Ballard
Date created: 09/07/2000
Date modified: 09/07/2000 by Mat Ballard
Purpose: Fires the OnFileClose event
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.DoFileClose(AFileName: String);
begin
if assigned(FOnFileClose) then
OnFileClose(Self, AFileName);
end;
{------------------------------------------------------------------------------
Function: TCustomPlot.GetPlotTypeAsString
Description: standard property getting method
Author: Mat Ballard
Date created: 23/07/2001
Date modified: 023/07/2001 by Mat Ballard
Purpose: gets the PlotType as a string (for BCB users mainly)
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetPlotTypeAsString: String;
begin
Result := Copy(TypInfo.GetEnumName(TypeInfo(TPlotType), Ord(FPlotType)), 3, 99);
end;
{------------------------------------------------------------------------------
Function: TCustomPlot.GetZAngle
Description: standard property getting method
Author: Mat Ballard
Date created: 01/07/2001
Date modified: 01/07/2001 by Mat Ballard
Purpose: gets the angle of the Z Axis, if any
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetZAngle: Word;
begin
if (FZAxis <> nil) then
GetZAngle := FZAxis.Angle
else
GetZAngle := 225;
end;
{------------------------------------------------------------------------------
Function: TCustomPlot.GetZLength
Description: standard property getting method
Author: Mat Ballard
Date created: 01/07/2001
Date modified: 01/07/2001 by Mat Ballard
Purpose: gets the Length of the Z Axis, if any
Known Issues:
------------------------------------------------------------------------------}
function TCustomPlot.GetZLength: Word;
begin
if (FZAxis <> nil) then
GetZLength := FZAxis.Length
else
GetZLength := 100;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetZAngle
Description: standard property setting method
Author: Mat Ballard
Date created: 01/07/2001
Date modified: 01/07/2001 by Mat Ballard
Purpose: sets the angle of the Z Axis, if any
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetZAngle(Value: Word);
begin
if (FZAxis <> nil) then
if (Value <> FZAxis.Angle) then
FZAxis.Angle := Value;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetZLength
Description: standard property setting method
Author: Mat Ballard
Date created: 01/07/2001
Date modified: 01/07/2001 by Mat Ballard
Purpose: sets the Length of the Z Axis, if any
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetZLength(Value: Word);
begin
if (FZAxis <> nil) then
if (Value <> FZAxis.Length) then
FZAxis.Length := Value;
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetZLink
Description: standard property setting method
Author: Mat Ballard
Date created: 01/07/2001
Date modified: 01/07/2001 by Mat Ballard
Purpose: sets the Link property - that is, should we link 3D series ?
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetZLink(Value: Boolean);
begin
if (Value <> FZLink) then
FZLink := Value;
DoStyleChange(Self);
end;
{------------------------------------------------------------------------------
Procedure: TCustomPlot.SetXYFastAt
Description: standard property setting method
Author: Mat Ballard
Date created: 05/07/2001
Date modified: 05/07/2001 by Mat Ballard
Purpose: sets the Bridge point of the data - when it switches to the
hyperfast draw algorithm
Known Issues:
------------------------------------------------------------------------------}
procedure TCustomPlot.SetXYFastAt(Value: Longint);
begin
if (Value > 100) then
FXYFastAt := Value;
DoStyleChange(Self);
end;
end.