Apophysis-AV/Forms/Editor.pas

8145 lines
244 KiB
ObjectPascal

{
Apophysis Copyright (C) 2001-2004 Mark Townsend
Apophysis Copyright (C) 2005-2006 Ronald Hordijk, Piotr Borys, Peter Sdobnov
Apophysis Copyright (C) 2007-2008 Piotr Borys, Peter Sdobnov
Apophysis "3D hack" Copyright (C) 2007-2008 Peter Sdobnov
Apophysis "7X" Copyright (C) 2009-2010 Georg Kiehne
Apophysis AV "Phoenix Edition" Copyright (C) 2021-2022 Alice V. Koryagina
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
}
//{$D-,L-,O+,Q-,R-,Y-,S-}
unit Editor;
//{$define VAR_STR}
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls, StdCtrls, ComCtrls, Math, Menus, ToolWin, Registry,
Grids, ValEdit, Buttons, ImgList, Types, StrUtils,
ControlPoint, XForm, cmap, CustomDrawControl, ClipBrd,
RenderingInterface, RenderThread, System.ImageList,
Vcl.Samples.Spin, Vcl.GraphUtil;
type
TEditForm = class(TForm)
StatusBar: TStatusBar;
EditPopup: TPopupMenu;
mnuAdd: TMenuItem;
mnuAutoZoom: TMenuItem;
N1: TMenuItem;
mnuUndo: TMenuItem;
mnuRedo: TMenuItem;
QualityPopup: TPopupMenu;
mnuLowQuality: TMenuItem;
mnuMediumQuality: TMenuItem;
mnuHighQuality: TMenuItem;
N3: TMenuItem;
mnuResetLoc: TMenuItem;
N4: TMenuItem;
mnuFlipVertical: TMenuItem;
mnuFlipHorizontal: TMenuItem;
mnuFlipAllV: TMenuItem; //AV
mnuFlipAllH: TMenuItem; // AV
EditorToolBar: TToolBar;
tbAdd: TToolButton;
tbDuplicate: TToolButton;
tbDelete: TToolButton;
ToolButton4: TToolButton;
tbMove: TToolButton;
tbRotate: TToolButton;
ToolButton1: TToolButton;
tbUndo: TToolButton;
tbRedo: TToolButton;
tbScale: TToolButton;
tbFlipHorz: TToolButton;
tbFlipVert: TToolButton;
tbSelect: TToolButton;
EditorTB: TImageList;
tbResetAll: TToolButton;
ToolButton2: TToolButton;
tbVarPreview: TToolButton;
tbEnableFinalXform: TToolButton;
ToolButton3: TToolButton;
TrianglePopup: TPopupMenu;
mnuDuplicate: TMenuItem;
mnuDelete: TMenuItem;
mnuAdd1: TMenuItem;
N2: TMenuItem;
mnuShowVarPreview: TMenuItem;
mnuReset: TMenuItem;
N6: TMenuItem;
Rotatetriangle90CCW1: TMenuItem;
Rotatetriangle90CCW2: TMenuItem;
mnuResetTrgRotation: TMenuItem;
mnuResetTrgPosition: TMenuItem;
mnuResetTrgScale: TMenuItem;
N7: TMenuItem;
mnuExtendedEdit: TMenuItem;
N8: TMenuItem;
mnuAxisLock: TMenuItem;
mnuSelectmode: TMenuItem;
ToolButton6: TToolButton;
tbPivotMode: TToolButton;
tbRotate90CCW: TToolButton;
tbRotate90CW: TToolButton;
tbPostXswap: TToolButton;
oggleposttriangleediting1: TMenuItem;
mnuCopyTriangle: TMenuItem;
mnuPasteTriangle: TMenuItem;
ChaosPopup: TPopupMenu;
mnuChaosViewTo: TMenuItem;
mnuChaosViewFrom: TMenuItem;
N9: TMenuItem;
mnuChaosClearAll: TMenuItem;
mnuChaosSetAll: TMenuItem;
N10: TMenuItem;
mnuLinkPostxform: TMenuItem;
mnuLinkPrexform: TMenuItem;
mnuChaosRebuild: TMenuItem;
tbPostLink: TToolButton;
ToolButton8: TToolButton;
tbCopy: TToolButton;
tbPaste: TToolButton;
ToolButton11: TToolButton;
EditPnl: TPanel;
Splitter1: TSplitter;
GrphPnl: TPanel;
RightPanel: TPanel;
Splitter2: TSplitter;
ControlPanel: TPanel;
cbTransforms: TComboBox;
PageControl: TPageControl;
TriangleTab: TTabSheet;
TriangleScrollBox: TScrollBox;
TrianglePanel: TPanel;
TriangleToolBar: TToolBar;
tbCopyTriangle: TToolButton;
tbPasteTriangle: TToolButton;
tbExtendedEdit: TToolButton;
tbAxisLock: TToolButton;
tbAutoWeights: TToolButton;
tb2PostXswap: TToolButton;
tabXForm: TTabSheet;
tabColors: TTabSheet;
tabVariations: TTabSheet;
VEVars: TValueListEditor;
bClear: TBitBtn;
TabVariables: TTabSheet;
vleVariables: TValueListEditor;
chkCollapseVariables: TCheckBox;
TabChaos: TTabSheet;
vleChaos: TValueListEditor;
optFrom: TRadioButton;
optTo: TRadioButton;
txtP: TEdit;
pnlWeight: TPanel;
Panel1: TPanel;
txtName: TEdit;
Panel2: TPanel;
PrevPnl: TPanel;
PreviewImage: TImage;
gbTrgOperations: TGroupBox;
btTrgRotateLeft90: TSpeedButton;
btTrgRotateRight90: TSpeedButton;
btTrgScaleDown: TSpeedButton;
btTrgScaleUp: TSpeedButton;
btTrgMoveDown: TSpeedButton;
btTrgMoveLeft: TSpeedButton;
btTrgMoveRight: TSpeedButton;
btTrgMoveUp: TSpeedButton;
btTrgRotateLeft: TSpeedButton;
btTrgRotateRight: TSpeedButton;
txtTrgScaleValue: TComboBox;
txtTrgRotateValue: TComboBox;
txtTrgMoveValue: TComboBox;
gbCoordinates: TGroupBox;
LabelC: TLabel;
LabelA: TLabel;
LabelB: TLabel;
txtAx: TEdit;
txtAy: TEdit;
txtBx: TEdit;
txtBy: TEdit;
txtCx: TEdit;
txtCy: TEdit;
ScrollBox1: TScrollBox;
GroupBox9: TGroupBox;
btnXcoefs: TSpeedButton;
btnYcoefs: TSpeedButton;
btnOcoefs: TSpeedButton;
btnResetCoefs: TSpeedButton;
txtA: TEdit;
txtB: TEdit;
txtC: TEdit;
txtD: TEdit;
txtE: TEdit;
txtF: TEdit;
spinA: TSpinButton;
spinB: TSpinButton;
spinC: TSpinButton;
spinD: TSpinButton;
spinE: TSpinButton;
spinF: TSpinButton;
GroupBox7: TGroupBox;
btnCoefsPolar: TSpeedButton;
btnCoefsRect: TSpeedButton;
GroupBox8: TGroupBox;
btnXpost: TSpeedButton;
btnYpost: TSpeedButton;
btnOpost: TSpeedButton;
btnResetPostCoefs: TSpeedButton;
txtPost00: TEdit;
txtPost01: TEdit;
txtPost10: TEdit;
txtPost11: TEdit;
txtPost20: TEdit;
txtPost21: TEdit;
spinPost00: TSpinButton;
spinPost01: TSpinButton;
spinPost10: TSpinButton;
spinPost11: TSpinButton;
spinPost20: TSpinButton;
spinPost21: TSpinButton;
chkAutoZscale: TCheckBox;
ScrollBox2: TScrollBox;
GroupBox1: TGroupBox;
pnlSymmetry: TPanel;
pnlXFormColor: TPanel;
shColor: TShape;
txtXFormColor: TEdit;
txtSymmetry: TEdit;
ColorBar: TPanel;
ColorBarPicture: TImage;
scrlXFormColor: TScrollBar;
pnlOpacity: TPanel;
txtOpacity: TEdit;
chkXformSolo: TCheckBox;
pnlDC: TPanel;
txtDC: TEdit;
GroupBox2: TGroupBox;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
trkVarPreviewDensity: TTrackBar;
trkVarPreviewRange: TTrackBar;
trkVarPreviewDepth: TTrackBar;
ImgTemp: TImage;
N11: TMenuItem;
mnuEHighQuality: TMenuItem;
mnuEMediumQuality: TMenuItem;
mnuELowQuality: TMenuItem;
lblSearch: TLabel;
txtSearchBox: TEdit;
ToolButton5: TToolButton;
btnMathPopup: TToolButton;
tbPreLink: TToolButton;
btnFullChaos: TToolButton;
btnResetSearch: TSpeedButton;
gbPivot: TGroupBox;
btnResetPivot: TSpeedButton;
btnPickPivot: TSpeedButton;
btnPivotMode: TSpeedButton;
editPivotY: TEdit;
editPivotX: TEdit;
MathPopup: TPopupMenu;
InsertPi1: TMenuItem;
Insert2Pi1: TMenuItem;
InsertPi21: TMenuItem;
InsertPi31: TMenuItem;
InsertGoldenratio1: TMenuItem;
InsertPi41: TMenuItem;
InsertPi61: TMenuItem;
Insertsqrt321: TMenuItem;
Insertsqrt331: TMenuItem;
Pifractions: TMenuItem;
Insert1sqrt21: TMenuItem;
CopyMenu: TPopupMenu;
PasteMenu: TPopupMenu;
CopyTriangleCoordinates: TMenuItem;
CopyTransform: TMenuItem;
PasteTriangleCoordinates: TMenuItem;
PasteTransform: TMenuItem;
Squareroots1: TMenuItem;
Insertsqrt361: TMenuItem;
Insertsqrt31: TMenuItem;
TriangleOperations: TPopupMenu;
InvertMovevalue1: TMenuItem;
ShowModVals: TMenuItem;
tbTriangle: TToolButton;
InvCurrentNum: TMenuItem;
N12: TMenuItem;
ScaleX: TMenuItem;
ScaleY: TMenuItem;
N13: TMenuItem;
ScaleXYO: TMenuItem;
N14: TMenuItem;
RotateXYO: TMenuItem;
RotateX: TMenuItem;
RotateY: TMenuItem;
ScaleO: TMenuItem;
RotateO: TMenuItem;
gbFlip: TGroupBox;
btnShowLine: TSpeedButton;
btnResetFlip: TSpeedButton;
btnFlip: TSpeedButton;
editFlipY: TEdit;
editFlipX: TEdit;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
lblGridType: TLabel;
GridComboBox: TComboBox;
Mul2: TMenuItem;
Div2: TMenuItem;
Squarethenumber1: TMenuItem;
RectGrid: TMenuItem;
TriGrid: TMenuItem;
N15: TMenuItem;
NormChaos: TMenuItem;
SpinPivotX: TSpinButton;
SpinPivotY: TSpinButton;
SpinFlipX: TSpinButton;
SpinFlipY: TSpinButton;
lblFlipAngle: TLabel;
RandomizeMatrix: TMenuItem;
btSwapCoefs: TButton;
CalcArcsinScale: TMenuItem;
N16: TMenuItem;
mnuFlipAllLine: TMenuItem;
btResetChaos: TButton;
ResetChaos: TMenuItem;
btClearChaos: TButton;
RandomizeChaos: TMenuItem;
N17: TMenuItem;
ChaosClearBelow: TMenuItem;
ClearAllAbove: TMenuItem;
btConjugate: TButton;
AddContainer: TMenuItem;
N18: TMenuItem;
CalcCos: TMenuItem;
CalcSin: TMenuItem;
CalcTan: TMenuItem;
UseDegrees: TMenuItem;
InheritWeights: TMenuItem;
InvertXaos: TMenuItem;
SquareRoot: TMenuItem;
btFlipX: TButton;
btFlipY: TButton;
btFlipDiag: TButton;
mnuResetTrgFlip: TMenuItem;
btChaos: TButton;
SpinXx: TSpinButton;
SpinYx: TSpinButton;
SpinOx: TSpinButton;
SpinXy: TSpinButton;
SpinYy: TSpinButton;
SpinOy: TSpinButton;
IconsAV: TImageList;
N19: TMenuItem;
ShowChaosMatrix: TMenuItem;
btnVarOrder: TBitBtn;
cbCollapseVariations: TComboBox;
btResetParams: TButton;
tbSyncTriangles: TToolButton;
mnuSyncTriangles: TPopupMenu;
SynchronizeAll: TMenuItem;
N20: TMenuItem;
CopyVariations: TMenuItem;
PasteVariations: TMenuItem;
ToolButton7: TToolButton;
tbComment: TToolButton;
mnuCalcExpression: TMenuItem;
N22: TMenuItem;
SaveFlameState: TToolButton;
N23: TMenuItem;
mnuCopyChaos: TMenuItem;
mnuPasteChaos: TMenuItem;
CopyChaos: TMenuItem;
PasteChaos: TMenuItem;
procedure btnResetSearchClick(Sender: TObject);
procedure txtSearchBoxKeyPress(Sender: TObject; var Key: Char);
// procedure txtSearchBoxChange(Sender: TObject);
procedure FormActivate(Sender: TObject);
procedure ScrollBox1Resize(Sender: TObject);
procedure ScrollBox2Resize(Sender: TObject);
procedure ControlPanelResize(Sender: TObject);
procedure TrianglePanelResize(Sender: TObject);
procedure ValidateVariable;
procedure vleVariablesValidate(Sender: TObject; ACol, ARow: Integer; const KeyName, KeyValue: string);
procedure vleVariablesKeyPress(Sender: TObject; var Key: Char);
procedure vleVariablesExit(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure TriangleViewMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: integer);
procedure TriangleViewMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: integer);
procedure TriangleViewMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: integer);
procedure TriangleViewMouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
procedure TriangleViewDblClick(Sender: TObject);
procedure TriangleViewKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure TriangleViewKeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure TriangleViewExit(Sender: TObject);
procedure TriangleViewMouseLeave(Sender: TObject);
procedure TriangleViewInvalidate(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure mnuDeleteClick(Sender: TObject);
procedure mnuAddClick(Sender: TObject);
procedure mnuDupClick(Sender: TObject);
procedure mnuAutoZoomClick(Sender: TObject);
procedure btnCloseClick(Sender: TObject);
procedure FormResize(Sender: TObject);
procedure txtPKeyPress(Sender: TObject; var Key: Char);
procedure CornerEditKeyPress(Sender: TObject; var Key: Char);
procedure CornerEditExit(Sender: TObject);
procedure txtPExit(Sender: TObject);
procedure DrawPreview;
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure mnuUndoClick(Sender: TObject);
procedure mnuRedoClick(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure mnuLowQualityClick(Sender: TObject);
procedure mnuHighQualityClick(Sender: TObject);
procedure mnuMediumQualityClick(Sender: TObject);
procedure mnuResetLocClick(Sender: TObject);
procedure mnuFlipAllVClick(Sender: TObject);
procedure mnuFlipAllHClick(Sender: TObject);
procedure mnuFlipVerticalClick(Sender: TObject);
procedure mnuFlipHorizontalClick(Sender: TObject);
procedure cbTransformsChange(Sender: TObject);
procedure CoefKeyPress(Sender: TObject; var Key: Char);
procedure CoefValidate(Sender: TObject);
procedure scrlXFormColorScroll(Sender: TObject;
ScrollCode: TScrollCode; var ScrollPos: Integer);
procedure scrlXFormColorChange(Sender: TObject);
procedure txtXFormColorExit(Sender: TObject);
procedure txtXFormColorKeyPress(Sender: TObject; var Key: Char);
procedure txtSymmetrySet(Sender: TObject);
procedure txtSymmetrKeyPress(Sender: TObject; var Key: Char);
procedure txtDCSet(Sender: TObject);
procedure txtDCKeyPress(Sender: TObject; var Key: Char);
procedure txtOpacitySet(Sender: TObject);
procedure txtOpacityKeyPress(Sender: TObject; var Key: Char);
procedure btTrgRotateLeftClick(Sender: TObject);
procedure btTrgRotateRightClick(Sender: TObject);
procedure btTrgRotateLeft90Click(Sender: TObject);
procedure btTrgRotateRight90Click(Sender: TObject);
procedure TrgMove(dx, dy: double);
procedure btTrgMoveLeftClick(Sender: TObject);
procedure btTrgMoveRightClick(Sender: TObject);
procedure btTrgMoveUpClick(Sender: TObject);
procedure btTrgMoveDownClick(Sender: TObject);
procedure btTrgScaleUpClick(Sender: TObject);
procedure btTrgScaleDownClick(Sender: TObject);
procedure splitterMoved(Sender: TObject);
procedure tbSelectClick(Sender: TObject);
procedure EditKeyPress(Sender: TObject; var Key: Char);
procedure tbEditModeClick(Sender: TObject);
procedure ValidateVariation;
procedure VEVarsKeyPress(Sender: TObject; var Key: Char);
procedure VEVarsChange(Sender: TObject);
procedure VEVarsValidate(Sender: TObject; ACol, ARow: Integer;
const KeyName, KeyValue: String);
procedure VEVarsMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure VEVarsMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure VEVarsMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure VEVarsDblClick(Sender: TObject);
procedure cbTransformsDrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
procedure tbFullViewClick(Sender: TObject);
procedure EditKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
procedure txtValidateValue(Sender: TObject);
procedure txtValKeyPress(Sender: TObject; var Key: Char);
procedure mnuResetTriangleClick(Sender: TObject);
procedure mnuResetAllClick(Sender: TObject);
procedure btnXcoefsClick(Sender: TObject);
procedure btnYcoefsClick(Sender: TObject);
procedure btnOcoefsClick(Sender: TObject);
procedure btnCoefsModeClick(Sender: TObject);
procedure tbVarPreviewClick(Sender: TObject);
procedure trkVarPreviewRangeChange(Sender: TObject);
procedure trkVarPreviewDensityChange(Sender: TObject);
procedure trkVarPreviewDepthChange(Sender: TObject);
procedure btnXpostClick(Sender: TObject);
procedure btnYpostClick(Sender: TObject);
procedure btnOpostClick(Sender: TObject);
procedure PostCoefValidate(Sender: TObject);
procedure PostCoefKeypress(Sender: TObject; var Key: Char);
procedure btnResetCoefsClick(Sender: TObject);
procedure btnResetPostCoefsClick(Sender: TObject);
procedure btnPivotModeClick(Sender: TObject);
procedure PivotValidate(Sender: TObject);
procedure PivotKeyPress(Sender: TObject; var Key: Char);
procedure btnResetPivotClick(Sender: TObject);
procedure btnPickPivotClick(Sender: TObject);
procedure VEVarsDrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
procedure tbEnableFinalXformClick(Sender: TObject);
procedure DragPanelMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure DragPanelMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure DragPanelMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure DragPanelDblClick(Sender: TObject);
procedure mnuResetTrgRotationClick(Sender: TObject);
procedure mnuResetTrgScaleClick(Sender: TObject);
procedure ResetAxisRotation(n: integer);
procedure ResetAxisScale(n: integer);
procedure tbExtendedEditClick(Sender: TObject);
procedure tbAxisLockClick(Sender: TObject);
procedure tbPostXswapClick(Sender: TObject);
procedure btnCopyTriangleClick(Sender: TObject);
procedure btnPasteTriangleClick(Sender: TObject);
procedure chkAutoZscaleClick(Sender: TObject);
procedure ValidateChaos;
procedure vleChaosExit(Sender: TObject);
procedure vleChaosKeyPress(Sender: TObject; var Key: Char);
procedure vleChaosValidate(Sender: TObject; ACol, ARow: Integer;
const KeyName, KeyValue: String);
procedure VleChaosDrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
procedure mnuChaosViewToClick(Sender: TObject);
procedure mnuChaosViewFromClick(Sender: TObject);
procedure mnuChaosClearAllClick(Sender: TObject);
procedure mnuChaosSetAllClick(Sender: TObject);
procedure mnuLinkPostxformClick(Sender: TObject);
procedure mnuLinkPrexformClick(Sender: TObject);
procedure chkXformSoloClick(Sender: TObject);
procedure mnuChaosRebuildClick(Sender: TObject);
procedure chkCollapseVariationsClick(Sender: TObject);
procedure chkCollapseVariablesClick(Sender: TObject);
procedure shColorMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure shColorMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
procedure shColorMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure bClearClick(Sender: TObject);
procedure ColorBarMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure txtNameKeyPress(Sender: TObject; var Key: Char);
procedure txtNameExit(Sender: TObject);
procedure InsertPi1Click(Sender: TObject);
procedure CopyTransformClick(Sender: TObject);
procedure PasteTransformClick(Sender: TObject);
procedure btResetparamsClick(Sender: TObject);
procedure SpinButtonDownClick(Sender: TObject);
procedure SpinButtonUpClick(Sender: TObject);
procedure InvertMovevalue1Click(Sender: TObject);
procedure InvCurrentNumClick(Sender: TObject);
procedure btnFlipClick(Sender: TObject);
procedure btnResetFlipClick(Sender: TObject);
procedure FlipPointKeyPress(Sender: TObject; var Key: Char);
procedure FlipPointValidate(Sender: TObject);
procedure btnShowLineClick(Sender: TObject);
procedure GridComboBoxChange(Sender: TObject);
procedure MulDiv2Click(Sender: TObject);
procedure NormChaosClick(Sender: TObject);
procedure RandomizeMatrixClick(Sender: TObject);
procedure btSwapCoefsClick(Sender: TObject);
procedure CalcArcsinScaleClick(Sender: TObject);
procedure mnuFlipAllLineClick(Sender: TObject);
procedure ResetChaosClick(Sender: TObject);
procedure ChaosClearBelowClick(Sender: TObject);
procedure ClearAllAboveClick(Sender: TObject);
procedure btConjugateClick(Sender: TObject);
procedure AddContainerClick(Sender: TObject);
procedure ResetToolsDblClick(Sender: TObject);
procedure CalcCosClick(Sender: TObject);
procedure InvertXaosClick(Sender: TObject);
procedure btFlipXYClick(Sender: TObject);
procedure AffineCoefsDblClick(Sender: TObject);
procedure mnuResetTrgFlipClick(Sender: TObject);
procedure btChaosClick(Sender: TObject);
procedure mnuChangeGridClick(Sender: TObject);
procedure ExtSysMenu(var Msg: TMessage); message WM_SysCommand;
procedure TriangleOperationsClick(Sender: TObject);
procedure btnFullChaosClick(Sender: TObject);
procedure btnVarOrderClick(Sender: TObject);
procedure FormShortCut(var Msg: TWMKey; var Handled: Boolean);
procedure tbSyncTrianglesClick(Sender: TObject);
procedure SynchronizeAllClick(Sender: TObject);
procedure SyncTrianglesDrawItem(Sender: TObject; ACanvas: TCanvas;
ARect: TRect; State: TOwnerDrawState);
procedure CopyVariationsClick(Sender: TObject);
procedure PasteVariationsClick(Sender: TObject);
procedure tbCommentClick(Sender: TObject);
procedure mnuCalcExpressionClick(Sender: TObject); // AV
procedure SaveFlameStateClick(Sender: TObject);
procedure mnuCopyChaosClick(Sender: TObject);
procedure mnuPasteChaosClick(Sender: TObject); // AV
private
TriangleView: TCustomDrawControl;
cmap: TColorMap;
PreviewDensity: double;
viewDragMode, viewDragged: boolean;
editMode, oldMode, widgetMode: (modeNone, modeMove, modeRotate, modeScale, modePick);
modeHack: boolean; // for mouseOverEdge...
modeKey: word;
key_handled: boolean;
updating: boolean;
MousePos: TPoint; // in screen coordinates
mouseOverTriangle, mouseOverEdge, mouseOverCorner, mouseOverWidget: integer;
mouseOverPos: TSPoint;
Widgets: array[0..3] of array [0..2] of TSPoint;
xx, xy, yx, yy: double;
varDragMode: boolean;
varDragIndex: integer;
varDragValue: double;
varDragPos, varDragOld: integer;
varMM: boolean; //hack?
pDragValue: ^double;
SelectMode, ExtendedEdit, AxisLock: boolean;
showVarPreview: boolean;
ShowFlipLine: boolean; // AV
hasLinkX: boolean; // AV
SyncTriangles: set of 0..NXFORMS; // AV: to change several triangles at time
GraphZoom: double;
TriangleCaught, CornerCaught, EdgeCaught: boolean;
LocalAxisLocked: boolean;
oldSelected: integer;
SelectedCorner: integer;
HasChanged: boolean;
oldTriangle: TTriangle;
gCenterX: double;
gCenterY: double;
MemTriangle: TTriangle;
oldx, oldy, olddist: double;
Pivot, FlipPoint, fl: TSPoint;
// hack: to prevent slow valuelist redraw
VarsCache: array of double; // AV: now length is sets dynamically
MemChaos: array of double; // AV
BackgroundBmp : TBitmap;
Renderer : TRenderThread;
pnlDragMode: boolean;
pnlDragPos, pnlDragOld: integer;
pnlDragValue: double;
LastFocus: TEdit;
procedure UpdateFlameX;
procedure UpdateFlame(DrawMain: boolean);
procedure UpdateWidgets;
procedure UpdateXformsList;
procedure UpdateVariationList; // AV
procedure DeleteTriangle(t: integer);
function GetPivot: TSPoint; overload;
function GetPivot(n: integer): TSPoint; overload;
procedure ShowSelectedInfo;
procedure Scale(var fx, fy: double; x, y: integer);
procedure RotateTriangleBy(const angle: double); // AV
procedure TriangleViewPaint(Sender: TObject);
procedure AutoZoom;
procedure KeyInput(str: string);
procedure CalcFlip;
function ValidNumField: boolean; inline; // AV: check active control
// AV: methods to synchronize tranformations of triangles
procedure FillSyncTrianglesMenu;
procedure AdjustSyncTriangles;
procedure SyncTrianglesClick(Sender: TObject);
procedure UpdateSyncTriangles;
public
cp: TControlPoint;
Render: TRenderer;
// Accessible from scripter
SelectedTriangle: integer; // outside only for scripting
PivotMode: (pivotLocal, pivotWorld);
LocalPivot, WorldPivot: TSPoint;
procedure UpdatePreview;
procedure UpdateDisplay(PreviewOnly: boolean = false);
function GetTriangleColor(n: integer): TColor;
function LastTriangle: integer;
function InsideTriangle(x, y: double): integer;
procedure ScriptGetPivot(var px, py: double);
procedure UpdateColorBar;
procedure PaintBackground;
procedure CreateScreenShot;
procedure RedrawButtons;
end;
const
{TrgColors: array[-1..13] of TColor = (clGray,
$0000ff, $00ffff, $00ff00, $ffff00, $ff0000, $ff00ff, $007fff,
$7f00ff, $55ffff, $ccffcc, $ffffaa, $ff7f7f, $ffaaff, $55ccff );}
TrgColors: array[-1..13] of TColor = (clGray,
$0000ff, $00cccc, $00cc00, $cccc00, $ff4040, $cc00cc, $0080cc,
$4f0080, $228080, $608060, $808050, $804f4f, $805080, $226080 );
saved_variations = 'Variations.list';
saved_variables = 'Variables.list';
var
EditForm: TEditForm;
function ColorValToColor(c: TColorMap; index: double): TColor;
function FlipTriangleVertical(t: TTriangle): TTriangle;
function FlipTriangleHorizontal(t: TTriangle): TTriangle;
function RotateTriangle(t: TTriangle; rad: double): TTriangle;
function ScaleTriangle(t: TTriangle; scale: double): TTriangle;
function RotateTrianglePoint(t: TTriangle; xr, yr: double; rad: double): TTriangle;
function ScaleTrianglePoint(t: TTriangle; x, y, scale: double): TTriangle;
{
function Centroid(t: TTriangle): TSPoint;
function RotateTriangleCenter(t: TTriangle; rad: double): TTriangle;
function ScaleTriangleCenter(t: TTriangle; scale: double): TTriangle;
function OffsetTriangle(t: TTriangle; range: double): TTriangle;
function OffsetTriangleRandom(t: TTriangle): TTriangle;
}
// AV: new operations
function ScaleTriangleXY(t: TTriangle; axis: integer; scale: double): TTriangle;
function ScaleTriangleO(t: TTriangle; x, y, scale: double): TTriangle;
function RotateTriangleO(t: TTriangle; x, y, rad: double): TTriangle;
function RotateTriangleXY(t: TTriangle; axis: integer; rad: double): TTriangle;
function FlipTriangleLine(t: TTriangle; x, y, fx, fy: double): TTriangle;
implementation
uses
Main, Global, Adjust, Mutate, XformMan, Translation,
Chaos, VarOrderForm, FlameComment, MathExpressions;
{$R *.DFM}
{ Triangle transformations }
function OffsetTriangleRandom(t: TTriangle): TTriangle;
var
r: integer;
begin
r := random(3);
Result.x[r] := t.x[r] + random - 0.5;
Result.y[r] := t.y[r] + random - 0.5;
end;
function FlipTriangleVertical(t: TTriangle): TTriangle;
begin
Result := t;
Result.y[0] := -t.y[0];
Result.y[1] := -t.y[1];
Result.y[2] := -t.y[2];
end;
function FlipTriangleHorizontal(t: TTriangle): TTriangle;
begin
Result := t;
Result.x[0] := -t.x[0];
Result.x[1] := -t.x[1];
Result.x[2] := -t.x[2];
end;
function FlipTriangleLine(t: TTriangle; x, y, fx, fy: double): TTriangle; // AV
var
N: TSpoint;
N2: double;
begin
N.x := fy - y;
N.y := -(fx - x);
N2 := 2 / (N.x * N.x + N.y * N.y);
Result.x[0] := t.x[0] - N2 *((t.x[0] - x) * N.x + (t.y[0] - y) * N.y)* N.x;
Result.y[0] := t.y[0] - N2 *((t.x[0] - x) * N.x + (t.y[0] - y) * N.y)* N.y;
Result.x[1] := t.x[1] - N2 *((t.x[1] - x) * N.x + (t.y[1] - y) * N.y)* N.x;
Result.y[1] := t.y[1] - N2 *((t.x[1] - x) * N.x + (t.y[1] - y) * N.y)* N.y;
Result.x[2] := t.x[2] - N2 *((t.x[2] - x) * N.x + (t.y[2] - y) * N.y)* N.x;
Result.y[2] := t.y[2] - N2 *((t.x[2] - x) * N.x + (t.y[2] - y) * N.y)* N.y;
end;
function ScaleTriangle(t: TTriangle; scale: double): TTriangle;
begin
Result.y[0] := scale * t.y[0];
Result.y[1] := scale * t.y[1];
Result.y[2] := scale * t.y[2];
Result.x[0] := scale * t.x[0];
Result.x[1] := scale * t.x[1];
Result.x[2] := scale * t.x[2];
end;
function ScaleTriangleXY(t: TTriangle; axis: integer; scale: double): TTriangle; // AV
begin
Result := t;
if scale < 1e-64 then Exit;
Result.x[axis] := scale * (t.x[axis] - t.x[1]) + t.x[1];
Result.y[axis] := scale * (t.y[axis] - t.y[1]) + t.y[1];
end;
function ScaleTriangleO(t: TTriangle; x, y, scale: double): TTriangle; // AV
begin
Result.x[1] := scale * (t.x[1] - x) + x;
Result.y[1] := scale * (t.y[1] - y) + y;
Result.x[0] := t.x[0] - t.x[1] + Result.x[1];
Result.y[0] := t.y[0] - t.y[1] + Result.y[1];
Result.x[2] := t.x[2] - t.x[1] + Result.x[1];
Result.y[2] := t.y[2] - t.y[1] + Result.y[1];
end;
function RotateTriangleO(t: TTriangle; x, y, rad: double): TTriangle;
begin
Result.x[1] := x + (t.x[1] - x) * cos(rad) - (t.y[1] - y) * sin(rad);
Result.y[1] := y + (t.x[1] - x) * sin(rad) + (t.y[1] - y) * cos(rad);
Result.x[0] := t.x[0] - t.x[1] + Result.x[1];
Result.y[0] := t.y[0] - t.y[1] + Result.y[1];
Result.x[2] := t.x[2] - t.x[1] + Result.x[1];
Result.y[2] := t.y[2] - t.y[1] + Result.y[1];
end;
function RotateTriangleXY(t: TTriangle; axis: integer; rad: double): TTriangle; // AV
begin
Result := t;
Result.x[axis] := t.x[1] + (t.x[axis] - t.x[1]) * cos(rad) - (t.y[axis] - t.y[1]) * sin(rad);
Result.y[axis] := t.y[1] + (t.x[axis] - t.x[1]) * sin(rad) + (t.y[axis] - t.y[1]) * cos(rad);
end;
function Centroid(t: TTriangle): TSPoint;
begin
Result.x := (t.x[0] + t.x[1] + t.x[2]) / 3;
Result.y := (t.y[0] + t.y[1] + t.y[2]) / 3;
end;
function ScaleTriangleCenter(t: TTriangle; scale: double): TTriangle;
var
xr, yr: double;
z: TSPoint;
begin
assert(scale <> 0);
z := Centroid(t);
xr := z.x;
yr := z.y;
Result.y[0] := scale * (t.y[0] - yr) + yr;
Result.y[1] := scale * (t.y[1] - yr) + yr;
Result.y[2] := scale * (t.y[2] - yr) + yr;
Result.x[0] := scale * (t.x[0] - xr) + xr;
Result.x[1] := scale * (t.x[1] - xr) + xr;
Result.x[2] := scale * (t.x[2] - xr) + xr;
end;
function ScaleTrianglePoint(t: TTriangle; x, y, scale: double): TTriangle;
begin
//assert(scale <> 0);
if scale = 0 then scale := 1e-64;
Result.y[0] := scale * (t.y[0] - y) + y;
Result.y[1] := scale * (t.y[1] - y) + y;
Result.y[2] := scale * (t.y[2] - y) + y;
Result.x[0] := scale * (t.x[0] - x) + x;
Result.x[1] := scale * (t.x[1] - x) + x;
Result.x[2] := scale * (t.x[2] - x) + x;
end;
function RotateTriangle(t: TTriangle; rad: double): TTriangle; //rad in Radians
var
i: integer;
begin
for i := 0 to 2 do
begin
Result.x[i] := t.x[i] * cos(rad) - t.y[i] * sin(rad);
Result.y[i] := t.x[i] * sin(rad) + t.y[i] * cos(rad);
end;
end;
function OffsetTriangle(t: TTriangle; range: double): TTriangle;
var
i: integer;
r: double;
begin
r := (random * 2 * range) - range;
for i := 0 to 2 do
begin
Result.x[i] := t.x[i] + r;
Result.y[i] := t.y[i] + r;
end;
end;
function RotateTriangleCenter(t: TTriangle; rad: double): TTriangle;
var
i: integer;
xr, yr: double;
z: TSPoint;
begin
z := Centroid(t);
xr := z.x;
yr := z.y;
for i := 0 to 2 do
begin
Result.x[i] := xr + (t.x[i] - xr) * cos(rad) - (t.y[i] - yr) * sin(rad);
Result.y[i] := yr + (t.x[i] - xr) * sin(rad) + (t.y[i] - yr) * cos(rad);
end;
end;
function RotateTrianglePoint(t: TTriangle; xr, yr: double; rad: double): TTriangle;
var
i: integer;
begin
for i := 0 to 2 do
begin
Result.x[i] := xr + (t.x[i] - xr) * cos(rad) - (t.y[i] - yr) * sin(rad);
Result.y[i] := yr + (t.x[i] - xr) * sin(rad) + (t.y[i] - yr) * cos(rad);
end;
end;
function ColorValToColor(c: TColorMap; index: double): TColor;
var
i: integer;
begin
i := Trunc(Index * 255);
assert(i >= 0);
assert(i < 256);
result := c[i][2] shl 16 + c[i][1] shl 8 + c[i][0];
end;
procedure TEditForm.UpdatePreview;
var
pw, ph: integer;
begin
pw := PrevPnl.Width -2;
ph := PrevPnl.Height -2;
if (cp.width / cp.height) > (pw / ph) then
begin
PreviewImage.Width := pw;
assert(pw <> 0);
PreviewImage.Height := round(cp.height / cp.Width * pw);
PreviewImage.Left := 1;
PreviewImage.Top := (ph - PreviewImage.Height) div 2;
end
else begin
PreviewImage.Height := ph;
assert(ph <> 0);
PreviewImage.Width := round(cp.Width / cp.Height * ph);
PreviewImage.Top := 1;
PreviewImage.Left := (pw - PreviewImage.Width) div 2;
end;
cp.AdjustScale(PreviewImage.Width, PreviewImage.Height);
DrawPreview;
TriangleViewPaint(TriangleView);
end;
procedure TEditForm.UpdateVariationList; // AV: adjust the var_order
var
s: string;
svars: TStringList;
begin
svars := TStringList.Create;
with cp.xform[SelectedTriangle] do
for s in ifs do
svars.AddPair(s, Round6(GetVariation(GetVariationIndex(s))).ToString);
VEVars.Strings.Assign(svars);
svars.Free;
end;
procedure TEditForm.UpdateXformsList;
var
i, n: integer;
prefix: string;
begin
cbTransforms.Clear;
for i := 1 to Transforms do begin
cbTransforms.Items.Add(IntToStr(i));
end;
if EnableFinalXform or cp.HasFinalXForm then
cbTransforms.Items.Add(TextByKey('editor-common-finalxformlistitem'));
cbTransforms.ItemIndex := SelectedTriangle;
if mnuChaosViewTo.Checked then prefix := TextByKey('editor-common-toprefix')
else prefix := TextByKey('editor-common-fromprefix');
n := Transforms + 1;
while vleChaos.RowCount > n do
vleChaos.DeleteRow(vleChaos.RowCount-1);
while vleChaos.RowCount < n do
vleChaos.InsertRow(Format(prefix, [vleChaos.RowCount]), '1', true);
UpdateVariationList; // AV
chkCollapseVariablesClick(nil);
chkCollapseVariationsClick(nil);
FillSyncTrianglesMenu; // AV
if (SelectedTriangle < Transforms) and (SelectedTriangle >= 0) then
begin
mnuSyncTriangles.Items[SelectedTriangle].Checked := True;
SyncTriangles := [SelectedTriangle];
end
else
SyncTriangles := [];
end;
procedure TEditForm.UpdateDisplay(PreviewOnly: boolean = false);
begin
// currently EditForm does not really know if we select another
// flame in the Main Window - which is not good...
cp.copy(MainCp);
if SelectedTriangle > LastTriangle{???} then
begin
SelectedTriangle := cp.NumXForms-1;
mouseOverTriangle := -1;
end;
EnableFinalXform := cp.finalXformEnabled;
tbEnableFinalXform.Down := EnableFinalXform;
UpdatePreview;
if PreviewOnly then exit;
cp.cmap := MainCp.cmap;
cmap := MainCp.cmap;
UpdateXformsList;
UpdateColorBar;
UpdateVariationList; // AV
// just in case:
SetCaptureControl(nil);
HasChanged := false;
// viewDragMode := false;
varDragMode := false;
pnlDragMode := false;
CornerCaught := false;
EdgeCaught := false;
TriangleCaught := false;
cp.TrianglesFromCP(MainTriangles);
ShowSelectedInfo;
if MainForm.UndoIndex = 0 then AutoZoom // auto-zoom only on 'new' flame
else TriangleView.Invalidate;
end;
procedure TEditForm.DrawPreview;
begin
if EnableEditorPreview then exit;
//Render.Stop;
cp.sample_density := PreviewDensity;
cp.spatial_oversample := defOversample;
cp.spatial_filter_radius := defFilterRadius;
if mnuResetLoc.checked then
begin
cp.zoom := 0;
cp.CalcBoundbox;
end;
cp.cmap := MainCp.cmap;
Render.SetCP(cp);
Render.Render;
PreviewImage.Picture.Bitmap.Assign(Render.GetImage);
PreviewImage.refresh;
end;
procedure TEditForm.ShowSelectedInfo;
var
i: integer;
v: double;
strval: string;
begin
updating := true;
if (SelectedTriangle > LastTriangle) then
SelectedTriangle := LastTriangle;
for i := 0 to Transforms - 1 do
begin
// AV: it's technically impossible inside this loop
{
if (i >= Transforms) then begin
if (cbTransforms.Items.Count > Transforms) then
cbTransforms.Items[i] := TextByKey('editor-common-finalxformlistitem');
end else begin
n := i + 1;
}
if (cp.xform[i].TransformName <> '') then
cbTransforms.Items[i] := IntToStr(i + 1) + ' - ' + cp.xform[i].TransformName
else
cbTransforms.Items[i] := IntToStr(i + 1);
// end;
end;
cbTransforms.ItemIndex := SelectedTriangle;
cbTransforms.Refresh;
with MainTriangles[SelectedTriangle] do
begin
txtAx.text := Format('%.6g', [x[0]]);
txtAy.text := Format('%.6g', [y[0]]);
txtBx.text := Format('%.6g', [x[1]]);
txtBy.text := Format('%.6g', [y[1]]);
txtCx.text := Format('%.6g', [x[2]]);
txtCy.text := Format('%.6g', [y[2]]);
end;
with cp.xform[SelectedTriangle] do
begin
if btnCoefsRect.Down then begin
txtA.text := Format('%.6g', [ c[0][0]]);
txtB.text := Format('%.6g', [-c[0][1]]);
txtC.text := Format('%.6g', [-c[1][0]]);
txtD.text := Format('%.6g', [ c[1][1]]);
txtE.text := Format('%.6g', [ c[2][0]]);
txtF.text := Format('%.6g', [-c[2][1]]);
txtPost00.text := Format('%.6g', [ p[0][0]]);
txtPost01.text := Format('%.6g', [-p[0][1]]);
txtPost10.text := Format('%.6g', [-p[1][0]]);
txtPost11.text := Format('%.6g', [ p[1][1]]);
txtPost20.text := Format('%.6g', [ p[2][0]]);
txtPost21.text := Format('%.6g', [-p[2][1]]);
end
else begin
txtA.text := Format('%.6g', [Hypot(c[0][0], c[0][1])]);
txtB.text := Format('%.6g', [arctan2(-c[0][1], c[0][0])*180/PI]);
txtC.text := Format('%.6g', [Hypot(c[1][0], c[1][1])]);
txtD.text := Format('%.6g', [arctan2(c[1][1], -c[1][0])*180/PI]);
txtE.text := Format('%.6g', [Hypot(c[2][0], c[2][1])]);
txtF.text := Format('%.6g', [arctan2(-c[2][1], c[2][0])*180/PI]);
txtPost00.text := Format('%.6g', [Hypot(p[0][0], p[0][1])]);
txtPost01.text := Format('%.6g', [arctan2(-p[0][1], p[0][0])*180/PI]);
txtPost10.text := Format('%.6g', [Hypot(p[1][0], p[1][1])]);
txtPost11.text := Format('%.6g', [arctan2(p[1][1], -p[1][0])*180/PI]);
txtPost20.text := Format('%.6g', [Hypot(p[2][0], p[2][1])]);
txtPost21.text := Format('%.6g', [arctan2(-p[2][1], p[2][0])*180/PI]);
end;
tbPostXswap.Down := postXswap;
tb2PostXswap.Down := postXswap;
CalcFlip; // AV
if postXswap then begin // AV: simplified
GroupBox9.Font.Style := [];
GroupBox8.Font.Style := [fsBold];
end
else begin
GroupBox8.Font.Style := [];
GroupBox9.Font.Style := [fsBold];
end;
chkAutoZscale.Checked := autoZscale;
txtName.Text := TransformName;
if (SelectedTriangle >= Transforms) then
begin
txtName.Text := 'n/a';
end;
if SelectedTriangle < Transforms then
begin
txtP.text := Format('%.6g', [density]);
txtP.Enabled := true;
txtName.Enabled := true;
vleChaos.Enabled := true;
optTo.Enabled := True; // AV
optFrom.Enabled := True; // AV
//chkXformInvisible.Enabled := true;
//chkXformInvisible.Checked := (transOpacity = 0);
chkXformSolo.Enabled := true;
txtOpacity.Enabled := true;
txtDC.Enabled := true;
btChaos.Visible := True; // AV
btClearChaos.Visible := True; // AV
btResetChaos.Visible := True; // AV
CopyChaos.Enabled := True; // AV
PasteChaos.Enabled := length(MemChaos) <> 0; // AV
if cp.soloXform >= 0 then begin
chkXformSolo.Checked := true;
chkXformSolo.Caption := Format(TextByKey('editor-tab-color-togglesoloformat'), [cp.soloXform + 1]);
end
else begin
chkXformSolo.Checked := false;
chkXformSolo.Caption := TextByKey('editor-tab-color-togglesolo');
end;
end
else begin // disable controls for FinalXform
txtP.Enabled := false;
txtP.Text := 'n/a';
txtName.Enabled := false;
vleChaos.Enabled := false;
btChaos.Visible := False; // AV
btClearChaos.Visible := False; // AV
btResetChaos.Visible := False; // AV
CopyChaos.Enabled := False; // AV
PasteChaos.Enabled := False; // AV
optTo.Enabled := False; // AV
optFrom.Enabled := False; // AV
//chkXformInvisible.Enabled := false;
//chkXformInvisible.Checked := false;
txtOpacity.Enabled := false;
chkXformSolo.Enabled := false;
end;
tbEnableFinalXform.Down := EnableFinalXform;
txtSymmetry.text := Format('%.6g', [symmetry]);
txtOpacity.text := Format('%.6g', [transOpacity]);
txtDC.Text := Format('%.6g', [pluginColor]);
pnlXFormColor.Color := ColorValToColor(cp.cmap, color);
shColor.Brush.Color := pnlXformColor.Color;
txtXFormColor.Text := Format('%1.3f', [color]);
scrlXFormcolor.Position := Trunc(color * scrlXFormColor.Max);
for i := 0 to NRVAR-1 do begin
v := GetVariation(i);
if v <> VarsCache[i] then
begin
VarsCache[i] := v;
VEVars.Values[VarNames(i)] := Format('%.6g', [v]);
end;
end;
for i:= 0 to GetNrVariableNames - 1 do begin
{$ifndef VAR_STR}
GetVariable(GetVariableNameAt(i), v);
strval := Format('%.6g', [v]);
{$else}
strval := GetVariableStr(GetVariableNameAt(i));
{$endif}
// kinda funny, but it really helped...
if vleVariables.Values[GetVariableNameAt(i)] <> strval then
vleVariables.Values[GetVariableNameAt(i)] := strval;
end;
//Assert(vleChaos.RowCount = Transforms+1);
if SelectedTriangle < Transforms then begin
if mnuChaosViewTo.Checked then
// view as "to" values
for i := 1 to Transforms do begin
strval := Format('%.6g', [modWeights[i - 1]]);
if vleChaos.Cells[1, i] <> strval then
vleChaos.Cells[1, i] := strval;
end
else
// view as "from" values
for i := 1 to Transforms do begin
strval := Format('%.6g', [cp.xform[i - 1].modWeights[SelectedTriangle]]);
if vleChaos.Cells[1, i] <> strval then
vleChaos.Cells[1, i] := strval;
end;
end
else
for i := 1 to vleChaos.RowCount-1 do
vleChaos.Cells[1, i] := 'n/a';
end;
//AV: moved checks here since Apo7X didn't refresh these pages well
// if cbCollapseVariations.ItemIndex = 1 then
chkCollapseVariationsClick(nil);
chkCollapseVariablesClick(nil);
if PivotMode = pivotLocal then begin
editPivotX.Text := Format('%.6g', [LocalPivot.x]);
editPivotY.Text := Format('%.6g', [LocalPivot.y]);
btnPivotMode.Caption := TextByKey('editor-tab-triangle-modelocal');
btnPivotMode.Hint := TextByKey('editor-tab-triangle-toworld');
tbPivotMode.Down := false;
end
else begin
editPivotX.Text := Format('%.6g', [WorldPivot.x]);
editPivotY.Text := Format('%.6g', [WorldPivot.y]);
btnPivotMode.Caption := TextByKey('editor-tab-triangle-modeworld');
btnPivotMode.Hint := TextByKey('editor-tab-triangle-tolocal');
tbPivotMode.Down := true;
end;
PageControl.Refresh;
updating := false;
end;
{/////////////////////////////////////////////////// }
procedure TEditForm.FillSyncTrianglesMenu; // AV
var
i: byte;
t: TMenuItem;
pic: TBitMap;
defStyle: boolean;
begin
mnuSyncTriangles.Items.Clear;
pic := TBitmap.Create;
pic.Width := 16;
pic.Height := 16;
if (CurrentStyle = 'Windows') then
begin
pic.Transparent := True;
pic.TransparentColor := clWhite;
defStyle := True;
end
else
defStyle := False;
for i := 0 to Transforms - 1 do
begin
t := TMenuItem.Create(self);
t.Caption := IntToStr(i + 1);
t.Tag := i;
t.AutoCheck := True;
with pic.Canvas do
begin
brush.Color := clWhite;
FillRect(Rect(0, 0, 16, 16));
pen.Color := TrgColors[i mod 14];
brush.Color := pen.Color shr 1 and $7f7f7f;
Polygon([Point(15, 5), Point(15, 15), Point(5, 15)]);
end;
t.Bitmap.Assign(pic);
t.OnClick := SyncTrianglesClick;
if defStyle then
t.OnAdvancedDrawItem := SyncTrianglesDrawItem
else
// AV: it's better to rely on RTL rather than adjust colors for every theme manually
t.OnAdvancedDrawItem := nil;
mnuSyncTriangles.Items.Add(t);
end;
pic.Free;
i := 0;
while i < mnuSyncTriangles.Items.Count do
begin
mnuSyncTriangles.Items[i].Break := mbBreak;
inc(i, mbHeight);
end;
end;
procedure TEditForm.SynchronizeAllClick(Sender: TObject);
var i: smallint;
begin
for i := 0 to mnuSyncTriangles.Items.Count - 1 do
begin
mnuSyncTriangles.Items[i].Checked := True;
Include(SyncTriangles, i);
end;
end;
procedure TEditForm.SyncTrianglesClick(Sender: TObject); // AV
begin
if (SelectedTriangle < Transforms) and
(Sender = mnuSyncTriangles.Items[SelectedTriangle]) then
TMenuItem(Sender).Checked := True;
if TMenuItem(Sender).Checked then
Include(SyncTriangles, TMenuItem(Sender).Tag)
else
Exclude(SyncTriangles, TMenuItem(Sender).Tag);
end;
procedure TEditForm.SyncTrianglesDrawItem(Sender: TObject; ACanvas: TCanvas;
ARect: TRect; State: TOwnerDrawState);
begin
ACanvas.Draw(ARect.Left + 10, ARect.Top, TMenuItem(Sender).Bitmap);
if not (odSelected in State) then
begin
ACanvas.Brush.Color := clMenu;
ACanvas.Font.Color := clMenuText;
end;
if TMenuItem(Sender).Tag = SelectedTriangle then
ACanvas.Font.Style := [fsBold];
ACanvas.TextOut(ARect.Left + 30, ARect.Top + 2, TMenuItem(Sender).Caption);
if (odChecked in State) then
DrawCheck(ACanvas, Point(ARect.Left + 5, ARect.Top + 10), 3);
end;
{/////////////////////////////////////////////////// }
procedure TEditForm.CreateScreenShot;
begin
SaveScreenShot('Apophysis Transform Editor');
end;
procedure TEditForm.ExtSysMenu(var Msg: TMessage);
begin
if Msg.WParam = $C0 then CreateScreenShot;
inherited;
end;
{ /////////////// AV: arrow buttons for all num fields //////////////// }
procedure TEditForm.SpinButtonDownClick(Sender: TObject);
var
step, n: double;
ANumEdit: TEdit;
begin
step := 0.01;
if GetKeyState(VK_MENU) < 0 then step := 0.000001 // Alt
else if GetKeyState(VK_CONTROL) < 0 then step := 0.0001
else if GetKeyState(VK_SHIFT) < 0 then step := 0.1;
try
ANumEdit := TEdit((Sender as TSpinButton).FocusControl);
n := StrToFloat(ANumEdit.Text);
ANumEdit.Text := Format('%.6g', [n - step]);
ANumEdit.OnExit(ANumEdit);
except
// do nothing
end;
end;
procedure TEditForm.SpinButtonUpClick(Sender: TObject);
var
step, n: double;
ANumEdit: TEdit;
begin
step := 0.01;
if GetKeyState(VK_MENU) < 0 then step := 0.000001 // Alt
else if GetKeyState(VK_CONTROL) < 0 then step := 0.0001
else if GetKeyState(VK_SHIFT) < 0 then step := 0.1;
try
ANumEdit := TEdit((Sender as TSpinButton).FocusControl);
n := StrToFloat(ANumEdit.Text);
ANumEdit.Text := Format('%.6g', [n + step]);
ANumEdit.OnExit(ANumEdit);
except
// do nothing
end;
end;
{ ////////////////////////////////////////////////////////////////// }
procedure TEditForm.Scale(var fx, fy: double; x, y: integer);
var
sc: double;
begin
sc := 50 * GraphZoom;
fx := (x - (TriangleView.Width / 2)) / sc + gCenterX;
fy := -((y - (TriangleView.Height / 2)) / sc - gCentery);
end;
procedure TEditForm.AddContainerClick(Sender: TObject);
var
i: integer;
sumw: double;
begin
if (Transforms < NXFORMS) then
begin
MainForm.UpdateUndo;
MainTriangles[Transforms + 1] := MainTriangles[Transforms];
cp.xform[Transforms + 1].Assign(cp.xform[Transforms]);
MainTriangles[Transforms] := MainTriangles[-1];
for i := 0 to Transforms-1 do
cp.xform[i].TransOpacity := 0;
cp.xform[Transforms].Clear;
cp.xform[Transforms].symmetry := 1;
cp.xform[Transforms].SetVariation(0, 1);
cp.xform[Transforms].modWeights[Transforms] := 0;
if InheritWeights.Checked then begin
sumw := 0;
for i := 0 to Transforms-1 do
sumw := sumw + cp.xform[i].density;
cp.xform[Transforms].density := sumw;
end else
cp.xform[Transforms].density := 0.5;
SelectedTriangle := Transforms;
cp.xform[SelectedTriangle].TransformName := 'Container TX';
Inc(Transforms);
UpdateXformsList;
UpdateFlame(True);
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
end;
procedure TEditForm.AffineCoefsDblClick(Sender: TObject); // AV
var
num: string;
begin
if not AllowResetCoefs then exit;
with TEdit(Sender) do // restore defaults
begin
if (Parent = gbCoordinates) or btnCoefsRect.Down then
num := IntToStr(Tag)
else // if btnCoefsPolar.Down then
begin
if (Left = 36) and (Top < 65) then // hack...
num := '1'
else if (Tag = 1) then
num := '90'
else num := '0';
end;
if Text <> num then
begin
Text := num;
OnExit(Sender);
end;
end;
end;
procedure TEditForm.AutoZoom;
var
i, j: integer;
xminz, yminz, xmaxz, ymaxz: double;
gxlength, gylength: double;
begin
xminz := 0;
yminz := 0;
xmaxz := 0;
ymaxz := 0;
for i := -1 to LastTriangle do
begin
for j := 0 to 2 do
begin
if MainTriangles[i].x[j] < xminz then xminz := MainTriangles[i].x[j];
if MainTriangles[i].y[j] < yminz then yminz := MainTriangles[i].y[j];
if MainTriangles[i].x[j] > xmaxz then xmaxz := MainTriangles[i].x[j];
if MainTriangles[i].y[j] > ymaxz then ymaxz := MainTriangles[i].y[j];
end;
end;
gxlength := xmaxz - xminz;
gylength := ymaxz - yminz;
gCenterX := xminz + gxlength / 2;
gCentery := yminz + gylength / 2;
if gxlength >= gylength then
GraphZoom := TriangleView.Width / 60 / gxlength
else
GraphZoom := TriangleView.Height / 60 / gylength;
EditForm.StatusBar.Panels[2].Text := Format(TextByKey('editor-status-zoomformat'), [GraphZoom]);
TriangleView.Invalidate;//Refresh;
end;
procedure TEditForm.UpdateFlameX;
begin
cp.GetFromTriangles(MainTriangles, Transforms);
if tbAutoWeights.Down then cp.CalculateWeights; //cp.ComputeWeights(MainTriangles, Transforms);
DrawPreview;
ShowSelectedInfo;
TriangleView.Refresh;
end;
procedure TEditForm.UpdateFlame(DrawMain: boolean);
begin
StatusBar.Panels[2].Text := Format(TextByKey('editor-status-zoomformat'), [GraphZoom]);
cp.GetFromTriangles(MainTriangles, LastTriangle);
DrawPreview;
ShowSelectedInfo;
TriangleView.Refresh;
if DrawMain then begin
MainForm.StopThread;
MainCp.Copy(cp, true);
MainCp.cmap := cmap;
if mnuResetLoc.checked then begin
MainCp.zoom := 0;
MainForm.center[0] := cp.center[0];
MainForm.center[1] := cp.center[1];
end;
if AdjustForm.Visible then AdjustForm.UpdateDisplay;
if MutateForm.Visible then MutateForm.UpdateDisplay;
MainForm.RedrawTimer.enabled := true;
end;
// AV: following is included into ShowSelectedInfo
//chkCollapseVariablesClick(nil);
//chkCollapseVariationsClick(nil);
end;
procedure TEditForm.UpdateWidgets;
function Point(x, y: double): TSPoint;
begin
Result.x := x;
Result.y := y;
end;
begin
with mainTriangles[Selectedtriangle] do
begin
xx := x[0] - x[1];
xy := y[0] - y[1];
yx := x[2] - x[1];
yy := y[2] - y[1];
Widgets[0][0] := Point(x[1] + 0.8*xx + yx, y[1] + 0.8*xy + yy);
Widgets[0][1] := Point(x[1] + xx + yx, y[1] + xy + yy);
Widgets[0][2] := Point(x[1] + xx + 0.8*yx, y[1] + xy + 0.8*yy);
Widgets[1][0] := Point(x[1] - 0.8*xx + yx, y[1] - 0.8*xy + yy);
Widgets[1][1] := Point(x[1] - xx + yx, y[1] - xy + yy);
Widgets[1][2] := Point(x[1] - xx + 0.8*yx, y[1] - xy + 0.8*yy);
Widgets[2][0] := Point(x[1] - 0.8*xx - yx, y[1] - 0.8*xy - yy);
Widgets[2][1] := Point(x[1] - xx - yx, y[1] - xy - yy);
Widgets[2][2] := Point(x[1] - xx - 0.8*yx, y[1] - xy - 0.8*yy);
Widgets[3][0] := Point(x[1] + 0.8*xx - yx, y[1] + 0.8*xy - yy);
Widgets[3][1] := Point(x[1] + xx - yx, y[1] + xy - yy);
Widgets[3][2] := Point(x[1] + xx - 0.8*yx, y[1] + xy - 0.8*yy);
end;
end;
procedure TEditForm.DeleteTriangle(t: integer);
var
i, j, nmin, nmax: integer;
lx, ps: integer;
txname: string;
begin
if (t = Transforms) then
begin
assert(cp.HasFinalXForm or EnableFinalXform);
MainForm.UpdateUndo;
EnableFinalXform := false;
cp.finalXformEnabled := false;
cp.xform[Transforms].Clear;
cp.xform[Transforms].symmetry := 1;
assert(cp.HasFinalXForm = false);
MainTriangles[Transforms] := MainTriangles[-1];
tbEnableFinalXform.Down := false;
if (SelectedTriangle = Transforms) then Dec(SelectedTriangle);
end
else
if (Transforms <= 1) then exit
else begin
MainForm.UpdateUndo;
for i := 0 to Transforms-1 do
begin
if (pos('link', cp.xform[i].TransformName) > 0) then
begin
// AV: correcting the numbers in linked transforms' names
if i = t then continue;
txname := cp.xform[i].TransformName;
ps := pos('TX ', txname) + 3;
txname := copy(txname, ps, length(txname) - ps + 1);
try // if user didn't change the original name
lx := StrToInt(txname) - 1;
if (lx = t) then cp.xform[i].TransformName := ''
else if (lx > t) then
cp.xform[i].TransformName := copy(cp.xform[i].TransformName, 1, ps - 1) + IntToStr(lx);
except
// leave the name as is
end;
end;
end;
if RebuildXaosLinks then begin
// check for single "to" links
for i := 0 to NXFORMS-1 {Transforms-1} do
with cp.xform[i] do begin
nmin := NXFORMS;
nmax := -1;
for j := 0 to NXFORMS-1 {Transforms-1} do
if modWeights[j] <> 0 then begin
if j < nmin then nmin := j;
if j > nmax then nmax := j;
end;
if (nmin = nmax) and (nmin = t) then begin
for j := 0 to NXFORMS-1 {Transforms-1} do
modWeights[j] := cp.xform[t].modWeights[j];
if (transOpacity = 0) then begin
transOpacity := cp.xform[t].transOpacity;
end;
end;
end;
// check for single "from" links
for i := 0 to NXFORMS-1 {Transforms-1} do
begin
if cp.xform[t].modWeights[i] = 0 then continue;
nmin := NXFORMS;
nmax := -1;
for j := 0 to NXFORMS-1 {Transforms-1} do
if cp.xform[j].modWeights[i] <> 0 then begin
if j < nmin then nmin := j;
if j > nmax then nmax := j;
end;
if (nmin = nmax) and (nmin = t) then begin
for j := 0 to NXFORMS-1 {Transforms-1} do
cp.xform[j].modWeights[i] := cp.xform[t].modWeights[i];
end;
end;
if pos('Container TX', cp.xform[t].TransformName) > 0 then
for i := 0 to t-1 do
if (cp.xform[t].transOpacity = 0) then
cp.xform[t].transOpacity := 1;
end;
// delete xform from all probability tables
for i := 0 to NXFORMS-1 {Transforms-1} do
with cp.xform[i] do begin
for j := t to NXFORMS-1 {Transforms-1} do
modWeights[j] := modWeights[j+1];
modWeights[Transforms-1] := 1;
end;
if t = (Transforms - 1) then
begin
MainTriangles[t] := MainTriangles[Transforms];
cp.xform[t].Assign(cp.xform[Transforms]);
Dec(SelectedTriangle);
end
else begin
for i := t to Transforms-1 do // was: -2
begin
{ copy higher transforms down }
MainTriangles[i] := MainTriangles[i + 1];
cp.xform[i].Assign(cp.xform[i + 1]);
end;
end;
if cp.soloXform > t then Dec(cp.soloXform)
else if cp.soloXform = t then cp.soloXform := -1;
Dec(Transforms);
assert(cp.xform[transforms].density = 0); // cp.xform[transforms].density := 0;
end;
UpdateXformsList;
UpdateFlame(True);
end;
procedure TEditForm.InsertPi1Click(Sender: TObject);
var
num: double;
sn: string;
begin
if (not ValidNumField) then
begin
Application.MessageBox(PChar(TextByKey('editor-status-nonumfield')),
ApophysisSVN, MB_ICONWARNING);
exit;
end
else if (ActiveControl = txtTrgRotateValue) then exit;
case TMenuItem(Sender).Tag of
0: num := 3.14159265358979; // pi;
1: num := 6.28318530717959; // 2 * pi;
2: num := 1.5707963267949; // pi * 0.5;
3: num := 1.0471975511966; // pi/3;
4: num := 0.785398163397448; // pi * 0.25;
5: num := 0.523598775598299; // pi/6;
6: num := 0.288675134594813; // sqrt(3)/6;
7: num := 0.707106781186548; // sqrt(2) * 0.5;
8: num := 0.866025403784439; // sqrt(3) * 0.5;
9: num := 0.577350269189626; // sqrt(3)/3;
10: num := 1.73205080756888; // sqrt(3);
11: num := 0.618033988749895; // (sqrt(5)- 1) * 0.5;
else num := 0;
end;
if (ActiveControl = txtTrgScaleValue) then num := num * 100;
sn := Format('%.6g', [num]);
if (ActiveControl is TEdit) then
begin
TEdit(ActiveControl).Text := sn;
TEdit(ActiveControl).OnExit(ActiveControl);
end else if (ActiveControl is TValueListEditor) then
begin
TValueListEditor(ActiveControl).Cells[1, TValueListEditor(ActiveControl).Row] := sn;
TValueListEditor(ActiveControl).OnExit(ActiveControl);
end
else // if (ActiveControl is TComboBox) then
TComboBox(ActiveControl).Text := sn;
end;
function TEditForm.InsideTriangle(x, y: double): integer;
var
i, j, k: integer;
inside: boolean;
begin
{ is x, y inside a triangle }
Result := -1;
inside := False;
j := 2;
for k := LastTriangle downto 0 do
begin
for i := 0 to 2 do
begin
if (((MainTriangles[k].y[i] <= y) and
(y < MainTriangles[k].y[j])) or
((MainTriangles[k].y[j] <= y) and
(y < MainTriangles[k].y[i]))) and
(x < (MainTriangles[k].x[j] - MainTriangles[k].x[i]) *
(y - MainTriangles[k].y[i]) /
(MainTriangles[k].y[j] - MainTriangles[k].y[i]) +
MainTriangles[k].x[i]) then
Inside := not Inside;
j := i
end;
if inside then break;
end;
if inside then Result := k;
end;
function TEditForm.GetTriangleColor(n: integer): TColor;
begin
if n = Transforms then Result := clWhite
else
if UseTransformColors then
Result := ColorValToColor(MainCp.cmap, cp.xform[n].color)
else Result := TrgColors[n mod 14];
end;
procedure TEditForm.GridComboBoxChange(Sender: TObject);
begin
if tbVarPreview.Down then
TriangleView.Invalidate;
end;
procedure TEditForm.ResetToolsDblClick(Sender: TObject);
begin
RotateXYO.Checked := True;
ScaleXYO.Checked := True;
ShowModvals.Checked := False;
mnuChangeGridClick(RectGrid);
txtTrgRotateValue.Text := '15';
txtTrgScaleValue.Text := '125';
txtTrgMoveValue.Text := '0.1';
end;
procedure TEditForm.RedrawButtons;
begin
if IsLightMenu then
btnMathPopup.ImageIndex := 42 // white PI
else
btnMathPopup.ImageIndex := 32; // black PI
end;
function TEditForm.LastTriangle: integer;
begin
if EnableFinalXform or cp.HasFinalXForm then Result := Transforms
else Result := Transforms-1;
end;
procedure TEditForm.CalcFlip;
var ang: double;
begin
if (PivotMode = pivotLocal) or (mouseOverEdge >= 0) then
with MainTriangles[SelectedTriangle] do begin
fl.x := (x[0] - x[1]) * (FlipPoint.x - LocalPivot.x) + (x[2] - x[1]) * (FlipPoint.y - LocalPivot.y);
fl.y := (y[0] - y[1]) * (FlipPoint.x - LocalPivot.x) + (y[2] - y[1]) * (FlipPoint.y - LocalPivot.y);
end
else begin
fl.x := FlipPoint.x - WorldPivot.x;
fl.y := FlipPoint.y - WorldPivot.y;
end;
ang := RadToDeg(arctan2(fl.y, fl.x));
if (ang < 0) then ang := ang + 180.0
else if (ang = 180.0) then ang := 0.0;
lblFlipAngle.Caption := lblFlipAngle.Hint + Format(': %1.3g'#176, [ang]);
end;
procedure TEditForm.CalcArcsinScaleClick(Sender: TObject);
var t: double;
begin
try
t := StrToFloat(txtTrgScaleValue.Text) * 0.01;
if (abs(t) <= 1) then begin
t := RadToDeg(arcsin(t));
txtTrgRotateValue.Text := Format('%.6g', [t]);
end else
Application.MessageBox(PChar(TextByKey('editor-status-warnscale')),
ApophysisSVN, MB_ICONWARNING);
except
Beep;
end;
end;
procedure TEditForm.CalcCosClick(Sender: TObject);
var
num, t: double;
sn: string;
begin
if (not ValidNumField) then
begin
Application.MessageBox(PChar(TextByKey('editor-status-nonumfield')),
ApophysisSVN, MB_ICONWARNING);
exit;
end;
try
if (ActiveControl is TEdit) then
sn := TEdit(ActiveControl).Text
else if (ActiveControl is TValueListEditor) then
sn := TValueListEditor(ActiveControl).Cells[1, TValueListEditor(ActiveControl).Row]
else //if (ActiveControl is TComboBox) then
sn := TComboBox(ActiveControl).Text;
num := StrToFloat(sn);
if UseDegrees.Checked then
num := num * pi / 180;
case TMenuItem(Sender).Tag of
0: sn := Format('%.6g', [cos(num)]);
1: sn := Format('%.6g', [sin(num)]);
else begin
t := abs(cos(num));
if (t < 1E-6) then exit;
t := Round6(tan(num));
sn := FloatToStr(t);
end;
end;
if (ActiveControl is TEdit) then
begin
TEdit(ActiveControl).Text := sn;
TEdit(ActiveControl).OnExit(ActiveControl);
end
else if (ActiveControl is TValueListEditor) then
begin
TValueListEditor(ActiveControl).Cells[1, TValueListEditor(ActiveControl).Row] := sn;
TValueListEditor(ActiveControl).OnExit(ActiveControl);
end
else //if (ActiveControl is TComboBox) then
TComboBox(ActiveControl).Text := sn;
except
end;
end;
procedure TEditForm.mnuCalcExpressionClick(Sender: TObject); // AV
var
sn: string;
begin
if (not ValidNumField) then
begin
Application.MessageBox(PChar(TextByKey('editor-status-nonumfield')),
ApophysisSVN, MB_ICONWARNING);
exit;
end;
try
if (ActiveControl is TEdit) then
sn := TEdit(ActiveControl).Text
else if (ActiveControl is TValueListEditor) then
sn := TValueListEditor(ActiveControl).Cells[1,
TValueListEditor(ActiveControl).Row]
else // if (ActiveControl is TComboBox) then
sn := TComboBox(ActiveControl).Text;
if not InputQuery(TextByKey('editor-toolbar-calcexpression'),
TextByKey('editor-status-formula'), sn) then exit;
MathExpressions.InDegrees := UseDegrees.Checked;
sn := MathExpressions.CalculateExpression(LowerCase(sn));
if sn = '' then exit; // expression is not evaluated
if (ActiveControl is TEdit) then
begin
TEdit(ActiveControl).Text := sn;
TEdit(ActiveControl).OnExit(ActiveControl);
end
else if (ActiveControl is TValueListEditor) then
begin
TValueListEditor(ActiveControl).Cells[1,
TValueListEditor(ActiveControl).Row] := sn;
TValueListEditor(ActiveControl).OnExit(ActiveControl);
end
else //if (ActiveControl is TComboBox) then
TComboBox(ActiveControl).Text := sn;
except
Application.MessageBox(PChar(TextByKey('formula-cannotevaluate')),
ApophysisSVN, 16);
end;
end;
procedure TEditForm.TriangleViewPaint(Sender: TObject);
const
foc_ofs = 4;
foc_size = 32;
var
ix, iy, sc: double;
function ToScreen(fx, fy: double): TPoint;
begin
Result.x := integer(round(ix + (fx - gCenterX) * sc));
Result.y := integer(round(iy - (fy - gCenterY) * sc));
end;
procedure ToUnit(p: TPoint; var fx, fy: double);
begin
fx := (p.x - ix) / sc + gCenterX;
fy := (p.y + iy) / sc + gCenterY;
end;
var
dx, dy: double;
Width, Height: integer;
BitMap: TBitMap;
procedure LineDxDy;
var
k: double;
begin
if (dx <> 0) and (dy <> 0) then with Bitmap.Canvas do
begin
k := dy / dx;
if abs(k) < 1 then begin
MoveTo(0, round(iy - sc*(Pivot.y - ( ix/sc-GCenterX+Pivot.x)*k - GCenterY)));
LineTo(Width, round(iy - sc*(Pivot.y - (-ix/sc-GCenterX+Pivot.x)*k - GCenterY)));
end
else begin
MoveTo(round(ix + sc*(Pivot.x - (-iy/sc-GCenterY+Pivot.y)/k - GCenterX)), 0);
LineTo(round(ix + sc*(Pivot.x - ( iy/sc-GCenterY+Pivot.y)/k - GCenterX)), Height);
end;
end;
end;
procedure DrawFlipLine;
var k: double;
begin
with Bitmap.Canvas do
begin
k := fl.y / fl.x;
if abs(k) < 1 then begin
MoveTo(0, round(iy - sc*(GetPivot.y - ( ix/sc-GCenterX+GetPivot.x)*k - GCenterY)));
LineTo(Width, round(iy - sc*(GetPivot.y - (-ix/sc-GCenterX+GetPivot.x)*k - GCenterY)));
end
else begin
MoveTo(round(ix + sc*(GetPivot.x - (-iy/sc-GCenterY+GetPivot.y)/k - GCenterX)), 0);
LineTo(round(ix + sc*(GetPivot.x - ( iy/sc-GCenterY+GetPivot.y)/k - GCenterX)), Height);
end;
end;
end;
var
a, b, c: TPoint;
e, f: TPoint;
procedure DrawWidgets;
var
i: integer;
begin
with Bitmap.Canvas do
with MainTriangles[SelectedTriangle] do
begin
for i := 0 to 3 do
begin
a:=toscreen(Widgets[i][0].x, Widgets[i][0].y);
b:=toscreen(Widgets[i][1].x, Widgets[i][1].y);
c:=toscreen(Widgets[i][2].x, Widgets[i][2].y);
moveto(a.x, a.y);
lineto(b.x, b.y);
lineto(c.x, c.y);
end
end;
end;
var
i, n, tc, tn, lin: integer;
d, d1: double;
tx, ty: double;
tr, ta, den: double; // for (bi)polar grid
ax, ay: integer;
gridX1, gridX2, gridY1, gridY2, gi, gstep: double;
gp: TRoundToRange;
tps: TPenStyle;
tT: TTriangle;
txx, txy, tyx, tyy: double;
str, vvstr: string;
bf: TBlendFunction;
RenderCP : TControlPoint;
Renderer : TRenderer;
bm : TBitmap;
q, p0, p1: integer;
label DrawCorner;
begin
if (SelectedTriangle < 0) then begin
assert(false, 'Selected triangle < 0');
SelectedTriangle := 0;
end;
assert(TCustomDrawControl(Sender) = TriangleView);
if SelectedTriangle > LastTriangle then SelectedTriangle := LastTriangle;
BitMap := TBitMap.Create;
Width := TriangleView.Width;
Height := TriangleView.Height;
Bitmap.Width := Width;
Bitmap.Height := Height;
ix := Width / 2;
iy := Height / 2;
sc := 50 * GraphZoom;
try
with Bitmap.Canvas do
begin
try // who knows... ;)
gp:=round(log10(max(Width, Height)/sc))-1;
gstep:=power(10.0, gp);
except
gp:=0;
gstep:=1.0;
end;
a := ToScreen(MainTriangles[-1].x[0], MainTriangles[-1].y[0]);
b := ToScreen(MainTriangles[-1].x[1], MainTriangles[-1].y[1]);
c := ToScreen(MainTriangles[-1].x[2], MainTriangles[-1].y[2]);
brush.Color := EditorBkgColor;
FillRect(Rect(0, 0, Width, Height));
if EnableEditorPreview then begin
q := 0;
if EditPrevQual = 2 then q := 1;
p0 := TriangleView.Width div (2 - q);
p1 := TriangleView.Height div (2 - q);
RenderCp := cp.Clone;
RenderCp.Width := TriangleView.Width;
Rendercp.Height := TriangleView.Height;
RenderCp.pixels_per_unit := sc;
RenderCp.AdjustScale(p0, p1);
RenderCP.sample_density := PreviewDensity * 0.5;
RenderCP.spatial_oversample := 1;
RenderCP.spatial_filter_radius := 0.001;
RenderCp.center[0] := gCenterX ;
RenderCp.center[1] := -gCenterY ;
RenderCp.background[0] := EditorBkgColor and $ff;
RenderCp.background[1] := (EditorBkgColor and $ff00) shl 8;
RenderCp.background[2] := (EditorBkgColor and $ff0000) shl 16;
Render.SetCP(RenderCp);
Render.Render;
bf.BlendOp := AC_SRC_OVER;
bf.BlendFlags := 0;
bf.SourceConstantAlpha := 255 - EditorPreviewTransparency;
bf.AlphaFormat := 0;
bm := TBitmap.Create;
bm.Width := p0;
bm.Height := p1;
bm.Assign(Render.GetImage);
Windows.AlphaBlend(Handle, 0, 0,
TriangleView.Width, TriangleView.Height,
bm.Canvas.Handle, 0, 0, bm.Width, bm.Height, bf);
RenderCp.Destroy;
try
bm.Dormant;
bm.FreeImage;
finally
bm.Free;
end;
end;
Pen.Style := psSolid;
Pen.Width := 1;
// draw grid
Pen.Color := GridColor2;
gridX1:=gCenterX-ix/sc;
gridX2:=gCenterX+(Width-ix)/sc;
gridY1:=gCenterY-iy/sc;
gridY2:=gCenterY+(Height-iy)/sc;
gi:=RoundTo(gridX1, gp);
while gi <= gridX2 do
begin
ax:=integer(round(ix + (gi - gCenterX)*sc));
MoveTo(ax, 0);
LineTo(ax, Height);
gi:=gi+gstep;
end;
gi:=RoundTo(gridY1, gp);
while gi <= gridY2 do
begin
ay:=integer(round(iy - (gi - gCenterY)*sc));
MoveTo(0, ay);
LineTo(Width, ay);
gi:=gi+gstep;
end;
// draw axis
Pen.Color := GridColor1;
ax := integer(round(ix - gCenterX*sc));
ay := integer(round(iy + gCentery*sc));
MoveTo(ax, 0);
LineTo(ax, Height-1);
MoveTo(0, ay);
LineTo(Width-1, ay);
{Reference Triangle}
Pen.Style := psDot;
Pen.color := ReferenceTriangleColor;
brush.Color := gridColor1 shr 1 and $7f7f7f;
Polyline([a, b, c, a]);
brush.Color := EditorBkgColor;
Font.color := Pen.color;
TextOut(c.x-9, c.y-12, 'Y');
TextOut(a.x+2, a.y+1, 'X');
TextOut(b.x-8, b.y+1, 'O');
Pen.Style := psSolid;
// Draw Triangles
for i := 0 to LastTriangle do
begin
if i <> SelectedTriangle then Pen.Style := psDot;
with cp.xform[i] do // draw post-triangle
if postXswap or
((ShowAllXforms or (i = SelectedTriangle)) and (
(p[0,0]<>1) or (p[0,1]<>0) or
(p[1,0]<>0) or (p[1,1]<>1) or
(p[2,0]<>0) or (p[2,1]<>0) )) then
begin
Pen.Color := GetTriangleColor(i) shr 1 and $7f7f7f;
tps := Pen.Style;
Pen.Style := psDot;
cp.GetPostTriangle(tT, i);
txx := tT.x[0] - tT.x[1];
txy := tT.y[0] - tT.y[1];
tyx := tT.x[2] - tT.x[1];
tyy := tT.y[2] - tT.y[1];
a := ToScreen(tT.x[1] + txx + tyx, tT.y[1] + txy + tyy);
b := ToScreen(tT.x[1] - txx + tyx, tT.y[1] - txy + tyy);
e := ToScreen(tT.x[1] + txx - tyx, tT.y[1] + txy - tyy);
f := ToScreen(tT.x[1] - txx - tyx, tT.y[1] - txy - tyy);
Polyline([a, b, f, e, a]);
pen.Style := psSolid;
a := ToScreen(tT.x[1] - txx, tT.y[1] - txy);
b := ToScreen(tT.x[1] + txx, tT.y[1] + txy);
e := ToScreen(tT.x[1] + tyx, tT.y[1] + tyy);
f := ToScreen(tT.x[1] - tyx, tT.y[1] - tyy);
Polyline([a, b, e, f]);
if postXswap and ((i = SelectedTriangle) or ShowAllXforms) then
begin
Pen.Style := psDot;
cp.GetTriangle(tT, i);
a:=toscreen(tT.x[0], tT.y[0]);
moveto(a.x, a.y);
b:=toscreen(tT.x[2], tT.y[2]);
lineto(b.x, b.y);
pen.Style := psSolid;
b:=toscreen(tT.x[1], tT.y[1]);
lineto(b.x, b.y);
lineto(a.x, a.y);
end;
Pen.Style := tps;
end;
Pen.Color := GetTriangleColor(i);
a := ToScreen(MainTriangles[i].x[0], MainTriangles[i].y[0]);
b := ToScreen(MainTriangles[i].x[1], MainTriangles[i].y[1]);
c := ToScreen(MainTriangles[i].x[2], MainTriangles[i].y[2]);
if pen.Style <> psSolid then
Polyline([a, b, c, a])
else begin
Polyline([a, b, c]);
Pen.Style := psDot;
brush.Color := pen.color shr 1 and $7f7f7f;
Polyline([c, a]);
brush.Color := EditorBkgColor;
end;
Pen.Style := psSolid;
Ellipse(a.x - 4, a.y - 4, a.x + 4, a.y + 4);
Ellipse(b.x - 4, b.y - 4, b.x + 4, b.y + 4);
Ellipse(c.x - 4, c.y - 4, c.x + 4, c.y + 4);
Font.color := Pen.color;
TextOut(c.x+2, c.y+1, 'Y');
TextOut(a.x+2, a.y+1, 'X');
TextOut(b.x+2, b.y+1, 'O');
end;
UpdateWidgets;
if ExtendedEdit then begin
n := GetTriangleColor(SelectedTriangle);// shr 1 and $7f7f7f;
if mouseOverTriangle <> SelectedTriangle then n := n shr 1 and $7f7f7f;
Pen.Color := n;
Pen.Mode := pmMerge;
DrawWidgets;
if mouseOverWidget >= 0 then
begin
pen.Color := pen.Color shr 1 and $7f7f7f;
pen.Width := 4;
DrawWidgets;
pen.Width := 1;
end;
end;
if showVarPreview then
begin
assert(trkVarPreviewRange.position > 0);
assert(trkVarPreviewDensity.position > 0);
cp.xform[SelectedTriangle].Prepare;
n := trkVarPreviewRange.position * trkVarPreviewDensity.position * 5;
d1 := trkVarPreviewDensity.position * 5;
tc := GetTriangleColor(SelectedTriangle);
// AV: draw the variation preview in the selected coordinate system
case GridComboBox.ItemIndex of
0: begin // transform rectangular grid
for ax := -n to n do
for ay := -n to n do
try
tx := ax / d1;
ty := ay / d1;
for i := trkVarPreviewDepth.position downto 1 do
cp.xform[SelectedTriangle].NextPointXY(tx, ty);
a := toscreen(tx, -ty);
Pixels[a.x, a.y] := tc;
except
end;
end;
1: begin // transform polar grid
try
tx := 0; ty := 0; // origin
for i := trkVarPreviewDepth.position downto 1 do
cp.xform[SelectedTriangle].NextPointXY(tx, ty);
a := ToScreen(tx, -ty);
Pixels[a.x, a.y] := tc;
except
end;
for ax := -2*n to 2*n do
for ay := 1 to n do
try
tr := ay/d1;
ta := ax * PI/2/n;
tx := tr * cos(ta);
ty := tr * sin(ta);
for i := trkVarPreviewDepth.position downto 1 do
cp.xform[SelectedTriangle].NextPointXY(tx, ty);
a := ToScreen(tx, -ty);
Pixels[a.x, a.y] := tc;
except
end;
end;
2: begin // transform bipolar grid
for ax := -2*n to 2*n do
for ay := -n to n do
try
tr := ay/d1;
ta := ax * PI/2/n;
den := cosh(tr) - cos(ta);
tx := sinh(tr)/den;
ty := sin(ta)/den;
for i := trkVarPreviewDepth.position downto 1 do
cp.xform[SelectedTriangle].NextPointXY(tx, ty);
a := ToScreen(tx, -ty);
Pixels[a.x, a.y] := tc;
except
end;
end;
else begin // transform elliptic grid
for ax := -2*n to 2*n do
for ay := 0 to n do
try
tr := ay/d1;
ta := ax * PI/2/n;
tx := cosh(tr) * cos(ta);
ty := sinh(tr) * sin(ta);
for i := trkVarPreviewDepth.position downto 1 do
cp.xform[SelectedTriangle].NextPointXY(tx, ty);
a := ToScreen(tx, -ty);
Pixels[a.x, a.y] := tc;
except
end;
end;
end;
end;
// *********** Reflection stuff ****************************
if ShowFlipLine then
begin
pen.Color := FlipColor;
pen.Mode := pmMerge;
pen.Style := psSolid;
CalcFlip;
if (fl.x <> 0) and (fl.y <> 0) then
DrawFlipLine
else if (fl.x = 0) and (fl.y <> 0)then
begin
lin := round(ix + (GetPivot.x - gCenterX) * sc);
MoveTo(lin, 0);
LineTo(lin, Height);
end
else if (fl.y = 0) and (fl.x <> 0) then
begin
lin := round(iy - (GetPivot.y - gCenterY) * sc);
MoveTo(0, lin);
LineTo(Width, lin);
end;
end;
//****************************************************
if (TriangleCaught or CornerCaught) then // if dragging, draw pivot axis
begin
mouseOverTriangle := SelectedTriangle;
if HelpersEnabled then
begin
pen.Color := HelpersColor;
pen.Mode := pmMerge;
pen.Style := psSolid;
a := ToScreen(Pivot.x, Pivot.y);
MoveTo(a.x, 0);
LineTo(a.x, Height);
MoveTo(0, a.y);
LineTo(Width, a.y);
if (editMode = modeRotate) then // draw circle
begin
if CornerCaught then begin
dx := MainTriangles[SelectedTriangle].x[SelectedCorner] - Pivot.x;
dy := MainTriangles[SelectedTriangle].y[SelectedCorner] - Pivot.y;
d := Hypot(dx, dy);
end
else begin
dx := MainTriangles[SelectedTriangle].x[0] - Pivot.x;
dy := MainTriangles[SelectedTriangle].y[0] - Pivot.y;
d := Hypot(dx, dy);
for i := 1 to 2 do
begin
d1 := dist(Pivot.x, Pivot.y, MainTriangles[SelectedTriangle].x[i], MainTriangles[SelectedTriangle].y[i]);
if d1 > d then
begin
if d > 0 then begin
dx := dx/d*d1;
dy := dy/d*d1;
end;
d := d1;
end;
end;
end;
i := integer(round(d * sc));
if i > 4 then
begin
pen.Color := HelpersColor;
brush.Style := bsClear;
Ellipse(a.x - i, a.y - i, a.x + i, a.y + i);
a := ToScreen(Pivot.x - dy, Pivot.y + dx);
b := ToScreen(Pivot.x + dy, Pivot.y - dx);
c := ToScreen(Pivot.x, Pivot.y);
MoveTo(a.x, a.y);
LineTo(c.X, c.y);
LineTo(b.X, b.y);
end;
// rotated axis
LineDxDy;
end
else if (editMode = modeScale) then // draw lines
begin
if CornerCaught then begin
dx := MainTriangles[SelectedTriangle].x[SelectedCorner] - Pivot.x;
dy := MainTriangles[SelectedTriangle].y[SelectedCorner] - Pivot.y;
LineDxDy;
end
else begin // hmmm...
dx := MainTriangles[SelectedTriangle].x[0] - Pivot.x;
dy := MainTriangles[SelectedTriangle].y[0] - Pivot.y;
LineDxDy;
dx := MainTriangles[SelectedTriangle].x[1] - Pivot.x;
dy := MainTriangles[SelectedTriangle].y[1] - Pivot.y;
LineDxDy;
dx := MainTriangles[SelectedTriangle].x[2] - Pivot.x;
dy := MainTriangles[SelectedTriangle].y[2] - Pivot.y;
LineDxDy;
end;
end
else // if editMode = modeMove then // draw target axis
begin
Pen.Color := HelpersColor;
Pen.Mode := pmMerge;//Xor;
brush.Color := 0;
if CornerCaught then
a := ToScreen(MainTriangles[SelectedTriangle].x[SelectedCorner],
MainTriangles[SelectedTriangle].y[SelectedCorner])
else
a := ToScreen(GetPivot.x, GetPivot.y);
MoveTo(a.x, 0);
LineTo(a.x, Height);
MoveTo(0, a.y);
LineTo(Width, a.y);
Pen.Mode := pmCopy;
end;
end; // endif HelpersEnabled
end;
if (mouseOverTriangle >= 0) then // highlight triangle under cursor
begin
with MainTriangles[mouseOverTriangle] do begin
a := ToScreen(x[0], y[0]);
b := ToScreen(x[1], y[1]);
c := ToScreen(x[2], y[2]);
end;
pen.Width:=2;
Pen.Color:=GetTriangleColor(mouseOverTriangle) shr 1 and $7f7f7f;
Pen.Mode:=pmMerge;
brush.Color:=Pen.Color shr 1 and $7f7f7f;
if (SelectMode and (editMode <> modePick)) or (mouseOverTriangle = SelectedTriangle) then
Polygon([a, b, c])
else
PolyLine([a, b, c, a]);
pen.width:=4;
Ellipse(a.x - 3, a.y - 3, a.x + 3, a.y + 3);
Ellipse(b.x - 3, b.y - 3, b.x + 3, b.y + 3);
Ellipse(c.x - 3, c.y - 3, c.x + 3, c.y + 3);
pen.width:=1;
pen.mode:=pmCopy;
if not (CornerCaught or TriangleCaught) then // show used variations
begin
font.Color := GetTriangleColor(mouseOverTriangle);
brush.Style := bsClear;
ay := Height-foc_ofs*2 + font.Height; // font.height < 0
for i:= NRVAR - 1 downto 0 do
if cp.xform[mouseOverTriangle].GetVariation(i) <> 0 then
begin
// AV: hack, inspired by Apo 2.09
if (pos('julian', Varnames(i))> 0) or (pos('julia3D', Varnames(i))> 0)
or (pos('juliascope', Varnames(i))> 0) then
begin
vvstr := Varnames(i) + '_power = ' +
cp.xform[mouseOverTriangle].GetVariableStr(Varnames(i) + '_power');
ax := Width-foc_ofs*2 - TextWidth(vvstr);
TextOut(ax, ay, vvstr);
Inc(ay, font.Height);
end else
if (Varnames(i) = 'affine3D') or (Varnames(i) = 'trianglecrop')
or (Varnames(i) = 'projective') or (Varnames(i) = 'spherecrop') then
begin
vvstr := Varnames(i) + '_mode';
vvstr := vvstr + ' = ' + cp.xform[mouseOverTriangle].GetVariableStr(vvstr);
ax := Width-foc_ofs*2 - TextWidth(vvstr);
TextOut(ax, ay, vvstr);
Inc(ay, font.Height);
end;
vvstr := Varnames(i) + Format(' = %.6g', [cp.xform[mouseOverTriangle].GetVariation(i)]);
ax := Width-foc_ofs*2 - TextWidth(vvstr);
TextOut(ax, ay, vvstr);
Inc(ay, font.Height);
end;
// brush.Style := bsSolid;
end;
end;
pen.color := clWhite;
if CornerCaught then // draw selected corner
begin
brush.Color:=clSilver;
a := ToScreen(MainTriangles[SelectedTriangle].x[SelectedCorner], MainTriangles[SelectedTriangle].y[SelectedCorner]);
Ellipse(a.x - 4, a.y - 4, a.x + 4, a.y + 4);
end
else if (mouseOverTriangle>=0) then
begin
if (mouseOverCorner >= 0) then // highlight corner under cursor
begin
case mouseOverCorner of
0: brush.Color:=clRed;
2: brush.Color:=clBlue;
else brush.Color:=clSilver;
end;
a := ToScreen(MainTriangles[mouseOverTriangle].x[mouseOverCorner], MainTriangles[mouseOverTriangle].y[mouseOverCorner]);
Ellipse(a.x - 4, a.y - 4, a.x + 4, a.y + 4);
// hmm... TODO: optimize
if HelpersEnabled then begin
pen.Color := HelpersColor;
pen.Mode := pmMerge;
pen.Style := psDot;
brush.Style := bsClear;
if (editMode = modeRotate) then
begin
i := integer(round(olddist * sc));
if i > 4 then begin
a := ToScreen(pivot.x, pivot.y);
Ellipse(a.x - i, a.y - i, a.x + i, a.y + i);
end;
end
else if editMode = modeScale then
begin
dx := MainTriangles[mouseOverTriangle].x[mouseOverCorner] - Pivot.x;
dy := MainTriangles[mouseOverTriangle].y[mouseOverCorner] - Pivot.y;
LineDxDy;
end;
end;
end;
if (mouseOverEdge >= 0) then // highlight edge under cursor
begin
i := (mouseOverEdge + 1) mod 3;
a := ToScreen(MainTriangles[mouseOverTriangle].x[mouseOverEdge], MainTriangles[mouseOverTriangle].y[mouseOverEdge]);
b := ToScreen(MainTriangles[mouseOverTriangle].x[i], MainTriangles[mouseOverTriangle].y[i]);
pen.Width:=5;
Pen.Color:=GetTriangleColor(mouseOverTriangle) shr 1 and $7f7f7f;
Pen.Mode:=pmMerge;
MoveTo(a.X, a.Y);
LineTo(b.X, b.Y);
pen.Mode:=pmCopy;
pen.Width:=1;
end;
end;
// draw pivot point
a := ToScreen(GetPivot.x, GetPivot.y);
Pen.Style := psSolid;
pen.Color := clWhite;
brush.Color := clSilver;
if (pivotMode = pivotLocal) or EdgeCaught then i := 2
else i := 3;
Ellipse(a.x - i, a.y - i, a.x + i, a.y + i);
if editMode = modePick then begin // hmm...
a := ToScreen(mouseOverPos.x, mouseOverPos.y);
brush.Style := bsClear;
Ellipse(a.x - i, a.y - i, a.x + i, a.y + i);
end;
if TWinControl(Sender).Focused then
begin
pen.Color := HelpersColor;
pen.Mode := pmXor;
MoveTo(foc_ofs, foc_size);
LineTo(foc_ofs, foc_ofs);
LineTo(foc_size, foc_ofs);
MoveTo(Width-1-foc_ofs, foc_size);
LineTo(Width-1-foc_ofs, foc_ofs);
LineTo(Width-1-foc_size, foc_ofs);
MoveTo(Width-1-foc_ofs, Height-1-foc_size);
LineTo(Width-1-foc_ofs, Height-1-foc_ofs);
LineTo(Width-1-foc_size, Height-1-foc_ofs);
MoveTo(foc_ofs, Height-1-foc_size);
LineTo(foc_ofs, Height-1-foc_ofs);
LineTo(foc_size, Height-1-foc_ofs);
end;
end;
TriangleView.Canvas.Draw(0, 0, Bitmap);
finally
BitMap.Free;
end;
end;
procedure TEditForm.FormCreate(Sender: TObject);
var
i: integer;
vn: string;
ExtSM: HMenu;
begin
mnuELowQuality.Caption := TextByKey('common-lowquality');
mnuEMediumQuality.Caption := TextByKey('common-mediumquality');
mnuEHighQuality.Caption := TextByKey('common-highquality');
mnuLowQuality.Caption := TextByKey('common-lowquality');
mnuMediumQuality.Caption := TextByKey('common-mediumquality');
mnuHighQuality.Caption := TextByKey('common-highquality');
tbCopy.Hint := TextByKey('common-copy');
tbCopyTriangle.Hint := TextByKey('editor-popup-transform-copycoords');
CopyTriangleCoordinates.Caption := TextByKey('editor-popup-transform-copycoords');
CopyTransform.Caption := TextByKey('editor-popup-transform-copywhole');
CopyVariations.Caption := TextByKey('editor-popup-transform-copyvars');
tbPaste.Hint := TextByKey('common-paste');
tbPasteTriangle.Hint := TextByKey('editor-popup-transform-pastecoords');
PasteTriangleCoordinates.Caption := TextByKey('editor-popup-transform-pastecoords');
PasteTransform.Caption := TextByKey('editor-popup-transform-pastewhole');
PasteVariations.Caption := TextByKey('editor-popup-transform-pastevars');
CopyChaos.Caption := TextByKey('editor-popup-chaos-copy');
PasteChaos.Caption := TextByKey('editor-popup-chaos-paste');
mnuCopyChaos.Caption := CopyChaos.Caption;
mnuPasteChaos.Caption := PasteChaos.Caption;
tbUndo.Hint := TextByKey('common-undo');
mnuUndo.Caption := TextByKey('common-undo');
tbRedo.Hint := TextByKey('common-redo');
mnuRedo.Caption := TextByKey('common-redo');
bClear.Caption := TextByKey('common-clear');
pnlSymmetry.Hint := TextByKey('common-dragpanelhint');
pnlOpacity.Hint := TextByKey('common-dragpanelhint');
pnlDC.Hint := TextByKey('common-dragpanelhint');
pnlWeight.Hint := TextByKey('common-dragpanelhint');
pnlXFormColor.Hint := TextByKey('common-dragpanelhint'); // AV
self.Caption := TextByKey('editor-title');
Panel1.Caption := TextByKey('editor-common-transform');
Panel2.Caption := TextByKey('editor-common-name');
pnlWeight.Caption := TextByKey('editor-common-weight');
tbComment.Hint := TextByKey('editor-common-editcomment');
SaveFlameState.Hint := TextByKey('editor-toolbar-savestate');
tabVariations.Caption := TextByKey('editor-tab-variations-title');
VEVars.TitleCaptions[0] := TextByKey('editor-tab-variations-name');
VEVars.TitleCaptions[1] := TextByKey('editor-tab-variations-value');
cbCollapseVariations.Items[0] := TextByKey('editor-tab-variations-toggleshowall');
cbCollapseVariations.Items[1] := TextByKey('editor-tab-variations-togglehideunused');
cbCollapseVariations.Items[2] := TextByKey('editor-tab-variations-togglefavourites');
cbCollapseVariations.Items[3] := TextByKey('editor-tab-variations-toggle3d');
cbCollapseVariations.Items[4] := TextByKey('editor-tab-variations-toggledc');
btnVarOrder.Caption := TextByKey('editor-tab-variations-order');
btnVarOrder.Hint := TextByKey('editor-tab-variations-orderhint');
TabVariables.Caption := TextByKey('editor-tab-variables-title');
vleVariables.TitleCaptions[0] := TextByKey('editor-tab-variables-name');
vleVariables.TitleCaptions[1] := TextByKey('editor-tab-variables-value');
chkCollapseVariables.Caption := TextByKey('editor-tab-variables-toggleshowall');
btResetparams.Caption := TextByKey('editor-tab-variables-reset');
TabChaos.Caption := TextByKey('editor-tab-chaos-title');
vleChaos.TitleCaptions[0] := TextByKey('editor-tab-chaos-path');
vleChaos.TitleCaptions[1] := TextByKey('editor-tab-chaos-modifier');
optTo.Caption := TextByKey('editor-tab-chaos-viewasto');
mnuChaosViewTo.Caption := TextByKey('editor-tab-chaos-viewasto');
optFrom.Caption := TextByKey('editor-tab-chaos-viewasfrom');
mnuChaosViewFrom.Caption := TextByKey('editor-tab-chaos-viewasfrom');
TriangleTab.Caption := TextByKey('editor-tab-triangle-title');
gbPivot.Caption := TextByKey('editor-tab-triangle-pivot');
GroupBox7.Caption := TextByKey('editor-tab-transform-coordsystem');
GroupBox9.Caption := TextByKey('editor-tab-transform-affine');
GroupBox8.Caption := TextByKey('editor-tab-transform-postaffine');
btSwapCoefs.Caption:= TextByKey('editor-tab-transform-swapaffine');
btSwapCoefs.Hint := TextByKey('editor-tab-transform-swapaffinehint');
RotateXYO.Caption := TextByKey('editor-popup-triangle-rotateall');
RotateX.Caption := TextByKey('editor-popup-triangle-rotatex');
RotateY.Caption := TextByKey('editor-popup-triangle-rotatey');
RotateO.Caption := TextByKey('editor-popup-triangle-rotateo');
ScaleXYO.Caption := TextByKey('editor-popup-triangle-scaleall');
ScaleX.Caption := TextByKey('editor-popup-triangle-scalex');
ScaleY.Caption := TextByKey('editor-popup-triangle-scaley');
ScaleO.Caption := TextByKey('editor-popup-triangle-scaleo');
RectGrid.Caption := TextByKey('editor-popup-triangle-squaregrid');
TriGrid.Caption := TextByKey('editor-popup-triangle-hexgrid');
InvertMovevalue1.Caption := TextByKey('editor-popup-triangle-invertstep');
CalcArcsinScale.Caption := TextByKey('editor-popup-triangle-arcsin');
ShowModVals.Caption := TextByKey('editor-popup-triangle-display');
mnuFlipAllLine.Caption := TextByKey('editor-popup-panel-allflipline');
tbTriangle.Hint := TextByKey('editor-tab-triangle-menuhint');
btnResetPivot.Hint := TextByKey('editor-tab-triangle-resetpivot');
btnPickPivot.Hint := TextByKey('editor-tab-triangle-pickpivot');
btTrgRotateLeft.Hint := TextByKey('editor-tab-triangle-rotateleft');
btTrgRotateRight.Hint := TextByKey('editor-tab-triangle-rotateright');
btTrgMoveUp.Hint := TextByKey('editor-tab-triangle-moveup');
btTrgMoveDown.Hint := TextByKey('editor-tab-triangle-movedown');
btTrgMoveLeft.Hint := TextByKey('editor-tab-triangle-moveleft');
btTrgMoveRight.Hint := TextByKey('editor-tab-triangle-moveright');
btTrgScaleDown.Hint := TextByKey('editor-tab-triangle-scaledown');
btTrgScaleUp.Hint := TextByKey('editor-tab-triangle-scaleup');
tbAutoWeights.Hint := TextByKey('editor-tab-triangle-autoweight');
tabXForm.Caption := TextByKey('editor-tab-transform-title');
btnResetCoefs.Caption := TextByKey('editor-tab-transform-reset');
btnResetCoefs.Hint := TextByKey('editor-tab-transform-resethint');
btnCoefsRect.Caption := TextByKey('editor-tab-transform-rectangular');
btnCoefsRect.Hint := TextByKey('editor-tab-transform-rectangularhint');
btnCoefsPolar.Caption := TextByKey('editor-tab-transform-polar');
btnCoefsPolar.Hint := TextByKey('editor-tab-transform-polarhint');
btnResetPostCoefs.Caption := TextByKey('editor-tab-transform-resetpost');
btnResetPostCoefs.Hint := TextByKey('editor-tab-transform-resetposthint');
btConjugate.Caption := 'TVT'#$02C9#$00B9#32#32 + TextByKey('editor-tab-transform-conjugate');
btConjugate.Hint := TextByKey('editor-tab-transform-conjugatehint');
chkAutoZScale.Caption := TextByKey('editor-tab-transform-autozscale');
btnXcoefs.Hint := TextByKey('editor-tab-transform-resetxhint');
btnXpost.Hint := TextByKey('editor-tab-transform-resetxhint');
btnYcoefs.Hint := TextByKey('editor-tab-transform-resetyhint');
btnYpost.Hint := TextByKey('editor-tab-transform-resetyhint');
btnOcoefs.Hint := TextByKey('editor-tab-transform-resetohint');
btnOpost.Hint := TextByKey('editor-tab-transform-resetohint');
tabColors.Caption := TextByKey('editor-tab-color-title');
GroupBox1.Caption := TextByKey('editor-tab-color-transformcolor');
pnlSymmetry.Caption := TextByKey('editor-tab-color-colorspeed');
pnlOpacity.Caption := TextByKey('editor-tab-color-opacity');
pnlDC.Caption := TextByKey('editor-tab-color-directcolor');
chkXFormSolo.Caption := TextByKey('editor-tab-color-togglesolo');
GroupBox2.Caption := TextByKey('editor-tab-color-varpreview');
gbFlip.Caption := TextByKey('editor-tab-triangle-reflection');
gbTrgOperations.Caption := TextByKey('editor-tab-triangle-transforms');
gbCoordinates.Caption := TextByKey('editor-tab-triangle-coordinates');
btnResetFlip.Hint := TextByKey('editor-tab-triangle-resetflip');
Label1.Caption := TextByKey('editor-tab-color-previewrange');
Label2.Caption := TextByKey('editor-tab-color-previewdepth');
Label3.Caption := TextByKey('editor-tab-color-previewdensity');
Label1.Hint := TextByKey('editor-tab-color-previewrangehint');
Label2.Hint := TextByKey('editor-tab-color-previewdepthhint');
Label3.Hint := TextByKey('editor-tab-color-previewdensityhint');
lblSearch.Caption := TextByKey('editor-tab-variations-search'); // AV
txtSearchBox.TextHint := TextByKey('editor-tab-variations-searchhint'); // AV
tbResetAll.Hint := TextByKey('editor-toolbar-newflame');
tbAdd.Hint := TextByKey('editor-toolbar-newtransform');
mnuAdd.Caption := TextByKey('editor-toolbar-newtransform');
mnuAdd1.Caption := TextByKey('editor-toolbar-newtransform');
tbPreLink.Hint := TextByKey('editor-toolbar-addlinkedpretransform');
tbPostLink.Hint := TextByKey('editor-toolbar-addlinkedtransform');
mnuLinkPostxform.Caption := TextByKey('editor-toolbar-addlinkedtransform');
mnuLinkPrexform.Caption := TextByKey('editor-toolbar-addlinkedpretransform');
tbDuplicate.Hint := TextByKey('editor-toolbar-duplicatetransform');
mnuDuplicate.Caption := TextByKey('editor-toolbar-duplicatetransform');
tbDelete.Hint := TextByKey('editor-toolbar-removetransform');
mnuDelete.Caption := TextByKey('editor-toolbar-removetransform');
tbSelect.Hint := TextByKey('editor-toolbar-modeselect');
mnuSelectMode.Caption := TextByKey('editor-toolbar-modeselect');
tbMove.Hint := TextByKey('editor-toolbar-modemove');
tbRotate.Hint := TextByKey('editor-toolbar-moderotate');
tbScale.Hint := TextByKey('editor-toolbar-modescale');
tbPivotMode.Caption := TextByKey('editor-toolbar-toggleworldpivot');
tbPivotMode.Hint := TextByKey('editor-toolbar-toggleworldpivot');
tbRotate90CCW.Caption := TextByKey('editor-toolbar-rotate90ccw');
tbRotate90CCW.Hint := TextByKey('editor-toolbar-rotate90ccw');
btTrgRotateLeft90.Hint := TextByKey('editor-toolbar-rotate90ccw');
RotateTriangle90CCW1.Caption := TextByKey('editor-toolbar-rotate90ccw');
tbRotate90CW.Caption := TextByKey('editor-toolbar-rotate90cw');
tbRotate90CW.Hint := TextByKey('editor-toolbar-rotate90cw');
btTrgRotateRight90.Hint := TextByKey('editor-toolbar-rotate90cw');
RotateTriangle90CCW2.Caption := TextByKey('editor-toolbar-rotate90cw');
tbFlipHorz.Caption := TextByKey('editor-toolbar-fliph');
tbFlipHorz.Hint := TextByKey('editor-toolbar-fliph');
mnuFlipHorizontal.Caption := TextByKey('editor-toolbar-fliph');
tbFlipVert.Caption := TextByKey('editor-toolbar-flipv');
tbFlipVert.Hint := TextByKey('editor-toolbar-flipv');
mnuFlipVertical.Caption := TextByKey('editor-toolbar-flipv');
tbVarPreview.Caption := TextByKey('editor-toolbar-togglevarpreview');
tbVarPreview.Hint := TextByKey('editor-toolbar-togglevarpreview');
mnuShowVarPreview.Caption := TextByKey('editor-toolbar-togglevarpreview');
tbPostXSwap.Caption := TextByKey('editor-toolbar-toggleposttransform');
tbPostXSwap.Hint := TextByKey('editor-toolbar-toggleposttransform');
tb2PostXSwap.Hint := TextByKey('editor-toolbar-toggleposttransform');
oggleposttriangleediting1.Caption := TextByKey('editor-toolbar-toggleposttransform');
tbEnableFinalxform.Caption := TextByKey('editor-toolbar-togglefinaltransform');
tbEnableFinalxform.Hint := TextByKey('editor-toolbar-togglefinaltransform');
mnuAutoZoom.Caption := TextByKey('editor-popup-panel-autozoom');
tbExtendedEdit.Hint := TextByKey('editor-popup-panel-toggleextendededit');
mnuExtendedEdit.Caption := TextByKey('editor-popup-panel-toggleextendededit');
tbAxisLock.Hint := TextByKey('editor-popup-panel-locktransformaxes');
mnuAxisLock.Caption := TextByKey('editor-popup-panel-locktransformaxes');
SynchronizeAll.Caption := TextByKey('editor-tab-triangle-syncall');
btnShowLine.Caption := TextByKey('editor-tab-triangle-showline');
btnShowLine.Hint := TextByKey('editor-tab-triangle-showlinehint');
btnFlip.Caption := TextByKey('editor-tab-triangle-fliptriangle');
btnFlip.Hint := TextByKey('editor-tab-triangle-fliptrianglehint');
btFlipX.Hint := TextByKey('editor-tab-triangle-flipx');
btFlipY.Hint := TextByKey('editor-tab-triangle-flipy');
btFlipDiag.Hint := TextByKey('editor-tab-triangle-flipxy');
lblFlipAngle.Hint := TextByKey('editor-status-angle');
editPivotX.Hint := TextByKey('editor-tab-triangle-pivot1x');
editPivotY.Hint := TextByKey('editor-tab-triangle-pivot1y');
editFlipX.Hint := TextByKey('editor-tab-triangle-pivot2x');
editFlipY.Hint := TextByKey('editor-tab-triangle-pivot2y');
btnFullChaos.Hint := TextByKey('editor-toolbar-showchaos');
ShowChaosMatrix.Caption := btnFullChaos.Hint;
mnuFlipAllH.Caption := TextByKey('editor-popup-panel-allfliph');
mnuFlipAllV.Caption := TextByKey('editor-popup-panel-allflipv');
mnuResetLoc.Caption := TextByKey('editor-popup-quality-autoreset');
mnuResetTrgPosition.Caption := TextByKey('editor-popup-transform-resetposition');
mnuResetTrgRotation.Caption := TextByKey('editor-popup-transform-resetrotation');
mnuResetTrgScale.Caption := TextByKey('editor-popup-transform-resetscale');
mnuResetTrgFlip.Caption := TextByKey('editor-popup-transform-resetflip');
mnuCopyTriangle.Caption := TextByKey('editor-popup-transform-copycoords');
mnuPasteTriangle.Caption := TextByKey('editor-popup-transform-pastecoords');
mnuReset.Caption := TextByKey('editor-popup-transform-resetentiretriangle');
mnuChaosRebuild.Caption := TextByKey('editor-popup-chaos-rebuildlinks');
mnuChaosClearAll.Caption := TextByKey('editor-popup-chaos-clearall');
mnuChaosSetAll.Caption := TextByKey('editor-popup-chaos-setall');
btClearChaos.Hint := TextByKey('editor-popup-chaos-clearall');
btResetChaos.Hint := TextByKey('editor-popup-chaos-setall');
NormChaos.Caption := TextByKey('editor-popup-chaos-normalize');
RandomizeMatrix.Caption := TextByKey('editor-popup-chaos-randomize');
RandomizeChaos.Caption := TextByKey('editor-popup-chaos-random');
ResetChaos.Caption := TextByKey('editor-popup-chaos-reset');
ChaosClearBelow.Caption := TextByKey('editor-popup-chaos-clearbelow');
ClearAllAbove.Caption := TextByKey('editor-popup-chaos-clearabove');
btnPivotMode.Hint := TextByKey('editor-tab-triangle-toworld');
AddContainer.Caption := TextByKey('editor-popup-chaos-container');
InheritWeights.Caption := TextByKey('editor-popup-chaos-keepweight');
InvertXaos.Caption := TextByKey('editor-popup-chaos-invert');
btChaos.Caption := TextByKey('editor-popup-chaos-showmenu');
GridComboBox.Items[0] := TextByKey('editor-grid-rectangular');
GridComboBox.Items[1] := TextByKey('editor-grid-polar');
GridComboBox.Items[2] := TextByKey('editor-grid-bipolar');
GridComboBox.Items[3] := TextByKey('editor-grid-elliptic');
GridComboBox.ItemIndex := 0;
lblGridType.Caption := TextByKey('editor-grid-type');
lblGridType.Hint := TextByKey('editor-grid-typehint');
gbTrgOperations.Hint := StringReplace(TextByKey('editor-tab-triangle-transformshint'),
',', ','#13, [rfReplaceAll]);
// Math constants
RedrawButtons;
btnMathPopup.Hint := TextByKey('editor-toolbar-pihint');
Pifractions.Caption := TextByKey('editor-toolbar-pimenu') + #32#$03C0'...';
InsertPi1.Caption := #$03C0;
Insert2Pi1.Caption := '2'#$03C0;
InsertPi21.Caption := #$03C0'/2';
InsertPi31.Caption := #$03C0'/3';
InsertPi41.Caption := #$03C0'/4';
InsertPi61.Caption := #$03C0'/6';
Insert1sqrt21.Caption := '1/'#$221A#$0305'2';
Insertsqrt321.Caption := #$221A#$0305'3/2';
Insertsqrt331.Caption := #$221A#$0305'3/3';
Insertsqrt361.Caption := #$221A#$0305'3/6';
Insertsqrt31.Caption := #$221A#$0305'3';
SquareRoots1.Caption := TextByKey('editor-toolbar-squareroots');
InsertGoldenratio1.Caption := TextByKey('editor-toolbar-goldenratio');
InvCurrentNum.Caption := TextByKey('editor-toolbar-invert');
Squarethenumber1.Caption := TextByKey('editor-toolbar-square');
SquareRoot.Caption := TextByKey('editor-toolbar-squareroot');
Mul2.Caption := TextByKey('editor-toolbar-multiply');
Div2.Caption := TextByKey('editor-toolbar-divide');
CalcCos.Caption := TextByKey('editor-toolbar-calccos');
CalcSin.Caption := TextByKey('editor-toolbar-calcsin');
CalcTan.Caption := TextByKey('editor-toolbar-calctan');
UseDegrees.Caption := TextByKey('editor-toolbar-usedegrees');
mnuCalcExpression.Caption := TextByKey('editor-toolbar-calcexpression');
ExtSM := GetSystemMenu(Handle, False); // AV
InsertMenu(ExtSM, UINT(5), MF_ByPosition or MF_Separator, 0, nil);
InsertMenu(ExtSM, UINT(6), MF_ByPosition, $C0, PChar(TextByKey('main-menu-screenshot')));
// Custom control setup
TriangleView := TCustomDrawControl.Create(self);
TriangleView.TabStop := True;
TriangleView.TabOrder := 0;
TriangleView.Parent := GrphPnl;
TriangleView.Align := alClient;
TriangleView.Visible := True;
TriangleView.OnPaint := TriangleViewPaint;
TriangleView.OnDblClick := TriangleViewDblClick;
TriangleView.OnMouseDown := TriangleViewMouseDown;
TriangleView.OnMouseMove := TriangleViewMouseMove;
TriangleView.OnMouseUp := TriangleViewMouseUp;
TriangleView.OnMouseWheel := TriangleViewMouseWheel;
TriangleView.OnKeyDown := TriangleViewKeyDown;
TriangleView.OnKeyUp := TriangleViewKeyUp;
TriangleView.OnEnter := TriangleViewInvalidate;
TriangleView.OnExit := TriangleViewExit;
TriangleView.OnMouseLeave := TriangleViewmouseLeave;
SetLength(VarsCache, NRVAR); // AV
for i:= 0 to NRVAR - 1 do begin
vn := Varnames(i);
VEVars.InsertRow(vn, '0', True);
VarsCache[i] := MinDouble; // AV: moved here
end;
for i:= 0 to GetNrVariableNames - 1 do begin
vn := GetVariableNameAt(i);
vleVariables.InsertRow(vn, '0', True);
end;
vleChaos.InsertRow(Format(TextByKey('editor-common-toprefix'), [1]), '1', true);
mnuChaosRebuild.Checked := RebuildXaosLinks;
GraphZoom := 1;
case EditPrevQual of
0: begin
mnuLowQuality.Checked := true;
PreviewDensity := prevLowQuality;
end;
1: begin
mnuMediumQuality.Checked := true;
PreviewDensity := prevMediumQuality;
end;
2: begin
mnuHighQuality.Checked := true;
PreviewDensity := prevHighQuality;
end;
end;
cp := TControlPoint.Create;
Render := TRenderer.Create;
SelectMode := true;
editMode := modeMove;
AxisLock := TransformAxisLock;
tbAxisLock.Down := AxisLock;
ExtendedEdit := ExtEditEnabled;
// tbExtendedEdit.Down := ExtendedEdit;
widgetMode := modeRotate;
ShowFlipLine := False;
hasLinkX := False;
EdgeCaught := false;
CornerCaught := false;
TriangleCaught := false;
mouseOverTriangle := -1;
mouseOverCorner := -1;
mouseOverEdge := -1;
mouseOverWidget := -1;
oldSelected := -1;
MemTriangle.x[0] := 1;
MemTriangle.y[0] := 0;
MemTriangle.x[1] := 0;
MemTriangle.y[1] := 0;
MemTriangle.x[2] := 0;
MemTriangle.y[2] := 1;
// AV: reflection start settings
FlipPoint.x := 0;
FlipPoint.y := 1;
// AV: added some "magic" variation parameters presets :)
with vleVariables do
begin
with ItemProps['fan2_x'] do
begin
EditStyle := esPickList;
PickList.Add('1.41421');
PickList.Add('1');
PickList.Add('0.816497');
PickList.Add('0.707107');
PickList.Add('0.57735');
PickList.Add('0.534522');
PickList.Add('0.5');
PickList.Add('0.471405');
PickList.Add('0.447214');
PickList.Add('0.426401');
PickList.Add('0.408248');
end;
with ItemProps['fan2_y'] do
begin
EditStyle := esPickList;
PickList.Add('6.28319');
PickList.Add('4.71239');
PickList.Add('4.18879');
PickList.Add('3.92699');
PickList.Add('3.66519');
PickList.Add('3.59039');
PickList.Add('3.53429');
PickList.Add('3.49066');
PickList.Add('3.45575');
PickList.Add('3.42719');
PickList.Add('3.40339');
end;
with ItemProps['rings2_val'] do
begin
EditStyle := esPickList;
PickList.Add('1');
PickList.Add('1.22474');
PickList.Add('1.41421'); // degenerate case - circumferences
PickList.Add('2');
end;
ItemProps['trianglecrop_mode'].PickList.CommaText := '"0","1","2"';
ItemProps['projective_mode'].PickList.CommaText := '"0","1","2"';;
ItemProps['affine3D_mode'].PickList.CommaText := '"0","1","2"';;
ItemProps['spherecrop_mode'].PickList.CommaText := '"0","1","2"';;
for i := NrLocVar to NumBuiltInVars - 1 do
begin
vn := VarNames(i);
if pos('hypertile', vn) > 0 then
begin
ItemProps[vn + '_p'].PickList.CommaText := '"3","4","5","7","8"';
ItemProps[vn + '_q'].PickList.CommaText := '"3","4","5","7","8"';
end;
end;
if NumBuiltInVars < NrVar then
begin
i := GetVariationIndex('hexes');
if (i > 0) then
with ItemProps['hexes_rotate'] do
begin
EditStyle := esPickList;
PickList.Add('0.166667');
PickList.Add('0.333333');
PickList.Add('0.5');
PickList.Add('0.666667');
PickList.Add('0.833333');
PickList.Add('1');
end;
end;
end;
// MainForm.Buttons.GetBitmap(9, btnResetPivot.Glyph);
// MainForm.Buttons.GetBitmap(9, btnResetFlip.Glyph);
PageControl.ActivePage := tabVariations; // AV
cbCollapseVariations.ItemIndex := 0; // AV
end;
procedure TEditForm.FormDestroy(Sender: TObject);
begin
cp.free;
Render.free;
if FileExists(APPDATA + saved_variations) then DeleteFile(APPDATA + saved_variations);
if FileExists(APPDATA + saved_variables) then DeleteFile(APPDATA + saved_variables);
end;
procedure TEditForm.TriangleViewMouseMove(Sender: TObject; Shift: TShiftState;
X, Y: integer);
var
vx, vy, fx, fy: double;
mt, mc, me: integer;
a, t: double;
i, j: integer;
d: double;
i0, i1: integer;
dx, dy, x1, y1: double;
label FoundCorner, Skip1, Skip2;
begin
Scale(fx, fy, x, y);
StatusBar.Panels[0].Text := Format(TextByKey('editor-status-xformat'), [fx]);
StatusBar.Panels[1].Text := Format(TextByKey('editor-status-yformat'), [fy]);
if viewDragMode then // graph panning
begin
if (fx = oldx) and (fy = oldy) then exit;
viewDragged := true;
GcenterX := GcenterX - (fx - oldx);
GcenterY := GcenterY - (fy - oldy);
TriangleView.Refresh;
exit;
end;
mt:=mouseOverTriangle;
mc:=MouseOverCorner;
me:=mouseOverEdge;
if not (CornerCaught or TriangleCaught) then // look for a point under cursor
begin
mouseOverWidget := -1;
mouseOverEdge := -1;
mouseOverCorner:= -1;
mouseOverPos.x := fx;
mouseOverPos.y := fy;
if SelectMode then
begin
i0:=0;
i1:=LastTriangle;//Transforms-1;
end
else begin
i0:=SelectedTriangle;
i1:=i0;
end;
for i := i1 downto i0 do
begin
for j := 0 to 2 do // -- detect point hit first
begin
d := dist(fx, fy, MainTriangles[i].x[j], MainTriangles[i].y[j]);
if (d * GraphZoom * 50) < 4 then
begin
mouseOverTriangle := i;
mouseOverCorner := j;
// mouseOverEdge := -1;
// -- from MouseDown -- for highlighting:
// TODO: optimize...
if (j = 1) then
begin
if PivotMode = pivotLocal then begin
Pivot.x := 0;
Pivot.y := 0;
end
else Pivot := GetPivot;
LocalAxisLocked := true;
end
else begin
Pivot := GetPivot(mouseOverTriangle);
LocalAxisLocked := false;
end;
oldx := MainTriangles[mouseOverTriangle].x[j] - Pivot.X;
oldy := MainTriangles[mouseOverTriangle].y[j] - Pivot.Y;
olddist := Hypot(oldx, oldy);
// --
// -- for Pick Pivot
if editMode = modePick then
begin
mouseOverPos.x := MainTriangles[mouseOverTriangle].x[mouseOverCorner];
mouseOverPos.y := MainTriangles[mouseOverTriangle].y[mouseOverCorner];
end;
// ---
goto FoundCorner;
end;
end;
end;
if ExtendedEdit then //and (oldMode = modeNone) then
begin
for i := 0 to 3 do // -- detect 'widget' hit
for j := 0 to 1 do begin
if abs(line_dist(fx, fy, Widgets[i][j].x, Widgets[i][j].y,
Widgets[i][j+1].x, Widgets[i][j+1].y)
) * GraphZoom * 50 < 3 then
begin
mouseOverTriangle := SelectedTriangle;
mouseOverWidget := i;
// mouseOverEdge := -1;
// mouseOverCorner:= -1;
mouseOverPos.x := fx;
mouseOverPos.y := fy;
goto FoundCorner;
end;
end;
for i := i1 downto i0 do
begin
for j := 0 to 2 do // -- detect edge hit
begin
if abs(line_dist(fx, fy, MainTriangles[i].x[j], MainTriangles[i].y[j],
MainTriangles[i].x[(j+1) mod 3], MainTriangles[i].y[(j+1) mod 3])
) * GraphZoom * 50 < 3 then
begin
mouseOverTriangle:=i;
mouseOverEdge := j;
// mouseOverCorner:= -1;
mouseOverPos.x := fx;
mouseOverPos.y := fy;
goto FoundCorner;
end;
end;
end;
end;
i := InsideTriangle(fx, fy);
if i >= 0 then mouseOverTriangle:=i
else mouseOverTriangle:=-1;
FoundCorner:
end;
if (mouseOverTriangle >= 0) or (SelectMode = false) or (oldMode <> modeNone) then
begin
if (mouseOverWidget >= 0) and (oldMode = modeNone) then
TriangleView.Cursor := crEditRotate
else
if (mouseOverEdge >= 0) and (oldMode = modeNone) then begin // kinda hack, not good...
if mouseOverEdge = 2 then
TriangleView.Cursor := crEditScale
else
TriangleView.Cursor := crEditRotate;
end
else
case editMode of
modeMove:
TriangleView.Cursor := crEditMove;
modeRotate:
TriangleView.Cursor := crEditRotate;
modeScale:
TriangleView.Cursor := crEditScale;
modePick:
TriangleView.Cursor := crEditArrow;
end
end
else
TriangleView.Cursor := crEditArrow; //crDefault;
Shift := Shift - [ssLeft];
if CornerCaught then // Modify a point ///////////////////////////////////////
begin
if (editMode = modeRotate) then // rotate point
begin // rotate point around pivot
d := dist(Pivot.X, Pivot.Y, fx, fy);
if d<>0 then begin
if ssShift in Shift then // angle snap
begin
try
t := StrToFloat(txtTrgRotateValue.Text)/180*PI;
//assert(t<>0);
except
t := 15.0*PI/180.0;
txtTrgRotateValue.Text := '15';
end;
if t = 0 then goto Skip1; //?
a := Round(arctan2(fy-Pivot.Y, fx-Pivot.X)/t)*t;
vx := olddist*cos(a);
vy := olddist*sin(a);
end
else begin
Skip1:
vx := (fx-Pivot.X)*olddist/d;
vy := (fy-Pivot.Y)*olddist/d;
a := arctan2(vy,vx) - arctan2(oldy,oldx);
end;
if LocalAxisLocked then with MainTriangles[SelectedTriangle] do
begin
assert(SelectedCorner = 1);
x[0] := OldTriangle.x[0] + Pivot.X+vx - OldTriangle.x[1];
y[0] := OldTriangle.y[0] + Pivot.Y+vy - OldTriangle.y[1];
x[2] := OldTriangle.x[2] + Pivot.X+vx - OldTriangle.x[1];
y[2] := OldTriangle.y[2] + Pivot.Y+vy - OldTriangle.y[1];
end;
MainTriangles[SelectedTriangle].x[SelectedCorner] := Pivot.X+vx;
MainTriangles[SelectedTriangle].y[SelectedCorner] := Pivot.Y+vy;
end
else a := 0;
vy := abs(
arctan2(MainTriangles[SelectedTriangle].y[0]-MainTriangles[SelectedTriangle].y[1],
MainTriangles[SelectedTriangle].x[0]-MainTriangles[SelectedTriangle].x[1])
-arctan2(MainTriangles[SelectedTriangle].y[2]-MainTriangles[SelectedTriangle].y[1],
MainTriangles[SelectedTriangle].x[2]-MainTriangles[SelectedTriangle].x[1])
);
if vy > PI then vy := 2*PI - vy;
StatusBar.Panels[2].Text := Format(TextByKey('editor-status-rotateformat'), [a*180/PI, vy*180/PI]);
end
else if (editMode = modeScale) then
begin // move point along vector ("scale")
if olddist<>0 then begin
d := (oldx*(fx-Pivot.X) + oldy*(fy-Pivot.Y))/olddist;
if ssShift in Shift then // 'snapped' scale
begin
try // use move-value for 'scaling' point:
t := abs(StrToFloat(txtTrgMoveValue.Text));
//assert(t<>0);
except
t := 0.1;
txtTrgMoveValue.Text := '0.1';
end;
if t <> 0 then d := Trunc(d/t)*t;
end;
vx := oldx*d/olddist;
vy := oldy*d/olddist;
if LocalAxisLocked then with MainTriangles[SelectedTriangle] do
begin
assert(SelectedCorner = 1);
x[0] := OldTriangle.x[0] + Pivot.X+vx - OldTriangle.x[1];
y[0] := OldTriangle.y[0] + Pivot.Y+vy - OldTriangle.y[1];
x[2] := OldTriangle.x[2] + Pivot.X+vx - OldTriangle.x[1];
y[2] := OldTriangle.y[2] + Pivot.Y+vy - OldTriangle.y[1];
end;
MainTriangles[SelectedTriangle].x[SelectedCorner] := Pivot.X + vx;
MainTriangles[SelectedTriangle].y[SelectedCorner] := Pivot.Y + vy;
StatusBar.Panels[2].Text := Format(TextByKey('editor-status-scaleformat'),
[Hypot(vx, vy), d*100/olddist]);
end
else begin
MainTriangles[SelectedTriangle].x[SelectedCorner] := Pivot.X;
MainTriangles[SelectedTriangle].y[SelectedCorner] := Pivot.Y;
end;
end
else begin // snap/move
if ssShift in Shift then // snap to axis
begin
if abs(fx-Pivot.X) > abs(fy-Pivot.Y) then begin
vx := fx;
vy := Pivot.Y;
end
else begin
vx := Pivot.x;
vy := fy;
end;
end
else begin // just move
vx := fx;
vy := fy;
end;
if (SelectedCorner = 1) and AxisLock then with MainTriangles[SelectedTriangle] do
begin
x[0] := OldTriangle.x[0] + (vx - OldTriangle.x[1]);
y[0] := OldTriangle.y[0] + (vy - OldTriangle.y[1]);
x[2] := OldTriangle.x[2] + (vx - OldTriangle.x[1]);
y[2] := OldTriangle.y[2] + (vy - OldTriangle.y[1]);
end;
MainTriangles[SelectedTriangle].x[SelectedCorner] := vx;
MainTriangles[SelectedTriangle].y[SelectedCorner] := vy;
StatusBar.Panels[2].Text := Format(TextByKey('editor-status-moveformat'), [vx-(Pivot.X+oldx), vy-(Pivot.Y+oldy)]);
end;
// --
HasChanged := True;
UpdateFlameX;
// UpdateFlame(False);
StatusBar.Refresh;
exit;
end
else if TriangleCaught then // Modify a whole triangle ///////////////////////
begin
if (editMode = modeRotate) then // rotate triangle
begin
a := arctan2(fy-Pivot.Y, fx-Pivot.X) - arctan2(oldy, oldx);
if ssShift in Shift then // angle snap
begin
try
t := StrToFloat(txtTrgRotateValue.Text)/180*PI;
//assert(t<>0);
except
t := 15.0*PI/180.0;
txtTrgRotateValue.Text := '15';
end;
if t = 0 then goto Skip2;
a := Round(a/t)*t
end;
Skip2:
MainTriangles[SelectedTriangle] :=
RotateTrianglePoint(OldTriangle, Pivot.X, Pivot.Y, a);
vx := MainTriangles[SelectedTriangle].x[0]-MainTriangles[SelectedTriangle].x[1];
vy := MainTriangles[SelectedTriangle].y[0]-MainTriangles[SelectedTriangle].y[1];
if abs(vx*(MainTriangles[SelectedTriangle].x[2]-MainTriangles[SelectedTriangle].x[1])+
vy*(MainTriangles[SelectedTriangle].y[2]-MainTriangles[SelectedTriangle].y[1])) < 0.001
then
StatusBar.Panels[2].Text := Format(TextByKey('editor-status-rotateformat2'), [a*180/PI, arctan2(vy, vx)*180/PI])
else StatusBar.Panels[2].Text := Format(TextByKey('editor-status-rotateformat3'), [a*180/PI]);
end
else if (editMode = modeScale) then // scale
begin
if olddist<>0 then begin
vy := (oldx*(fx-Pivot.X) + oldy*(fy-Pivot.Y))/sqr(olddist);
if ssShift in Shift then // 'snapped' scale
begin
try
t := abs(StrToFloat(txtTrgScaleValue.Text)/100.0 - 1.0);
//assert(t<>0);
except
t := 0.1;
txtTrgRotateValue.Text := '0.1';
end;
if t <> 0 then vy := Trunc(vy/t)*t;
end;
MainTriangles[SelectedTriangle] :=
ScaleTrianglePoint(OldTriangle, Pivot.X, Pivot.Y, vy);
StatusBar.Panels[2].Text := Format(TextByKey('editor-status-scaleformat2'), [vy*100]);
end
else MainTriangles[SelectedTriangle] := OldTriangle;
end
else begin // snap/move
vx := fx - (Pivot.x + oldx);
vy := fy - (Pivot.y + oldy);
if ssShift in Shift then // snap to axis
begin
if abs(vx) > abs(vy) then vy := 0
else vx := 0;
end;
with MainTriangles[SelectedTriangle] do
begin
x[0] := OldTriangle.x[0] + vx;
y[0] := OldTriangle.y[0] + vy;
x[1] := OldTriangle.x[1] + vx;
y[1] := OldTriangle.y[1] + vy;
x[2] := OldTriangle.x[2] + vx;
y[2] := OldTriangle.y[2] + vy;
end;
StatusBar.Panels[2].Text := Format(TextByKey('editor-status-moveformat2'), [vx, vy]);
end;
HasChanged := True;
UpdateFlameX;
// UpdateFlame(False);
StatusBar.Refresh;
exit;
end;
if ((mt <> mouseOverTriangle) or (mc <> MouseOverCorner) or (me <> MouseOverEdge)) then
begin
if (mouseOverTriangle >= 0) then
StatusBar.Panels[2].Text := Format(TextByKey('editor-status-transformformat'), [mouseOverTriangle+1])
else StatusBar.Panels[2].Text := '';
TriangleView.Refresh;
end
else if editMode = modePick then TriangleView.Refresh; // hmm...
end;
procedure TEditForm.TriangleViewMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: integer);
var
d, fx, fy: double;
i, j: integer;
i0, i1: integer;
label
FoundTriangle;
begin
TWinControl(Sender).SetFocus;
viewDragged := false;
Scale(fx, fy, x, y);
if Button = mbLeft then
begin
if editMode = modePick then
begin
if (mouseOverCorner >= 0) then // snap to point
begin
fx := MainTriangles[mouseOverTriangle].x[mouseOverCorner];
fy := MainTriangles[mouseOverTriangle].y[mouseOverCorner];
end;
if PivotMode = pivotLocal then
with MainTriangles[SelectedTriangle] do begin
// xx := x[0] - x[1];
// xy := y[0] - y[1];
// yx := x[2] - x[1];
// yy := y[2] - y[1];
d := (xx*yy - yx*xy);
if d <> 0 then
begin
LocalPivot.x := ( (fx - x[1]) * yy - (fy - y[1]) * yx) / d;
LocalPivot.y := (-(fx - x[1]) * xy + (fy - y[1]) * xx) / d;
end
end
else begin
WorldPivot.x := fx;
WorldPivot.y := fy;
end;
editMode := oldMode;
oldMode := modeNone;
btnPickPivot.Down := false;
ShowSelectedInfo;
TriangleView.Invalidate;
exit;
end;
Shift := Shift - [ssLeft];
if SelectMode then
begin
i0:=0;
i1:=LastTriangle;
end
else begin // Only check selected triangle
i0:=SelectedTriangle;
i1:=i0;
end;
oldSelected := SelectedTriangle;
for i := i1 downto i0 do
begin
for j := 0 to 2 do // detect corner hit
begin
d := dist(fx, fy, MainTriangles[i].x[j], MainTriangles[i].y[j]);
if (d * GraphZoom * 50) < 4 then
begin
SelectedTriangle := i;
CornerCaught := True;
SelectedCorner := j;
// Pivot := GetPivot;
if (j = 1) then
begin
if PivotMode = pivotLocal then begin
Pivot.x := 0;
Pivot.y := 0;
end
else Pivot := GetPivot;
LocalAxisLocked := true;
end
else begin
Pivot := GetPivot;
LocalAxisLocked := false;
end;
OldTriangle := MainTriangles[SelectedTriangle];
oldx := MainTriangles[SelectedTriangle].x[j] - Pivot.X;
oldy := MainTriangles[SelectedTriangle].y[j] - Pivot.Y;
olddist := sqrt(sqr(oldx) + sqr(oldy));
HasChanged := false;
ShowSelectedInfo;
TriangleView.Invalidate;
UpdateSyncTriangles; // AV
exit;
end;
end;
end;
if ExtendedEdit then //and (oldMode = modeNone) then
begin
for i := 0 to 3 do // -- detect 'widget' hit
for j := 0 to 1 do
begin
if abs(line_dist(fx, fy, Widgets[i][j].x, Widgets[i][j].y,
Widgets[i][j+1].x, Widgets[i][j+1].y)
) * GraphZoom * 50 < 3 then
begin
// modeHack := true;
if (oldMode = modeNone) then
begin
modeHack := true;
oldMode := editMode;
editMode := modeRotate;
end;
goto FoundTriangle;
end;
end;
for i := i1 downto i0 do
begin
for j := 0 to 2 do // -- detect edge hit
begin
if abs(line_dist(fx, fy, MainTriangles[i].x[j], MainTriangles[i].y[j],
MainTriangles[i].x[(j+1) mod 3], MainTriangles[i].y[(j+1) mod 3])
) * GraphZoom * 50 < 3 then
begin
SelectedTriangle := i;
EdgeCaught := true;
// modeHack := true;
if (oldMode = modeNone) then
begin
modeHack := true;
oldMode := editMode;
if j = 2 then
editMode := modeScale
else
if AxisLock then editMode := modeRotate
else
begin
// hacky...
CornerCaught := True;
editMode := modeRotate;
if j = 1 then SelectedCorner := 2
else SelectedCorner := 0;
Pivot := GetPivot;
LocalAxisLocked := false;
OldTriangle := MainTriangles[SelectedTriangle];
oldx := MainTriangles[SelectedTriangle].x[SelectedCorner] - Pivot.X;
oldy := MainTriangles[SelectedTriangle].y[SelectedCorner] - Pivot.Y;
olddist := sqrt(sqr(oldx) + sqr(oldy));
HasChanged := false;
ShowSelectedInfo;
TriangleView.Invalidate;
UpdateSyncTriangles; // AV
exit;
end;
end;
goto FoundTriangle;
end;
end;
end;
end;
// so user hasn't selected any corners,
// let's check for triangles then!
if SelectMode then
begin
i := InsideTriangle(fx, fy);
if i >= 0 then SelectedTriangle := i
else
if (oldMode = modeNone) and not(ssShift in Shift) then exit;
end;
FoundTriangle:
TriangleCaught := True;
OldTriangle := MainTriangles[SelectedTriangle];
//MainForm.UpdateUndo;
HasChanged := false;
Pivot := GetPivot;
oldx := fx-Pivot.X;
oldy := fy-Pivot.Y;
olddist := sqrt(oldx*oldx + oldy*oldy);
UpdateVariationList; // AV
UpdateSyncTriangles; // AV
ShowSelectedInfo;
TriangleView.Invalidate;
exit;
end
else if (Button = mbRight) and
not (TriangleCaught or CornerCaught) then // graph panning
begin
SetCaptureControl(TriangleView);
Screen.Cursor := crSizeAll;
viewDragMode := true;
oldx := fx;
oldY := fy;
end;
end;
procedure TEditForm.TriangleViewMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: integer);
begin
if Button = mbLeft then
begin
if modeHack then begin
assert(oldMode <> modeNone);
editMode := oldMode;
oldMode := modeNone;
modeHack := false;
end;
if HasChanged then
begin
MainForm.UpdateUndo;
UpdateFlame(true);
HasChanged := False;
end;
EdgeCaught := false;
CornerCaught := false;
TriangleCaught := false;
TriangleView.Invalidate;
end
else if (Button = mbRight) and viewDragMode then
begin
viewDragMode := false;
Screen.Cursor := crDefault;
SetCaptureControl(nil);
if viewDragged = false then // haven't dragged - popup menu then
begin
//GetCursorPos(mousepos); // hmmm
mousePos := (Sender as TControl).ClientToScreen(Point(x, y));
if mouseOverTriangle < 0 then
EditPopup.Popup(mousepos.x, mousepos.y)
else begin
SelectedTriangle := mouseOverTriangle;
cbTransforms.ItemIndex := SelectedTriangle;
TriangleView.Refresh;
TrianglePopup.Popup(mousepos.x, mousepos.y)
end;
end
else viewDragged := false;
end
end;
// AV: added standart shotcuts for numeric feilds
procedure TEditForm.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
if GetKeyState(VK_CONTROL) >= 0 then
Exit;
if Msg.CharCode = Ord('W') then begin
CreateScreenShot;
Handled := True;
end;
if (ActiveControl = txtName) or (ActiveControl = txtSearchBox) then Exit;
if not ((ActiveControl is TEdit) or (ActiveControl is TComboBox)) then Exit;
if Msg.CharCode = Ord('C') then begin
SendMessage(ActiveControl.Handle, WM_COPY, 0, 0);
Handled := True;
end
else
if Msg.CharCode = Ord('V') then begin
if not Clipboard.HasFormat(CF_TEXT) then
Handled := False
else begin
if StrToFloatDef(Clipboard.AsText, MaxDouble) <> MaxDouble then // hack
begin
SendMessage(ActiveControl.Handle, WM_PASTE, 0, 0);
Handled := True;
end
else
Handled := False;
end;
end
else
if Msg.CharCode = Ord('X') then begin
SendMessage(ActiveControl.Handle, WM_CUT, 0, 0);
Handled := True;
end
else
if Msg.CharCode = Ord('U') then begin
if (ActiveControl is TEdit) and TEdit(ActiveControl).CanUndo then
begin
TEdit(ActiveControl).Undo;
//SendMessage(ActiveControl.Handle, WM_UNDO, 0, 0);
Handled := True;
end
else
Handled := False;
end;
end;
procedure TEditForm.FormShow(Sender: TObject);
var
Registry: TRegistry;
begin
Registry := TRegistry.Create;
try
Registry.RootKey := HKEY_CURRENT_USER;
if Registry.OpenKey('Software\' + APP_NAME + '\Forms\Editor', False) then
begin
{ Size and position }
if Registry.ValueExists('Left') then
EditForm.Left := Registry.ReadInteger('Left');
if Registry.ValueExists('Top') then
EditForm.Top := Registry.ReadInteger('Top');
if Registry.ValueExists('Width') then
EditForm.Width := Registry.ReadInteger('Width');
if Registry.ValueExists('Height') then
EditForm.Height := Registry.ReadInteger('Height');
if Registry.ValueExists('ResetLocation') then
mnuResetLoc.checked := Registry.ReadBool('ResetLocation')
else
mnuResetLoc.checked := false;
if Registry.ValueExists('HelpersEnabled') then
HelpersEnabled := Registry.ReadBool('HelpersEnabled')
else
HelpersEnabled := true;
if Registry.ValueExists('VariationPreview') then
begin
showVarPreview := Registry.ReadBool('VariationPreview');
tbVarPreview.Down := showVarPreview;
end
else begin
showVarPreview := false;
tbVarPreview.Down := false;
end;
if Registry.ValueExists('VariationPreviewRange') then
trkVarPreviewRange.Position := Registry.ReadInteger('VariationPreviewRange');
if Registry.ValueExists('VariationPreviewDensity') then
trkVarPreviewDensity.Position := Registry.ReadInteger('VariationPreviewDensity');
if Registry.ValueExists('VariationPreviewDepth') then
trkVarPreviewDepth.Position := Registry.ReadInteger('VariationPreviewDepth');
if Registry.ValueExists('VariationPreviewGrid') then
GridComboBox.ItemIndex := Registry.ReadInteger('VariationPreviewGrid');
if Registry.ValueExists('VariationFilter') then
cbCollapseVariations.ItemIndex := Registry.ReadInteger('VariationFilter');
end
else begin
UseFlameBackground := False;
mnuResetLoc.checked := false;
end;
Registry.CloseKey;
finally
Registry.Free;
end;
if ExtendedEdit then tbExtendedEdit.Down := true
else tbMove.Down := true;
AdjustSyncTriangles; // AV
UpdateDisplay;
TrianglePanelResize(nil);
ScrollBox1Resize(nil);
end;
procedure TEditForm.mnuDeleteClick(Sender: TObject);
begin
if (SelectedTriangle >= 0) then DeleteTriangle(SelectedTriangle);
end;
procedure TEditForm.mnuAddClick(Sender: TObject);
begin
if Transforms < NXFORMS then
begin
MainForm.UpdateUndo;
MainTriangles[Transforms+1] := MainTriangles[Transforms];
cp.xform[Transforms+1].Assign(cp.xform[Transforms]);
MainTriangles[Transforms] := MainTriangles[-1];
SelectedTriangle := Transforms;
cp.xform[Transforms].Clear(hasLinkX);
cp.xform[Transforms].density := 0.5;
cp.xform[Transforms].SetVariation(0, 1);
Inc(Transforms);
UpdateXformsList;
UpdateFlame(True);
end;
end;
procedure TEditForm.mnuDupClick(Sender: TObject);
var
i: integer;
begin
if Transforms < NXFORMS then
begin
MainForm.UpdateUndo;
MainTriangles[Transforms+1] := MainTriangles[Transforms];
cp.xform[Transforms+1].Assign(cp.xform[Transforms]);
if SelectedTriangle <> Transforms then
begin
MainTriangles[Transforms] := MainTriangles[SelectedTriangle];
cp.xform[Transforms].Assign(cp.xform[SelectedTriangle]);
for i := 0 to Transforms-1 do
cp.xform[i].modWeights[Transforms] := cp.xform[i].modWeights[SelectedTriangle];
cp.xform[Transforms].modWeights[Transforms] := cp.xform[SelectedTriangle].modWeights[SelectedTriangle];
SelectedTriangle := Transforms;
end
else cp.xform[Transforms].density := 0.5;
Inc(Transforms);
UpdateXformsList;
UpdateFlame(True);
end;
end;
procedure TEditForm.mnuAutoZoomClick(Sender: TObject);
begin
AutoZoom;
end;
procedure TEditForm.btChaosClick(Sender: TObject);
begin
vleChaos.SetFocus;
ChaosPopup.Popup(btChaos.ClientOrigin.x, btChaos.ClientOrigin.y + btChaos.Height);
end;
procedure TEditForm.btConjugateClick(Sender: TObject);
var
deta: double;
begin
if not tbPostXSwap.Down then
begin
with cp.xform[SelectedTriangle] do
begin
deta := detC; // pre-affine determinant
if (abs(deta) < 1E-4) then
begin
Application.MessageBox(PChar(TextByKey('editor-status-warninvert')),
ApophysisSVN, MB_ICONWARNING);
exit;
end;
MainForm.UpdateUndo;
p[0,0] := c[1,1] / deta; // d
p[0,1] := -c[0,1] / deta; // -c
p[1,0] := -c[1,0] / deta; // -b
p[1,1] := c[0,0] / deta; // a
p[2,0] := (c[1,0] * c[2,1] - c[1,1] * c[2,0]) / deta; // -d*e + b*f
p[2,1] := (c[0,1] * c[2,0] - c[0,0] * c[2,1]) / deta; // c*e - a*f
end;
cp.GetTriangle(MainTriangles[SelectedTriangle], SelectedTriangle);
end else
begin
with cp.xform[SelectedTriangle] do
begin
deta := detP; // post-affine determinant
if (abs(deta) < 1E-4) then
begin
Application.MessageBox(PChar(TextByKey('editor-status-warninvert')),
ApophysisSVN, MB_ICONWARNING);
exit;
end;
MainForm.UpdateUndo;
c[0,0] := p[1,1] / deta;
c[0,1] := -p[0,1] / deta;
c[1,0] := -p[1,0] / deta;
c[1,1] := p[0,0] / deta;
c[2,0] := (p[1,0] * p[2,1] - p[1,1] * p[2,0]) / deta;
c[2,1] := (p[0,1] * p[2,0] - p[0,0] * p[2,1]) / deta;
end;
cp.GetPostTriangle(MainTriangles[SelectedTriangle], SelectedTriangle);
end;
UpdateFlame(true);
end;
procedure TEditForm.btFlipXYClick(Sender: TObject);
begin
if (editPivotX.Text <> '0') or (editPivotY.Text <> '0') then
btnResetPivot.Click;
if (Sender = btFlipX) then
begin
FlipPoint.x := 1; editFlipX.Text := '1';
FlipPoint.y := 0; editFlipY.Text := '0';
end
else if (Sender = btFlipY) then
begin
FlipPoint.x := 0; editFlipX.Text := '0';
FlipPoint.y := 1; editFlipY.Text := '1';
end else // if Sender = btFlipDiag then
begin
FlipPoint.x := 1; editFlipX.Text := '1';
FlipPoint.y := 1; editFlipY.Text := '1';
end;
if not ShowFlipLine then CalcFlip // refresh current angle
else TriangleView.Invalidate; // refresh angle and image
end;
procedure TEditForm.btnCloseClick(Sender: TObject);
begin
EditForm.Close;
end;
procedure TEditForm.FormResize(Sender: TObject);
begin
AutoZoom;
end;
procedure TEditForm.CornerEditExit(Sender: TObject);
var
Allow: boolean;
OldText: string;
Val: string;
begin
Allow := True;
if Sender = txtAx then
Val := Format('%.6f', [MainTriangles[SelectedTriangle].x[0]])
else if Sender = txtAy then
Val := Format('%.6f', [MainTriangles[SelectedTriangle].y[0]])
else if Sender = txtBx then
Val := Format('%.6f', [MainTriangles[SelectedTriangle].x[1]])
else if Sender = txtBy then
Val := Format('%.6f', [MainTriangles[SelectedTriangle].y[1]])
else if Sender = txtCx then
Val := Format('%.6f', [MainTriangles[SelectedTriangle].x[2]])
else if Sender = txtCy then
Val := Format('%.6f', [MainTriangles[SelectedTriangle].y[2]])
else if Sender = txtP then
if SelectedTriangle < Transforms then
val := Format('%.6f', [cp.xform[SelectedTriangle].density]);
OldText := Val;
{ Test that it's a valid floating point number }
try
StrToFloat(TEdit(Sender).Text);
except on Exception do
begin
{ It's not, so we restore the old value }
TEdit(Sender).Text := OldText;
Allow := False;
end;
end;
{ If it's not the same as the old value and it was valid }
if (val <> TEdit(Sender).Text) and Allow then
begin
if Sender = txtAx then
MainTriangles[SelectedTriangle].x[0] := StrToFloat(TEdit(Sender).Text)
else if Sender = txtAy then
MainTriangles[SelectedTriangle].y[0] := StrToFloat(TEdit(Sender).Text)
else if Sender = txtBx then
MainTriangles[SelectedTriangle].x[1] := StrToFloat(TEdit(Sender).Text)
else if Sender = txtBy then
MainTriangles[SelectedTriangle].y[1] := StrToFloat(TEdit(Sender).Text)
else if Sender = txtCx then
MainTriangles[SelectedTriangle].x[2] := StrToFloat(TEdit(Sender).Text)
else if Sender = txtCy then
MainTriangles[SelectedTriangle].y[2] := StrToFloat(TEdit(Sender).Text)
else if Sender = txtP then
begin
cp.xform[SelectedTriangle].density := StrToFloat(TEdit(Sender).Text);
TEdit(Sender).Text := Format('%.6g', [cp.xform[SelectedTriangle].density]);
end;
MainForm.UpdateUndo;
UpdateFlame(True);
end;
self.LastFocus := TEdit(sender);
end;
procedure TEditForm.CornerEditKeyPress(Sender: TObject; var Key: Char);
var
Allow: boolean;
OldText: string;
Val: string;
begin
if key = #13 then
begin
Allow := True;
if Sender = txtAx then
Val := Format('%.6f', [MainTriangles[SelectedTriangle].x[0]])
else if Sender = txtAy then
Val := Format('%.6f', [MainTriangles[SelectedTriangle].y[0]])
else if Sender = txtBx then
Val := Format('%.6f', [MainTriangles[SelectedTriangle].x[1]])
else if Sender = txtBy then
Val := Format('%.6f', [MainTriangles[SelectedTriangle].y[1]])
else if Sender = txtCx then
Val := Format('%.6f', [MainTriangles[SelectedTriangle].x[2]])
else if Sender = txtCy then
Val := Format('%.6f', [MainTriangles[SelectedTriangle].y[2]])
else if Sender = txtP then
val := Format('%.6f', [cp.xform[SelectedTriangle].density]);
OldText := Val;
{ Stop the beep }
Key := #0;
{ Test that it's a valid floating point number }
try
StrToFloat(TEdit(Sender).Text);
except on Exception do
begin
{ It's not, so we restore the old value }
TEdit(Sender).Text := OldText;
Allow := False;
end;
end;
{ If it's not the same as the old value and it was valid }
if (val <> TEdit(Sender).Text) and Allow then
begin
if Sender = txtAx then
MainTriangles[SelectedTriangle].x[0] := StrToFloat(TEdit(Sender).Text)
else if Sender = txtAy then
MainTriangles[SelectedTriangle].y[0] := StrToFloat(TEdit(Sender).Text)
else if Sender = txtBx then
MainTriangles[SelectedTriangle].x[1] := StrToFloat(TEdit(Sender).Text)
else if Sender = txtBy then
MainTriangles[SelectedTriangle].y[1] := StrToFloat(TEdit(Sender).Text)
else if Sender = txtCx then
MainTriangles[SelectedTriangle].x[2] := StrToFloat(TEdit(Sender).Text)
else if Sender = txtCy then
MainTriangles[SelectedTriangle].y[2] := StrToFloat(TEdit(Sender).Text)
else if Sender = txtP then
begin
cp.xform[SelectedTriangle].density := StrToFloat(TEdit(Sender).Text);
TEdit(Sender).Text := Format('%.6g', [cp.xform[SelectedTriangle].density]);
end;
MainForm.UpdateUndo;
UpdateFlame(True);
end;
end;
end;
{ ************************* Probability input ******************************** }
procedure TEditForm.txtPKeyPress(Sender: TObject; var Key: Char);
var
Allow: boolean;
NewVal, OldVal: double;
begin
if (Key = '-') then Key:= #0;
if SelectedTriangle >= Transforms then key := #0;
if key = #13 then
begin
{ Stop the beep }
Key := #0;
Allow := True;
OldVal := Round6(cp.xform[SelectedTriangle].density);
{ Test that it's a valid floating point number }
try
StrToFloat(TEdit(Sender).Text);
except on Exception do
begin
{ It's not, so we restore the old value }
TEdit(Sender).Text := Format('%.6g', [OldVal]);
Allow := False;
end;
end;
NewVal := Round6(StrToFloat(TEdit(Sender).Text));
if NewVal < 0.000001 then NewVal := 0.000001;
if NewVal > MAX_WEIGHT then NewVal := MAX_WEIGHT;
{ If it's not the same as the old value and it was valid }
TEdit(Sender).Text := Format('%.6g', [NewVal]);
if (OldVal <> NewVal) and Allow then
begin
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].density := NewVal;
//ReadjustWeights(cp);
UpdateFlame(True);
if ChaosForm.Visible then // AV
ChaosForm.WeightVector.Invalidate;
end;
end;
end;
procedure TEditForm.txtPExit(Sender: TObject);
var
Allow: boolean;
NewVal, OldVal: double;
begin
if SelectedTriangle >= Transforms then exit;
Allow := True;
OldVal := Round6(cp.xform[SelectedTriangle].density);
{ Test that it's a valid floating point number }
try
StrToFloat(TEdit(Sender).Text);
except on Exception do
begin
{ It's not, so we restore the old value }
TEdit(Sender).Text := Format('%.6g', [OldVal]);
Allow := False;
end;
end;
NewVal := Round6(StrToFloat(TEdit(Sender).Text));
if NewVal < 0.000001 then NewVal := 0.000001;
if NewVal > MAX_WEIGHT then NewVal := MAX_WEIGHT;
{ If it's not the same as the old value and it was valid }
TEdit(Sender).Text := Format('%.6g', [NewVal]);
if (OldVal <> NewVal) and Allow then
begin
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].density := NewVal;
//ReadjustWeights(cp);
UpdateFlame(True);
if ChaosForm.Visible then // AV
ChaosForm.WeightVector.Invalidate;
end;
self.LastFocus := TEdit(sender);
end;
{ **************************************************************************** }
procedure TEditForm.FormClose(Sender: TObject; var Action: TCloseAction);
var
Registry: TRegistry;
begin
{ Write position to registry }
Registry := TRegistry.Create;
try
Registry.RootKey := HKEY_CURRENT_USER;
{ Defaults }
if Registry.OpenKey('\Software\' + APP_NAME + '\Forms\Editor', True) then
begin
{ Options }
Registry.WriteBool('ResetLocation', mnuResetLoc.checked);
Registry.WriteBool('VariationPreview', showVarPreview);
Registry.WriteBool('HelpersEnabled', HelpersEnabled);
Registry.WriteInteger('VariationPreviewRange', trkVarPreviewRange.Position);
Registry.WriteInteger('VariationPreviewDensity', trkVarPreviewDensity.Position);
Registry.WriteInteger('VariationPreviewDepth', trkVarPreviewDepth.Position);
Registry.WriteInteger('VariationPreviewGrid', GridComboBox.ItemIndex);
Registry.WriteInteger('VariationFilter', cbCollapseVariations.ItemIndex);
{ Size and position }
if EditForm.WindowState <> wsMaximized then begin
Registry.WriteInteger('Top', EditForm.Top);
Registry.WriteInteger('Left', EditForm.Left);
Registry.WriteInteger('Width', EditForm.Width);
Registry.WriteInteger('Height', EditForm.Height);
end;
end;
finally
Registry.Free;
end;
// AV: free memory
SetLength(MemChaos, 0);
mnuPasteChaos.Enabled := False;
PasteChaos.Enabled := False;
end;
procedure TEditForm.mnuUndoClick(Sender: TObject);
begin
MainForm.Undo;
end;
procedure TEditForm.MulDiv2Click(Sender: TObject);
var
num: double;
sn: string;
begin
if (not ValidNumField) then
begin
Application.MessageBox(PChar(TextByKey('editor-status-nonumfield')),
ApophysisSVN, MB_ICONWARNING);
exit;
end;
if (txtTrgRotateValue.Focused) and (TMenuItem(Sender).Tag = 0) then exit;
try
if (ActiveControl is TEdit) then
sn := TEdit(ActiveControl).Text
else if (ActiveControl is TValueListEditor) then
sn := TValueListEditor(ActiveControl).Cells[1, TValueListEditor(ActiveControl).Row]
else // if (ActiveControl is TComboBox) then
sn := TComboBox(ActiveControl).Text;
num := StrToFloat(sn);
if (num <> 0) then
begin
case TMenuItem(Sender).Tag of
0: if (txtTrgScaleValue.Focused) then
sn := Format('%.6g', [num * num * 0.01])
else sn := Format('%.6g', [num * num]);
1: sn := Format('%.6g', [num * 2]);
2: sn := Format('%.6g', [num * 0.5]);
else if (txtTrgScaleValue.Focused) then
sn := Format('%.6g', [sign(num) * sqrt(abs(num * 0.01)) * 100])
else sn := Format('%.6g', [sign(num) * sqrt(abs(num))]);
end;
if (ActiveControl is TEdit) then
begin
TEdit(ActiveControl).Text := sn;
TEdit(ActiveControl).OnExit(ActiveControl);
end
else if (ActiveControl is TValueListEditor) then
begin
TValueListEditor(ActiveControl).Cells[1, TValueListEditor(ActiveControl).Row] := sn;
TValueListEditor(ActiveControl).OnExit(ActiveControl);
end
else //if (ActiveControl is TComboBox) then
TComboBox(ActiveControl).Text := sn;
end;
except
end;
end;
procedure TEditForm.NormChaosClick(Sender: TObject);
var i, j: smallint;
sum: double;
begin
MainForm.UpdateUndo;
for i := 0 to Transforms-1 do
begin
sum := 0;
for j := 0 to Transforms-1 do
sum := sum + cp.xform[i].modWeights[j];
if (sum = 1.0) or (sum = 0.0) then continue;
for j := 0 to Transforms-1 do
cp.xform[i].modWeights[j] := cp.xform[i].modWeights[j] / sum;
end;
UpdateFlame(True);
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
procedure TEditForm.mnuRedoClick(Sender: TObject);
begin
MainForm.Redo;
end;
procedure TEditForm.mnuLowQualityClick(Sender: TObject);
begin
mnuLowQuality.Checked := True;
mnuELowQuality.Checked := True;
PreviewDensity := prevLowQuality;
EditPrevQual := 0;
DrawPreview;
TriangleViewPaint(TriangleView);
end;
procedure TEditForm.mnuHighQualityClick(Sender: TObject);
begin
mnuHighQuality.Checked := True;
mnuEHighQuality.Checked := True;
PreviewDensity := prevHighQuality;
EditPrevQual := 2;
DrawPreview;
TriangleViewPaint(TriangleView);
end;
procedure TEditForm.mnuMediumQualityClick(Sender: TObject);
begin
mnuMediumQuality.Checked := True;
mnuEMediumQuality.Checked := True;
PreviewDensity := prevMediumQuality;
EditPrevQual := 1;
DrawPreview;
TriangleViewPaint(TriangleView);
end;
procedure TEditForm.mnuResetLocClick(Sender: TObject);
var
reset: boolean;
begin
reset:= not mnuResetLoc.Checked;
mnuResetLoc.Checked := reset;
if reset then
begin
cp.width := MainCp.width;
cp.height := MainCp.height;
cp.pixels_per_unit := MainCp.pixels_per_unit;
cp.AdjustScale(PreviewImage.width, PreviewImage.Height);
cp.zoom := MainCp.zoom;
cp.center[0] := MainCp.center[0];
cp.center[1] := MainCp.center[1];
end;
DrawPreview;
end;
procedure TEditForm.mnuFlipAllVClick(Sender: TObject);
var
i: smallint;
begin
MainForm.UpdateUndo;
for i := -1 to Transforms do
begin
MainTriangles[i] := FlipTriangleVertical(MainTriangles[i]);
end;
cp.GetFromTriangles(MainTriangles, Transforms);
cp.TrianglesFromCP(MainTriangles);
AutoZoom;
UpdateFlame(True);
end;
procedure TEditForm.mnuFlipAllHClick(Sender: TObject);
var
i: smallint;
begin
MainForm.UpdateUndo;
for i := -1 to Transforms do
begin
MainTriangles[i] := FlipTriangleHorizontal(MainTriangles[i]);
end;
cp.GetFromTriangles(MainTriangles, Transforms);
cp.TrianglesFromCP(MainTriangles);
AutoZoom;
UpdateFlame(True);
end;
procedure TEditForm.mnuFlipAllLineClick(Sender: TObject); // AV
var
i: smallint;
begin
if (FlipPoint.x = 0) and (FlipPoint.y = 0) then exit;
if (FlipPoint.x = 0) then mnuFlipAllH.Click
else if (FlipPoint.y = 0) then mnuFlipAllV.Click
else begin
MainForm.UpdateUndo;
for i := -1 to Transforms do
MainTriangles[i] := FlipTriangleLine(MainTriangles[i], 0, 0,
FlipPoint.x, FlipPoint.y);
cp.GetFromTriangles(MainTriangles, Transforms);
cp.TrianglesFromCP(MainTriangles);
AutoZoom;
UpdateFlame(True);
end;
end;
procedure TEditForm.mnuFlipVerticalClick(Sender: TObject);
var
p: double;
i: integer;
begin
MainForm.UpdateUndo;
if (not UseTriangleSync) or (SelectedTriangle = Transforms) then
with MainTriangles[SelectedTriangle] do
begin
p := GetPivot.y * 2;
y[0] := p - y[0];
y[1] := p - y[1];
y[2] := p - y[2];
end
else for i in SyncTriangles do
with MainTriangles[i] do
begin
p := GetPivot(i).y * 2;
y[0] := p - y[0];
y[1] := p - y[1];
y[2] := p - y[2];
end;;
//AutoZoom;
UpdateFlame(True);
end;
procedure TEditForm.mnuFlipHorizontalClick(Sender: TObject);
var
p: double;
i: integer;
begin
MainForm.UpdateUndo;
if (not UseTriangleSync) or (SelectedTriangle = Transforms) then
with MainTriangles[SelectedTriangle] do
begin
p := GetPivot.x * 2;
x[0] := p - x[0];
x[1] := p - x[1];
x[2] := p - x[2];
end
else for i in SyncTriangles do
with MainTriangles[i] do
begin
p := GetPivot(i).x * 2;
x[0] := p - x[0];
x[1] := p - x[1];
x[2] := p - x[2];
end;
//AutoZoom;
UpdateFlame(True);
end;
procedure TEditForm.cbTransformsChange(Sender: TObject);
var
n: smallint;
begin
n := cbTransforms.ItemIndex;
if (n <> SelectedTriangle) and (n >= 0) and (n <= LastTriangle) then
begin
SelectedTriangle := n;
UpdateVariationList; // AV
ShowSelectedInfo;
TriangleView.Invalidate;
end;
UpdateSyncTriangles; // AV
end;
procedure TEditForm.UpdateSyncTriangles;
var n: smallint;
begin
if SelectedTriangle in SyncTriangles then exit;
for n := 0 to Transforms-1 do
if mnuSyncTriangles.Items[n].Checked then
mnuSyncTriangles.Items[n].Click;
if SelectedTriangle < Transforms then
mnuSyncTriangles.Items[SelectedTriangle].Click;
end;
procedure TEditForm.cbTransformsDrawItem(Control: TWinControl;
Index: Integer; Rect: TRect; State: TOwnerDrawState);
var
h: integer;
ax,ay,bx,by: integer;
TrgColor: TColor;
begin
assert(Index >= 0);
TrgColor := GetTriangleColor(Index);
with cbTransforms.Canvas do
begin
h := Rect.Bottom - Rect.Top;
brush.Color:=clBlack;
FillRect(Rect);
Font.Color := clWhite;
TextOut(Rect.Left+h+2, Rect.Top, cbTransforms.Items[Index]); //IntToStr(Index+1));
pen.Color := TrgColor;
brush.Color := pen.Color shr 1 and $7f7f7f;
ax:=Rect.Left+h-2;
ay:=Rect.Top+1;
bx:=Rect.Left+2;
by:=Rect.Bottom-3;
Polygon([Point(ax, ay), Point(ax, by), Point(bx, by)]);
end;
end;
procedure TEditForm.ChaosClearBelowClick(Sender: TObject);
var i, n: smallint;
begin
n := vleChaos.Row;
if n = Transforms then exit;
MainForm.UpdateUndo;
if mnuChaosViewTo.Checked then
for i := n to Transforms-1 do
cp.xform[SelectedTriangle].modWeights[i] := 0
else for i := n to Transforms-1 do
cp.xform[i].modWeights[SelectedTriangle] := 0;
UpdateFlame(true);
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
procedure TEditForm.ClearAllAboveClick(Sender: TObject);
var i, n: smallint;
begin
n := vleChaos.Row;
if (n < 2) then exit;
MainForm.UpdateUndo;
if mnuChaosViewTo.Checked then
for i := 0 to n-2 do
cp.xform[SelectedTriangle].modWeights[i] := 0
else for i := 0 to n-2 do
cp.xform[i].modWeights[SelectedTriangle] := 0;
UpdateFlame(true);
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
procedure TEditForm.CoefKeyPress(Sender: TObject; var Key: Char);
begin
if key <> #13 then exit;
key := #0;
CoefValidate(Sender);
end;
procedure TEditForm.CoefValidate(Sender: TObject);
var
NewVal: double;
x, y, r, a: double; // dumb... must optimize
begin
try
NewVal := Round6(StrToFloat(TEdit(Sender).Text));
except on Exception do
begin
ShowSelectedInfo; //TEdit(Sender).Text := Format('%.6g', [pVal^]);
exit;
end;
end;
//TEdit(Sender).Text := Format('%.6g', [NewVal]);
MainForm.UpdateUndo; // TODO - prevent unnecessary UpdateUndo...
with cp.xform[SelectedTriangle] do
begin
if btnCoefsRect.Down = true then
begin
if Sender = txtA then c[0][0] := NewVal
else if Sender = txtB then c[0][1] := -NewVal
else if Sender = txtC then c[1][0] := -NewVal
else if Sender = txtD then c[1][1] := NewVal
else if Sender = txtE then c[2][0] := NewVal
else if Sender = txtF then c[2][1] := -NewVal;
end
else begin
if (Sender = txtA) or (Sender = txtB) then begin
x := c[0][0];
y := -c[0][1];
end else
if (Sender = txtC) or (Sender = txtD) then begin
x := -c[1][0];
y := c[1][1];
end else
{if (Sender = txtE) or (Sender = txtF) then}
begin
x := c[2][0];
y := -c[2][1];
end;
r := Hypot(x, y);
a := arctan2(y, x);
if (Sender = txtA) or (Sender = txtC) or (Sender = txtE) then
r := NewVal
else
a := NewVal*PI/180;
x := r * cos(a);
y := r * sin(a);
if (Sender = txtA) or (Sender = txtB) then begin
c[0][0] := x;
c[0][1] := -y;
end else
if (Sender = txtC) or (Sender = txtD) then begin
c[1][0] := -x;
c[1][1] := y;
end else
{if (Sender = txtE) or (Sender = txtF) then}
begin
c[2][0] := x;
c[2][1] := -y;
end;
end;
end;
cp.TrianglesFromCP(MainTriangles);
if tbAutoWeights.Down then cp.CalculateWeights; // AV
ShowSelectedInfo;
UpdateFlame(true);
self.LastFocus := TEdit(sender);
end;
procedure TEditForm.scrlXFormColorScroll(Sender: TObject;
ScrollCode: TScrollCode; var ScrollPos: Integer);
begin
if (ScrollCode = scEndScroll) and HasChanged then begin
MainForm.UpdateUndo;
UpdateFlame(True);
end;
end;
procedure TEditForm.scrlXFormColorChange(Sender: TObject);
var
v: double;
begin
if updating then exit;
v := (scrlXFormColor.Position) / scrlXFormColor.Max;
if v <> cp.xform[SelectedTriangle].color then
begin
cp.xform[SelectedTriangle].color := v;
pnlXFormColor.color := ColorValToColor(MainCp.cmap, v);
shColor.Brush.Color := pnlXFormColor.Color;
txtXFormColor.Text := Format('%1.3f', [v]);
txtXFormColor.Refresh;
HasChanged := true;
DrawPreview;
end;
end;
function TEditForm.ValidNumField: boolean;
begin
Result := (ActiveControl is TEdit);
if Result then
if (ActiveControl = txtSearchBox) or (ActiveControl = txtName) then
Exit(False);
Result := Result or (ActiveControl is TValueListEditor) or
((ActiveControl is TComboBox) and (ActiveControl.Parent = gbTrgOperations));
end;
(*
procedure TEditForm.chkUseXFormColorClick(Sender: TObject);
begin
UseTransformColors := chkUseXFormColor.checked;
TriangleView.Invalidate;
end;
procedure TEditForm.chkHelpersClick(Sender: TObject);
begin
HelpersEnabled := chkHelpers.checked;
TriangleView.Invalidate;
end;
*)
procedure TEditForm.txtXFormColorExit(Sender: TObject);
var
v: double;
begin
try
v := StrToFloat(txtXFormColor.Text);
except on EConvertError do
begin
txtXformColor.text := Format('%1.3f', [cp.xform[SelectedTriangle].color]);
exit;
end;
end;
if v > 1 then v := 1;
if v < 0 then v := 0;
if v <> cp.xform[SelectedTriangle].color then
begin
updating := true;
scrlXFormColor.Position := round(v * scrlXFormColor.Max);
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].color := v;
updating := false;
UpdateFlame(true);
end;
end;
procedure TEditForm.txtXFormColorKeyPress(Sender: TObject; var Key: Char);
begin
if (Key = '-') then Key:= #0; // AV
if key = #13 then
begin
key := #0;
txtXFormColorExit(Sender);
end;
end;
procedure TEditForm.txtOpacitySet(Sender: TObject);
var
Allow: boolean;
NewVal, OldVal: double;
begin
Allow := True;
OldVal := Round6(cp.xform[SelectedTriangle].transOpacity);
{ Test that it's a valid floating point number }
try
StrToFloat(TEdit(Sender).Text);
except on Exception do
begin
{ It's not, so we restore the old value }
TEdit(Sender).Text := Format('%.6g', [OldVal]);
Allow := False;
end;
end;
NewVal := Round6(StrToFloat(TEdit(Sender).Text));
if NewVal < 0 then NewVal := 0;
if NewVal > 1 then NewVal := 1;
{ If it's not the same as the old value and it was valid }
TEdit(Sender).Text := Format('%.6g', [NewVal]);
if (OldVal <> NewVal) and Allow then
begin
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].transOpacity := NewVal;
UpdateFlame(True);
end;
end;
procedure TEditForm.txtDCSet(Sender: TObject);
var
Allow: boolean;
NewVal, OldVal: double;
begin
Allow := True;
OldVal := Round6(cp.xform[SelectedTriangle].pluginColor);
{ Test that it's a valid floating point number }
try
StrToFloat(TEdit(Sender).Text);
except on Exception do
begin
{ It's not, so we restore the old value }
TEdit(Sender).Text := Format('%.6g', [OldVal]);
Allow := False;
end;
end;
NewVal := Round6(StrToFloat(TEdit(Sender).Text));
if NewVal < 0 then NewVal := 0;
if NewVal > 1 then NewVal := 1;
{ If it's not the same as the old value and it was valid }
TEdit(Sender).Text := Format('%.6g', [NewVal]);
if (OldVal <> NewVal) and Allow then
begin
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].pluginColor := NewVal;
UpdateFlame(True);
end;
end;
procedure TEditForm.txtSymmetrySet(Sender: TObject);
var
Allow: boolean;
NewVal, OldVal: double;
begin
Allow := True;
OldVal := Round6(cp.xform[SelectedTriangle].symmetry);
{ Test that it's a valid floating point number }
try
StrToFloat(TEdit(Sender).Text);
except on Exception do
begin
{ It's not, so we restore the old value }
TEdit(Sender).Text := Format('%.6g', [OldVal]);
Allow := False;
end;
end;
NewVal := Round6(StrToFloat(TEdit(Sender).Text));
if NewVal < -1 then NewVal := -1;
if NewVal > 1 then NewVal := 1;
{ If it's not the same as the old value and it was valid }
TEdit(Sender).Text := Format('%.6g', [NewVal]);
if (OldVal <> NewVal) and Allow then
begin
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].symmetry := NewVal;
UpdateFlame(True);
end;
end;
procedure TEditForm.txtOpacityKeyPress(Sender: TObject; var Key: Char);
var
Allow: boolean;
NewVal, OldVal: double;
begin
if (Key = '-') then Key:= #0; // AV
if key = #13 then
begin
{ Stop the beep }
Key := #0;
Allow := True;
OldVal := Round6(cp.xform[SelectedTriangle].transOpacity);
{ Test that it's a valid floating point number }
try
StrToFloat(TEdit(Sender).Text);
except on Exception do
begin
{ It's not, so we restore the old value }
TEdit(Sender).Text := Format('%.6g', [OldVal]);
Allow := False;
end;
end;
NewVal := Round6(StrToFloat(TEdit(Sender).Text));
if NewVal < 0 then NewVal := 0;
if NewVal > 1 then NewVal := 1;
{ If it's not the same as the old value and it was valid }
TEdit(Sender).Text := Format('%.6g', [NewVal]);
if (OldVal <> NewVal) and Allow then
begin
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].transOpacity := NewVal;
UpdateFlame(True);
end;
end;
end;
procedure TEditForm.txtDCKeyPress(Sender: TObject; var Key: Char);
var
Allow: boolean;
NewVal, OldVal: double;
begin
if (Key = '-') then Key:= #0;
if key = #13 then
begin
{ Stop the beep }
Key := #0;
Allow := True;
OldVal := Round6(cp.xform[SelectedTriangle].pluginColor);
{ Test that it's a valid floating point number }
try
StrToFloat(TEdit(Sender).Text);
except on Exception do
begin
{ It's not, so we restore the old value }
TEdit(Sender).Text := Format('%.6g', [OldVal]);
Allow := False;
end;
end;
NewVal := Round6(StrToFloat(TEdit(Sender).Text));
if NewVal < 0 then NewVal := 0;
if NewVal > 1 then NewVal := 1;
{ If it's not the same as the old value and it was valid }
TEdit(Sender).Text := Format('%.6g', [NewVal]);
if (OldVal <> NewVal) and Allow then
begin
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].pluginColor := NewVal;
UpdateFlame(True);
end;
end;
end;
procedure TEditForm.txtSymmetrKeyPress(Sender: TObject; var Key: Char);
var
Allow: boolean;
NewVal, OldVal: double;
begin
if key = #13 then
begin
{ Stop the beep }
Key := #0;
Allow := True;
OldVal := Round6(cp.xform[SelectedTriangle].symmetry);
{ Test that it's a valid floating point number }
try
StrToFloat(TEdit(Sender).Text);
except on Exception do
begin
{ It's not, so we restore the old value }
TEdit(Sender).Text := Format('%.6g', [OldVal]);
Allow := False;
end;
end;
NewVal := Round6(StrToFloat(TEdit(Sender).Text));
if NewVal < -1 then NewVal := -1;
if NewVal > 1 then NewVal := 1;
{ If it's not the same as the old value and it was valid }
TEdit(Sender).Text := Format('%.6g', [NewVal]);
if (OldVal <> NewVal) and Allow then
begin
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].symmetry := NewVal;
UpdateFlame(True);
end;
end;
end;
// -- Variation List Editor ----------------------------------------------------
procedure TEditForm.ValidateVariation;
var
i: integer;
NewVal, OldVal: double;
begin
//i := VEVars.Row - 1;
i := GetVariationIndex(VEVars.Keys[VEVars.Row]); // AV
OldVal := Round6(cp.xform[SelectedTriangle].GetVariation(i));
try
NewVal := Round6(StrToFloat(VEVars.Values[VarNames(i)]));
except
VEVars.Values[VarNames(i)] := Format('%.6g', [OldVal]);
exit;
end;
if (NewVal <> OldVal) then
begin
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].SetVariation(i, NewVal);
VEVars.Values[VarNames(i)] := Format('%.6g', [NewVal]);
ShowSelectedInfo;
UpdateFlame(True);
end;
end;
(*
// here's another way to do this -
// we could use it with variables value editor,
// only if we had an *array* of variables
type
TDblArray = array of double;
PDblArray = ^TDblArray;
procedure ValidateValue(Sender: TValueListEditor; values: PDblArray);
var
Allow: boolean;
i: integer;
NewVal, OldVal: double;
begin
Allow := True;
i := Sender.Row - 1;
OldVal := values^[i];
{ Test that it's a valid floating point number }
try
StrToFloat(Sender.Values[VarNames(i)]);
except on Exception do
begin
{ It's not, so we restore the old value }
Sender.Values[VarNames(i)] := Format('%.6g', [OldVal]);
Allow := False;
end;
end;
NewVal := Round6(StrToFloat(Sender.Values[VarNames(i)]));
Sender.Values[VarNames(i)] := Format('%.6g', [NewVal]);
{ If it's not the same as the old value and it was valid }
if (NewVal <> OldVal) and Allow then
begin
MainForm.UpdateUndo;
values^[i] := NewVal;
Sender.Values[VarNames(i)] := Format('%.6g', [NewVal]);
EditForm.ShowSelectedInfo;
EditForm.UpdateFlame(True);
end;
end;
*)
procedure TEditForm.VEVarsKeyPress(Sender: TObject; var Key: Char);
begin
if key = #13 then
begin
key := #0;
ValidateVariation;
end;
end;
procedure TEditForm.VEVarsChange(Sender: TObject);
begin
ValidateVariation;
end;
procedure TEditForm.VEVarsValidate(Sender: TObject; ACol, ARow: Integer; const KeyName, KeyValue: String);
begin
ValidateVariation;
end;
// -- ValueList mouse stuff ----------------------------------------------------
procedure TEditForm.VEVarsMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
cell: TGridCoord;
begin
if Button = mbLeft then begin
varDragOld:=x;
cell := TValueListEditor(Sender).MouseCoord(x, y);
varDragIndex := cell.Y-1;
if (cell.y < 1) or (cell.y >= TValueListEditor(Sender).RowCount) or
(cell.x <> 0) then exit;
TValueListEditor(Sender).Row := cell.Y;
Screen.Cursor := crHSplit;
//GetCursorPos(mousepos); // hmmm
mousePos := (Sender as TControl).ClientToScreen(Point(x, y));
varDragMode:=true;
varDragPos:=0;
varMM := false;
SetCaptureControl(TValueListEditor(Sender));
if Sender = VEVars then
begin
varDragIndex := GetVariationIndex(VEVars.Keys[varDragIndex+1]); // AV
varDragValue := cp.xform[SelectedTriangle].GetVariation(varDragIndex);
end
else if Sender = vleVariables then
cp.xform[SelectedTriangle].GetVariable(vleVariables.Keys[varDragIndex+1], varDragValue)
else if Sender = vleChaos then begin
if mnuChaosViewTo.Checked then
pDragValue := @cp.xform[SelectedTriangle].modWeights[varDragIndex]
else
pDragValue := @cp.xform[varDragIndex].modWeights[SelectedTriangle];
varDragValue := pDragValue^;
end
else Assert(false);
HasChanged := False;
end;
end;
procedure TEditForm.VEVarsMouseMove(Sender: TObject; Shift: TShiftState; X,
Y: Integer);
var
v: double;
cell: TGridCoord;
begin
cell := TValueListEditor(Sender).MouseCoord(x, y);
if (cell.Y > 0) and (cell.X = 0) then TValueListEditor(Sender).Cursor := crHandPoint
else TValueListEditor(Sender).Cursor := crDefault;
if varMM then // hack: to skip MouseMove event
begin
varMM:=false;
end
else
if varDragMode and (x <> varDragOld) then
begin
Inc(varDragPos, x - varDragOld);
if GetKeyState(VK_MENU) < 0 then v := 100000
else if GetKeyState(VK_CONTROL) < 0 then v := 10000
else if GetKeyState(VK_SHIFT) < 0 then v := 100
else v := 1000;
v := Round6(varDragValue + varDragPos/v);
SetCursorPos(MousePos.x, MousePos.y); // hmmm
// this Delphi is WEIRD!
// why GetCursorPos deals with TPoint,
// and SetCursorPos - with two integers? :)
varMM:=true;
//cp.xform[SelectedTriangle].vars[varDragIndex] := v;
if Sender = VEVars then
begin
cp.xform[SelectedTriangle].SetVariation(varDragIndex, v);
VEVars.Values[VarNames(varDragIndex)] := FloatToStr(v); //Format('%.6g', [v]);
end
else if Sender = vleVariables then begin
cp.xform[SelectedTriangle].SetVariable(vleVariables.Keys[varDragIndex+1], v);
vleVariables.Values[vleVariables.Keys[varDragIndex+1]] := FloatToStr(v);
end
else begin
if v < 0 then v := 0;
//cp.xform[SelectedTriangle].modWeights[varDragIndex] := v;
pDragValue^ := v;
vleChaos.Cells[1, varDragIndex+1] := FloatToStr(v);
end;
HasChanged := True;
UpdateFlameX;
end;
end;
procedure TEditForm.VEVarsMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button <> mbLeft then exit;
SetCaptureControl(nil);
if varDragMode then
begin
varDragMode:=false;
Screen.Cursor := crDefault;
if HasChanged then
begin
MainForm.UpdateUndo;
UpdateFlame(true);
HasChanged := False;
if (Sender = vleChaos) and ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
end;
end;
procedure TEditForm.VEVarsDblClick(Sender: TObject);
var
n, i: integer;
v, v1: double;
changed, allzero: boolean;
varname: string;
begin
n := TValueListEditor(Sender).Row - 1;
assert(n >= 0);
assert(n < TValueListEditor(Sender).rowCount);
//changed := false;
if (SelectedTriangle < 0) or (SelectedTriangle > High(cp.xform)) then
changed := false
else begin
if Sender = VEVars then
begin
if (n < 0) or (n > (cp.xform[SelectedTriangle].NumVariations - 1)) then
changed := false
else begin
i := n; // AV
n := GetVariationIndex(VEVars.Keys[i+1]); // AV
v := cp.xform[SelectedTriangle].GetVariation(n);
if AllowResetLinear then // AV
begin
if v = 0 then
begin
allzero := true;
for i := 1 to NrVar-1 do
allzero := allzero and (cp.xform[SelectedTriangle].GetVariation(i) = 0);
if (cp.xform[SelectedTriangle].GetVariation(0) = 1) and allzero then
cp.xform[SelectedTriangle].SetVariation(0, 0);
cp.xform[SelectedTriangle].SetVariation(n, 1);
end
else cp.xform[SelectedTriangle].SetVariation(n, 0);
end else
cp.xform[SelectedTriangle].SetVariation(n, IfThen(v = 0, 1, 0));
changed := (cp.xform[SelectedTriangle].GetVariation(n) <> v);
end;
end
else if Sender = vleVariables then begin
varname := vleVariables.Keys[n + 1]; // AV
cp.xform[SelectedTriangle].GetVariable(varname, v);
cp.xform[SelectedTriangle].ResetVariable(varname);
cp.xform[SelectedTriangle].GetVariable(varname, v1);
changed := (v1 <> v);
end
else if Sender = vleChaos then begin
if ((varDragIndex) < 0) or ((varDragIndex) > high(cp.xform[SelectedTriangle].modWeights)) then
changed := false
else
begin
if mnuChaosViewTo.Checked then
pDragValue := @cp.xform[SelectedTriangle].modWeights[varDragIndex]
else
pDragValue := @cp.xform[varDragIndex].modWeights[SelectedTriangle];
v := pDragValue^;
v := ifthen(v = 1, 0, 1);
pDragValue^ := v;
vleChaos.Cells[1, n+1] := FloatToStr(v);
changed := true;
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end
//else Assert(false);
end else changed := false;
end;
if changed then MainForm.UpdateUndo;
UpdateFlame(true);
end;
{ **************************************************************************** }
function TEditForm.GetPivot: TSPoint;
begin
Result := GetPivot(SelectedTriangle);
end;
function TEditForm.GetPivot(n: integer): TSPoint;
begin
if (PivotMode = pivotLocal) or {EdgeCaught} (mouseOverEdge >= 0) then // should be always local for edges (hmm...?)
with MainTriangles[n] do begin
Result.x := x[1] + (x[0] - x[1])*LocalPivot.x + (x[2] - x[1])*LocalPivot.y;
Result.y := y[1] + (y[0] - y[1])*LocalPivot.x + (y[2] - y[1])*LocalPivot.y;
end
else begin
Result.x := WorldPivot.x;
Result.y := WorldPivot.y;
end;
end;
procedure TEditForm.ScriptGetPivot(var px, py: double);
begin
// AV: sometimes the scripter swaps pre and post triangles...
if (PivotMode = pivotLocal) then
with MainTriangles[SelectedTriangle] do begin
px := x[1] + (x[0] - x[1])*LocalPivot.x + (x[2] - x[1])*LocalPivot.y;
py := y[1] + (y[0] - y[1])*LocalPivot.x + (y[2] - y[1])*LocalPivot.y;
end
{ with cp.xform[SelectedTriangle] do
begin
if not postXswap then begin
px := c[2,0] + c[0,0]*LocalPivot.x + (-c[0,1])*LocalPivot.y;
py := -c[2,1] + (-c[0,1])*LocalPivot.x + c[1,1]*LocalPivot.y;
end
else begin
px := p[2,0] + p[0,0]*LocalPivot.x + (-p[0,1])*LocalPivot.y;
py := -p[2,1] + (-p[0,1])*LocalPivot.x + p[1,1]*LocalPivot.y;
end;
end }
else begin
px := WorldPivot.x;
py := WorldPivot.y;
end;
end;
procedure TEditForm.InvCurrentNumClick(Sender: TObject);
var
num: double;
sn: string;
isEdit: boolean;
begin
if (ActiveControl = txtTrgMoveValue) then
begin
InvertMovevalue1.Click;
exit;
end
else if (ActiveControl is TComboBox) then exit;
isEdit := (ActiveControl is TEdit);
if isEdit then
if (ActiveControl = txtSearchBox) or (ActiveControl = txtName) then
isEdit := False;
if not (isEdit or (ActiveControl is TValueListEditor)) then
begin
Application.MessageBox(PChar(TextByKey('editor-status-nonumfield')),
ApophysisSVN, MB_ICONWARNING);
exit;
end;
try
if isEdit then
sn := TEdit(ActiveControl).Text
else // if (ActiveControl is TValueListEditor) then
sn := TValueListEditor(ActiveControl).Cells[1, TValueListEditor(ActiveControl).Row];
num := StrToFloat(sn);
if (abs(num) < 1E-5) then exit;
sn := Format('%.6g', [1/num]);
if isEdit then
begin
TEdit(ActiveControl).Text := sn;
TEdit(ActiveControl).OnExit(ActiveControl);
end
else // if (ActiveControl is TValueListEditor) then
begin
TValueListEditor(ActiveControl).Cells[1, TValueListEditor(ActiveControl).Row] := sn;
TValueListEditor(ActiveControl).OnExit(ActiveControl);
end;
except
end;
end;
procedure TEditForm.InvertMovevalue1Click(Sender: TObject);
var step: double;
begin
try
step := StrToFloat(txtTrgMoveValue.Text);
if (abs(step) >= 0.1) then txtTrgMoveValue.Text := Format('%.6g', [1/step]);
except
txtTrgMoveValue.ItemIndex := 1;
end;
end;
procedure TEditForm.InvertXaosClick(Sender: TObject);
var i: smallint;
cmax: double;
begin
MainForm.UpdateUndo;
if mnuChaosViewTo.Checked then
begin
cmax := MaxValue(cp.xform[SelectedTriangle].modWeights);
if (cmax > 0) then
for i := 0 to Transforms-1 do
cp.xform[SelectedTriangle].modWeights[i] :=
IfThen(cp.xform[SelectedTriangle].modWeights[i] = 0, cmax,
cmax - cp.xform[SelectedTriangle].modWeights[i])
else for i := 0 to Transforms-1 do
cp.xform[SelectedTriangle].modWeights[i] := 1;
end else begin
cmax := 0;
for i := 0 to Transforms-1 do
if (cp.xform[i].modWeights[SelectedTriangle] > cmax) then
cmax := cp.xform[i].modWeights[SelectedTriangle];
if (cmax > 0) then
for i := 0 to Transforms-1 do
cp.xform[i].modWeights[SelectedTriangle] :=
IfThen(cp.xform[i].modWeights[SelectedTriangle] = 0, cmax,
cmax - cp.xform[i].modWeights[SelectedTriangle])
else for i := 0 to Transforms-1 do
cp.xform[i].modWeights[SelectedTriangle] := 1;
end;
UpdateFlame(true);
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
procedure TEditForm.UpdateColorBar;
var
BitMap: TBitmap;
Row: pRGBTripleArray;
i: smallint;
begin
BitMap := TBitMap.Create;
try
Bitmap.PixelFormat := pf24bit;
BitMap.Width := 256;
BitMap.Height := 1;
Row := Bitmap.Scanline[0];
for i := 0 to 255 do
with Row[i] do
begin
rgbtRed := MainCP.cmap[i][0];
rgbtGreen := MainCP.cmap[i][1];
rgbtBlue := MainCP.cmap[i][2];
end;
EditForm.ColorBarPicture.Picture.Graphic := Bitmap;
EditForm.ColorBarPicture.Refresh;
finally
BitMap.Free;
end;
end;
procedure TEditForm.RotateTriangleBy(const angle: double); // AV
var
i: smallint;
begin
MainForm.UpdateUndo;
if (not UseTriangleSync) or (SelectedTriangle = Transforms) then
begin
if RotateXYO.Checked then
MainTriangles[SelectedTriangle] :=
RotateTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, angle)
else if RotateX.Checked then begin
MainTriangles[SelectedTriangle] :=
RotateTriangleXY(MainTriangles[SelectedTriangle], 0, angle);
if tbAutoWeights.Down then cp.CalculateWeights; // AV
end else if RotateY.Checked then begin
MainTriangles[SelectedTriangle] :=
RotateTriangleXY(MainTriangles[SelectedTriangle], 2, angle);
if tbAutoWeights.Down then cp.CalculateWeights; // AV
end else //if RotateO.Checked then
MainTriangles[SelectedTriangle] :=
RotateTriangleO(MainTriangles[SelectedTriangle], WorldPivot.x, WorldPivot.y, angle);
end
else begin
if RotateXYO.Checked then
for i in SyncTriangles do
MainTriangles[i] :=
RotateTrianglePoint(MainTriangles[i], GetPivot(i).x, GetPivot(i).y, angle)
else if RotateX.Checked then
for i in SyncTriangles do
MainTriangles[i] := RotateTriangleXY(MainTriangles[i], 0, angle)
else if RotateY.Checked then
for i in SyncTriangles do
MainTriangles[i] := RotateTriangleXY(MainTriangles[i], 2, angle)
else //if RotateO.Checked then
for i in SyncTriangles do
MainTriangles[i] := RotateTriangleO(MainTriangles[i], WorldPivot.x, WorldPivot.y, angle);
end;
HasChanged := True;
UpdateFlame(true);
end;
procedure TEditForm.btTrgRotateLeftClick(Sender: TObject);
var
angle: double;
begin
try
angle := StrToFloat(txtTrgRotateValue.Text);
except
txtTrgRotateValue.ItemIndex := 1;
exit;
end;
assert(angle <> 0);
if GetKeyState(VK_CONTROL) < 0 then angle := angle / 6.0
else if GetKeyState(VK_SHIFT) < 0 then angle := angle * 6.0;
// AV: to show internally modified value
if (ShowModVals.Checked) then txtTrgRotateValue.Text := Format('%.6g', [angle]);
angle := PI/180 * angle; // AV
RotateTriangleBy(angle); // AV
end;
procedure TEditForm.btTrgRotateLeft90Click(Sender: TObject);
begin
RotateTriangleBy(PI/2); // AV
end;
procedure TEditForm.btTrgRotateRightClick(Sender: TObject);
var
angle: double;
begin
try
angle := StrToFloat(txtTrgRotateValue.Text);
except
txtTrgRotateValue.ItemIndex := 1;
exit;
end;
assert(angle <> 0);
if GetKeyState(VK_CONTROL) < 0 then angle := angle/6.0
else if GetKeyState(VK_SHIFT) < 0 then angle := angle*6.0;
// AV: to show internally modified value
if (ShowModVals.Checked) then txtTrgRotateValue.Text := Format('%.6g', [angle]);
angle := -PI/180 * angle; // AV
RotateTriangleBy(angle); // AV
end;
procedure TEditForm.btTrgRotateRight90Click(Sender: TObject);
begin
RotateTriangleBy(-PI/2); // AV
end;
procedure TEditForm.PaintBackground;
begin
assert(false);
TriangleViewPaint(TriangleView);
end;
procedure TEditForm.TrgMove(dx, dy: double);
var
i, j: smallint;
offset: double;
begin
try
offset := StrToFloat(txtTrgMoveValue.Text);
assert(offset <> 0);
except
txtTrgMoveValue.ItemIndex := 1;
exit;
end;
if GetKeyState(VK_CONTROL) < 0 then offset := offset/10.0
else if GetKeyState(VK_SHIFT) < 0 then offset := offset*10.0;
// AV: to show internally modified value
if (ShowModVals.Checked) then txtTrgMoveValue.Text := Format('%.6g', [offset]);
MainForm.UpdateUndo;
if (not UseTriangleSync) or (SelectedTriangle = Transforms) then
for i := 0 to 2 do begin
MainTriangles[SelectedTriangle].x[i] :=
MainTriangles[SelectedTriangle].x[i] + dx*offset;
MainTriangles[SelectedTriangle].y[i] :=
MainTriangles[SelectedTriangle].y[i] + dy*offset;
end
else
for j in SyncTriangles do
for i := 0 to 2 do begin
MainTriangles[j].x[i] := MainTriangles[j].x[i] + dx * offset;
MainTriangles[j].y[i] := MainTriangles[j].y[i] + dy * offset;
end;
// HasChanged := True;
UpdateFlame(true);
end;
procedure TEditForm.btTrgMoveLeftClick(Sender: TObject);
begin
TrgMove(-1,0);
end;
procedure TEditForm.btTrgMoveRightClick(Sender: TObject);
begin
TrgMove(1,0);
end;
procedure TEditForm.btTrgMoveUpClick(Sender: TObject);
begin
if RectGrid.Checked then TrgMove(0,1)
else TrgMove(0.5, sqrt(3)*0.5);
end;
procedure TEditForm.btTrgMoveDownClick(Sender: TObject);
begin
if RectGrid.Checked then TrgMove(0,-1)
else TrgMove(-0.5, -sqrt(3)*0.5);
end;
{
procedure TEditForm.btTrgMoveLUClick(Sender: TObject);
begin
TrgMove(-1,1);
end;
procedure TEditForm.btTrgMoveLDClick(Sender: TObject);
begin
TrgMove(-1,-1);
end;
procedure TEditForm.btTrgMoveRUClick(Sender: TObject);
begin
TrgMove(1,1);
end;
procedure TEditForm.btTrgMoveRDClick(Sender: TObject);
begin
TrgMove(1,-1);
end;
}
procedure TEditForm.btTrgScaleUpClick(Sender: TObject);
var
scale: double;
i: smallint;
begin
try
scale := StrToFloat(txtTrgScaleValue.Text) / 100.0;
except
txtTrgScaleValue.ItemIndex := 1;
exit;
end;
if scale = 0 then scale := 1e-6; //assert(scale <> 0);
// AV: fixed - added abs() for negative value
if GetKeyState(VK_CONTROL) < 0 then scale := sqrt(abs(scale))
else if GetKeyState(VK_SHIFT) < 0 then scale := scale*scale;
// AV: to show internally modified value
if (ShowModVals.Checked) then txtTrgScaleValue.Text := Format('%.6g', [scale * 100.0]);
MainForm.UpdateUndo;
if (not UseTriangleSync) or (SelectedTriangle = Transforms) then
begin
if ScaleXYO.Checked then
MainTriangles[SelectedTriangle] :=
ScaleTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, scale)
else if ScaleX.Checked then
MainTriangles[SelectedTriangle] := ScaleTriangleXY(MainTriangles[SelectedTriangle], 0, scale)
else if ScaleY.Checked then
MainTriangles[SelectedTriangle] := ScaleTriangleXY(MainTriangles[SelectedTriangle], 2, scale)
else //if ScaleO.Checked then
MainTriangles[SelectedTriangle] :=
ScaleTriangleO(MainTriangles[SelectedTriangle], WorldPivot.x, WorldPivot.y, scale);
end
else begin
if ScaleXYO.Checked then
for i in SyncTriangles do
MainTriangles[i] :=
ScaleTrianglePoint(MainTriangles[i], GetPivot(i).x, GetPivot(i).y, scale)
else if ScaleX.Checked then
for i in SyncTriangles do
MainTriangles[i] := ScaleTriangleXY(MainTriangles[i], 0, scale)
else if ScaleY.Checked then
for i in SyncTriangles do
MainTriangles[i] := ScaleTriangleXY(MainTriangles[i], 2, scale)
else //if ScaleO.Checked then begin
for i in SyncTriangles do
MainTriangles[i] :=
ScaleTriangleO(MainTriangles[i], WorldPivot.x, WorldPivot.y, scale);
end;
if tbAutoWeights.Down then cp.CalculateWeights; // AV
HasChanged := True;
UpdateFlame(true);
end;
procedure TEditForm.btTrgScaleDownClick(Sender: TObject);
var
scale: double;
i: smallint;
begin
try
scale := 100.0 / StrToFloat(txtTrgScaleValue.Text);
except
txtTrgScaleValue.ItemIndex := 1;
exit;
end;
if scale = 0 then scale := 1e-6; //assert(scale <> 0);
// AV: fixed for negative value
if GetKeyState(VK_CONTROL) < 0 then scale := sqrt(abs(scale))
else if GetKeyState(VK_SHIFT) < 0 then scale := scale*scale;
// AV: to show modified value
if (ShowModVals.Checked) then txtTrgScaleValue.Text := Format('%.6g', [scale * 100.0]);
MainForm.UpdateUndo;
if (not UseTriangleSync) or (SelectedTriangle = Transforms) then
begin
if ScaleXYO.Checked then
MainTriangles[SelectedTriangle] :=
ScaleTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, scale)
else if ScaleX.Checked then
MainTriangles[SelectedTriangle] := ScaleTriangleXY(MainTriangles[SelectedTriangle], 0, scale)
else if ScaleY.Checked then
MainTriangles[SelectedTriangle] := ScaleTriangleXY(MainTriangles[SelectedTriangle], 2, scale)
else //if ScaleO.Checked then
MainTriangles[SelectedTriangle] :=
ScaleTriangleO(MainTriangles[SelectedTriangle], WorldPivot.x, WorldPivot.y, scale);
end
else begin
if ScaleXYO.Checked then
for i in SyncTriangles do
MainTriangles[i] :=
ScaleTrianglePoint(MainTriangles[i], GetPivot(i).x, GetPivot(i).y, scale)
else if ScaleX.Checked then
for i in SyncTriangles do
MainTriangles[i] := ScaleTriangleXY(MainTriangles[i], 0, scale)
else if ScaleY.Checked then
for i in SyncTriangles do
MainTriangles[i] := ScaleTriangleXY(MainTriangles[i], 2, scale)
else //if ScaleO.Checked then begin
for i in SyncTriangles do
MainTriangles[i] :=
ScaleTriangleO(MainTriangles[i], WorldPivot.x, WorldPivot.y, scale);
end;
if tbAutoWeights.Down then cp.CalculateWeights; // AV
HasChanged := True;
UpdateFlame(true);
end;
procedure TEditForm.TriangleViewKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (oldMode = modeNone) and
(key in [{VK_SHIFT,} VK_MENU, VK_CONTROL]) then
begin
oldMode := editMode;
modeKey := key;
if key = VK_MENU then
if editMode <> modeRotate then
begin
editMode := modeRotate;
TriangleView.Cursor := crEditRotate;
end
else begin
editMode := modeMove;
TriangleView.Cursor := crEditMove;
end
else {if key = VK_CONTROL then}
begin
if editMode <> modeScale then
begin
editMode := modeScale;
TriangleView.Cursor := crEditScale;
end
else begin
editMode := modeMove;
TriangleView.Cursor := crEditMove;
end
end;
end
else
case key of
VK_LEFT:
if Shift = [ssAlt] then btTrgRotateLeftClick(Sender)
else TrgMove(-1,0);
VK_RIGHT:
if Shift = [ssAlt] then btTrgRotateRightClick(Sender)
else TrgMove(1,0);
VK_UP:
if Shift = [ssAlt] then btTrgScaleUpClick(Sender)
else TrgMove(0,1);
VK_DOWN:
if Shift = [ssAlt] then btTrgScaleDownClick(Sender)
else TrgMove(0,-1);
VK_PRIOR: btTrgRotateLeftClick(Sender);
VK_NEXT: btTrgRotateRightClick(Sender);
VK_HOME: btTrgScaleUpClick(Sender);
VK_END: btTrgScaleDownClick(Sender);
VK_INSERT: mnuDupClick(Sender);
VK_DELETE: mnuDeleteClick(Sender);
// can be changed in the future...
Ord('R'): btnResetPivotClick(Sender);
Ord('P'): btnPickPivotClick(Sender);
Ord('T'): tbPostXswapClick(Sender);
{
Ord('I'): // Invisible <<-- AV: or Invert :-)
chkXformInvisible.Checked := not chkXformInvisible.Checked;
}
Ord('S'): // Solo
begin
chkXformSolo.Checked := not chkXformSolo.Checked;
end;
189: // "-"
begin
GraphZoom := GraphZoom * 0.8;
EditForm.StatusBar.Panels[2].Text := Format(TextByKey('editor-status-zoomformat'), [GraphZoom]);
TriangleView.Invalidate;
end;
187: // "+"
begin
GraphZoom := GraphZoom * 1.25;
EditForm.StatusBar.Panels[2].Text := Format(TextByKey('editor-status-zoomformat'), [GraphZoom]);
TriangleView.Invalidate;
end;
VK_ESCAPE:
begin
if TriangleCaught or CornerCaught or EdgeCaught then begin
if modeHack then begin
assert(oldMode <> modeNone);
editMode := oldMode;
oldMode := modeNone;
modeHack := false;
end;
if HasChanged then
begin
MainTriangles[SelectedTriangle] := OldTriangle;
HasChanged := False;
end;
EdgeCaught := false;
CornerCaught := false;
TriangleCaught := false;
TriangleView.Invalidate;
UpdateFlameX;
end;
end
end;
end;
procedure TEditForm.TriangleViewKeyUp(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (oldMode <> modeNone) and (key = modeKey) then
begin
assert(key in [VK_MENU, VK_CONTROL]);
editMode := oldMode;
oldMode := modeNone;
// tbMove.Down := (editMode = modeMove);
// tbRotate.Down := (editMode = modeRotate);
// tbScale.Down := (editMode = modeScale);
// hack: to generate MouseMove event
GetCursorPos(MousePos);
SetCursorPos(MousePos.x, MousePos.y);
end;
end;
procedure TEditForm.TriangleViewExit(Sender: TObject);
begin
if oldMode <> modeNone then
begin
editMode := oldMode;
oldMode := modeNone;
// tbMove.Down := (editMode = modeMove);
// tbRotate.Down := (editMode = modeRotate);
// tbScale.Down := (editMode = modeScale);
end;
mouseOverTriangle := -1;
TriangleView.Invalidate;
end;
procedure TEditForm.TriangleViewMouseLeave(Sender: TObject);
begin
if viewDragMode = false then
begin
mouseOverTriangle := -1;
TriangleView.Invalidate;
end;
end;
procedure TEditForm.EditKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
var num: double;
begin
case key of
VK_ADD:
if SelectedTriangle < LastTriangle then begin
txtNameExit(Sender); // store name before re-filling name box by changing xform
Inc(SelectedTriangle);
TriangleView.Invalidate;
ShowSelectedInfo;
end;
VK_SUBTRACT:
if SelectedTriangle > 0 then begin
txtNameExit(Sender); // store name before re-filling name box by changing xform
Dec(SelectedTriangle);
TriangleView.Invalidate;
ShowSelectedInfo;
end;
VK_SPACE:
if not txtName.Focused then
btnPivotModeClick(Sender);
Ord('I'):
if (not txtName.Focused) and (not txtSearchBox.Focused) then begin
if txtTrgMoveValue.Focused then InvertMoveValue1.Click
else InvCurrentNum.Click;
end;
Ord('X'):
if (not txtName.Focused) and (not txtSearchBox.Focused) then
begin
ScaleX.Checked := True;
RotateX.Checked := True;
end;
Ord('Y'):
if (not txtName.Focused) and (not txtSearchBox.Focused) then
begin
ScaleY.Checked := True;
RotateY.Checked := True;
end;
Ord('O'):
if (not txtName.Focused) and (not txtSearchBox.Focused) then
begin
ScaleO.Checked := True;
RotateO.Checked := True;
end;
Ord('A'):
if (not txtName.Focused) and (not txtSearchBox.Focused) then
begin
ScaleXYO.Checked := True;
RotateXYO.Checked := True;
end;
Ord('M'):
if (not txtName.Focused) and (not txtSearchBox.Focused) then
begin
mnuCalcExpression.Click;
end;
else
key_handled := false;
exit;
end;
key_handled := true;
key := 0;
end;
procedure TEditForm.EditKeyPress(Sender: TObject; var Key: Char);
begin
if txtName.Focused then begin
{
if (key = '+') or (key='-') then begin
// nvm...code moved to EditKeyDown
key := #0;
end;
if (key='"') then key := #0; // we dont want that in "name" box -> XML mess!
}
// AV: we also don't want XML-tag's brackets here
if CharInSet(Key,['+', '-', '"', '<', '>']) then key := #0;
exit;
end
else if txtSearchBox.Focused then
begin
if (key = #13) then key := #0; // AV: to prevent a beep
exit;
end;
// kill alphanumeric keys generally
// if key_handled or (CharInSet(key,['A'..'z'])) then key := #0; // hmmm...
{ AV: the code above doesn't work properly, so I rewrote it }
{ AV: a lot of users type comma as the decimal separator,
but Apo discard it. It's not normally... }
if (Key = ',') then Key := '.'; // FormatSettings.DecimalSeparator;
if key_handled or not CharInSet(Key,['0'..'9', '-', #8, #13, '.'])
then Key:= #0;
end;
procedure TEditForm.splitterMoved(Sender: TObject);
begin
UpdatePreview;
end;
procedure TEditForm.tbSelectClick(Sender: TObject);
begin
SelectMode := not SelectMode;
tbSelect.Down := SelectMode;
if SelectMode then
begin
StatusBar.Panels[2].Text := TextByKey('editor-status-selecton');
end
else begin
mouseOverTriangle := SelectedTriangle;
StatusBar.Panels[2].Text := TextByKey('editor-status-selectoff');;
end;
// hack: to generate MouseMove event
GetCursorPos(MousePos);
SetCursorPos(MousePos.x, MousePos.y);
end;
procedure TEditForm.tbSyncTrianglesClick(Sender: TObject);
begin
UseTriangleSync := not UseTriangleSync;
AdjustSyncTriangles;
end;
procedure TEditForm.AdjustSyncTriangles;
begin
if UseTriangleSync then begin
tbSyncTriangles.Style := tbsDropDown;
tbSyncTriangles.DropdownMenu := mnuSyncTriangles;
TriangleToolBar.Perform(CM_CONTROLCHANGE, WPARAM(tbSyncTriangles), 36);
tbSyncTriangles.ImageIndex := 44;
tbSyncTriangles.Hint := TextByKey('editor-tab-triangle-enablesync');
end
else begin
tbSyncTriangles.Style := tbsButton;
tbSyncTriangles.DropdownMenu := nil;
TriangleToolBar.Perform(CM_CONTROLCHANGE, WPARAM(tbSyncTriangles), 23);
tbSyncTriangles.ImageIndex := 43;
tbSyncTriangles.Hint := TextByKey('editor-tab-triangle-disablesync');
end;
end;
procedure TEditForm.TriangleViewMouseWheel(Sender: TObject; Shift: TShiftState;
WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
var
fx, fy, sc: double;
p: TPoint;
begin
p := TriangleView.ScreenToClient(MousePos);
Scale(fx, fy, p.X, p.Y);
if WheelDelta > 0 then GraphZoom := GraphZoom * 1.25
else GraphZoom := GraphZoom * 0.8;
EditForm.StatusBar.Panels[2].Text := Format(TextByKey('editor-status-zoomformat'), [GraphZoom]);
if viewDragMode then begin
sc := GraphZoom * 50;
gCenterX := fx - (p.X - TriangleView.Width/2) / sc;
gCenterY := fy + (p.Y - TriangleView.Height/2) / sc;
end;
TriangleView.Invalidate;
Handled := true;
end;
procedure TEditForm.TriangleViewDblClick(Sender: TObject);
begin
if mouseOverTriangle >= 0 then
begin
if mouseOverCorner >= 0 then begin
case mouseOverCorner of
0: if editMode = modeRotate then ResetAxisRotation(0) else ResetAxisScale(0);
1: if editMode = modeRotate then ResetAxisRotation(1)
else begin
if editMode = modeScale then
ResetAxisScale(1)
else begin
if cp.xform[SelectedTriangle].postXswap then
btnOpostClick(Sender)
else
btnOcoefsClick(Sender);
end;
end;
2: if editMode = modeRotate then ResetAxisRotation(2) else ResetAxisScale(2);
end;
end
else if mouseOverEdge >= 0 then begin
if AxisLock then begin
if (editMode = modeScale) or (mouseOverEdge = 2)then
mnuResetTrgScaleClick(Sender)
else
mnuResetTrgRotationClick(Sender);
end
else case mouseOverEdge of
0: if editMode = modeScale then ResetAxisScale(0) else ResetAxisRotation(0);
1: if editMode = modeScale then ResetAxisScale(2) else ResetAxisRotation(2);
2: mnuResetTrgScaleClick(Sender);
end;
end
else if mouseOverWidget >= 0 then begin
case editMode of
modeScale: mnuResetTrgScaleClick(Sender);
else mnuResetTrgRotationClick(Sender);
end;
end
else case editMode of
//modeMove: Do Nothing
modeScale: mnuResetTrgScaleClick(Sender);
modeRotate: mnuResetTrgRotationClick(Sender);
end;
end
else AutoZoom;
end;
procedure TEditForm.TriangleViewInvalidate(Sender: TObject);
begin
TriangleView.Invalidate;
end;
procedure TEditForm.tbEditModeClick(Sender: TObject);
begin
// ExtendedEdit := (Sender = tbExtendedEdit);
if Sender = tbRotate then
begin
editMode := modeRotate;
//tbRotate.Down := true;
end
else if Sender = tbScale then
begin
editMode := modeScale;
//tbScale.Down := true;
end
else begin
editMode := modeMove;
//tbMove.Down := true;
end;
TToolButton(Sender).Down := true;
TriangleView.Invalidate;
end;
procedure TEditForm.tbExtendedEditClick(Sender: TObject);
begin
ExtendedEdit := not ExtendedEdit;
tbExtendedEdit.Down := ExtendedEdit;
TriangleView.Invalidate;
end;
procedure TEditForm.tbAxisLockClick(Sender: TObject);
begin
AxisLock := not AxisLock;
tbAxisLock.Down := AxisLock;
end;
procedure TEditForm.tbCommentClick(Sender: TObject);
begin
CommentForm.memComment.Lines.Text := cp.comment;
if CommentForm.ShowModal = mrOK then
begin
cp.comment := Trim(CommentForm.memComment.Lines.Text);
MainCp.comment := cp.comment;
end;
end;
procedure TEditForm.tbFullViewClick(Sender: TObject);
begin
MainForm.mnuFullScreenClick(Sender);
end;
//-- Variables -------------------------------------------------------------
procedure TEditForm.ValidateVariable;
var
i: integer;
NewVal, OldVal: double;
str, oldstr: string;
begin
i := vleVariables.Row;
{$ifndef VAR_STR}
cp.xform[SelectedTriangle].GetVariable(vleVariables.Keys[i], OldVal);
{ Test that it's a valid floating point number }
try
NewVal := Round6(StrToFloat(vleVariables.Values[vleVariables.Keys[i]]));
except
{ It's not, so we restore the old value }
vleVariables.Values[vleVariables.Keys[i]] := Format('%.6g', [OldVal]);
// cp.xform[SelectedTriangle].GetVariableStr(vleVariables.Keys[i]);
exit;
end;
{ If it's not the same as the old value and it was valid }
if (NewVal <> OldVal) then
begin
vleVariables.Cells[1,i];
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].SetVariable(vleVariables.Keys[i], NewVal);
vleVariables.Values[vleVariables.Keys[i]] := Format('%.6g', [NewVal]);
ShowSelectedInfo;
UpdateFlame(True);
end;
{$else}
oldstr := cp.xform[SelectedTriangle].GetVariableStr(vleVariables.Keys[i]);
str := vleVariables.Values[vleVariables.Keys[i]];
cp.xform[SelectedTriangle].SetVariableStr(vleVariables.Keys[i], str);
if str <> oldstr then
begin
MainForm.UpdateUndo;
vleVariables.Values[vleVariables.Keys[i]] := str;
ShowSelectedInfo;
UpdateFlame(True);
end;
{$endif}
end;
procedure TEditForm.vleVariablesExit(Sender: TObject);
begin
ValidateVariable;
end;
procedure TEditForm.vleVariablesKeyPress(Sender: TObject; var Key: Char);
begin
if key <> #13 then Exit;
key := #0;
ValidateVariable;
end;
procedure TEditForm.vleVariablesValidate(Sender: TObject; ACol, ARow: Integer; const KeyName, KeyValue: string);
begin
ValidateVariable;
end;
// -----------------------------------------------------------------------------
procedure TEditForm.txtValidateValue(Sender: TObject);
var
t: double;
begin
try
t := StrToFloat(TComboBox(Sender).Text);
if t <> 0 then exit;
except
TComboBox(Sender).ItemIndex := 1;
end;
end;
procedure TEditForm.txtValKeyPress(Sender: TObject; var Key: Char);
begin
if key <> #13 then exit;
key := #0;
txtValidateValue(Sender);
end;
procedure TEditForm.mnuResetTriangleClick(Sender: TObject);
begin
if (MainTriangles[SelectedTriangle].x[0] = MainTriangles[-1].x[0]) and
(MainTriangles[SelectedTriangle].x[1] = MainTriangles[-1].x[1]) and
(MainTriangles[SelectedTriangle].x[2] = MainTriangles[-1].x[2]) and
(MainTriangles[SelectedTriangle].y[0] = MainTriangles[-1].y[0]) and
(MainTriangles[SelectedTriangle].y[1] = MainTriangles[-1].y[1]) and
(MainTriangles[SelectedTriangle].y[2] = MainTriangles[-1].y[2])
then exit;
MainForm.UpdateUndo;
MainTriangles[SelectedTriangle] := MainTriangles[-1];
UpdateFlame(True);
end;
procedure TEditForm.mnuResetAllClick(Sender: TObject);
var
i: integer;
saved: boolean;
begin
MainForm.UpdateUndo;
for i := 0 to Transforms do cp.xform[i].Clear;
cp.xform[0].SetVariation(0, 1);
cp.xform[0].density := 0.5;
cp.xform[1].symmetry := 1;
cp.center[0] := 0;
cp.center[1] := 0;
cp.zoom := 0;
cp.pixels_per_unit := PreviewImage.Width/4;
cp.FAngle := 0;
// AV: add 3D-camera resetting
cp.cameraPitch := 0;
cp.cameraYaw := 0;
cp.cameraRoll := 0;
cp.cameraPersp := 0;
cp.cameraZPos := 0;
cp.cameraDOF := 0;
Transforms := 1;
SelectedTriangle := 0; // AV: fixed - was 1;
MainTriangles[0] := MainTriangles[-1];
MainTriangles[1] := MainTriangles[-1]; // kinda reset finalxform
EnableFinalXform := false;
assert(cp.HasFinalXForm = false);
UpdateXformsList;
AutoZoom;
UpdateFlame(True);
if AutoSaveXML then // AV: create a flame from scratch if needed
begin
MainCp.name := 'New flame' + FormatDateTime(' (MM-dd-yyyy hh-mm-ss)', Now);
if (OpenFileType = ftXML) then
saved := MainForm.SaveXMLFlame(MainCp, MainCp.name, OpenFile)
else
saved := MainForm.SaveFlame(MainCp, MainCp.name, OpenFile);
if saved then MainForm.AddFlameToList; // AV: show the new item
end;
end;
procedure TEditForm.SaveFlameStateClick(Sender: TObject); // AV
{ Saves current flame into opened file and adds it to list view }
var
n: word;
FItem: TListItem;
Ftitle: string;
saved: boolean;
begin
n := 0; //
for FItem in MainForm.ListView1.Items do
if pos(MainCp.name, FItem.Caption) = 1 then inc(n);
if (n = 0) then
Ftitle := MainCp.name // current flame is not in the list
else begin
Ftitle := MainCp.name + ' (' + IntToStr(n) + ')';
Fitem := MainForm.ListView1.FindCaption(0, FTitle, false, true, false);
if FItem <> nil then // we already have a flame with the same name
Ftitle := MainCp.name + FormatDateTime(' (MM-dd-yyyy hh-mm-ss)', Now);
end;
if (OpenFileType = ftXML) then
saved := MainForm.SaveXMLFlame(MainCp, Ftitle, OpenFile)
else
saved := MainForm.SaveFlame(MainCp, Ftitle, OpenFile);
if saved then
MainForm.AddFlameToList(Ftitle); // show the new item
end;
// -----------------------------------------------------------------------------
procedure TEditForm.btnXcoefsClick(Sender: TObject);
begin
with cp.xform[SelectedTriangle] do
begin
if (c[0][0] = 1) and (c[0][1] = 0) then exit;
MainForm.UpdateUndo;
c[0][0] := 1;
c[0][1] := 0;
end;
cp.TrianglesFromCP(MainTriangles);
UpdateFlame(True);
end;
procedure TEditForm.btnYcoefsClick(Sender: TObject);
begin
if (cp.xform[SelectedTriangle].c[1][0] = 0) and
(cp.xform[SelectedTriangle].c[1][1] = 1) then exit;
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].c[1][0] := 0;
cp.xform[SelectedTriangle].c[1][1] := 1;
cp.TrianglesFromCP(MainTriangles);
UpdateFlame(True);
end;
procedure TEditForm.btnOcoefsClick(Sender: TObject);
begin
if (sender = mnuResetTrgPosition) and cp.xform[SelectedTriangle].postXswap then
begin
btnOpostClick(Sender);
exit;
end;
if (cp.xform[SelectedTriangle].c[2][0] = 0) and
(cp.xform[SelectedTriangle].c[2][1] = 0) then exit;
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].c[2][0] := 0;
cp.xform[SelectedTriangle].c[2][1] := 0;
cp.TrianglesFromCP(MainTriangles);
UpdateFlame(True);
end;
procedure TEditForm.btnCoefsModeClick(Sender: TObject);
begin
ShowSelectedInfo;
end;
procedure TEditForm.tbVarPreviewClick(Sender: TObject);
begin
showVarPreview := not showVarPreview;
tbVarPreview.Down := showVarPreview;
TriangleView.Invalidate;
end;
procedure TEditForm.trkVarPreviewRangeChange(Sender: TObject);
begin
trkVarPreviewRange.Hint := Format(TextByKey('editor-tab-color-previewrange') + ' %d', [trkVarPreviewRange.position]);
TriangleView.Invalidate;
end;
procedure TEditForm.trkVarPreviewDensityChange(Sender: TObject);
begin
trkVarPreviewDensity.Hint := Format(TextByKey('editor-tab-color-previewdensity') + ' %d', [trkVarPreviewDensity.position]);
TriangleView.Invalidate;
end;
procedure TEditForm.trkVarPreviewDepthChange(Sender: TObject);
begin
trkVarPreviewDepth.Hint := Format(TextByKey('editor-tab-color-previewdepth') + ' %d', [trkVarPreviewDepth.position]);
TriangleView.Invalidate;
end;
procedure TEditForm.btnXpostClick(Sender: TObject);
begin
with cp.xform[SelectedTriangle] do
begin
if (p[0][0] = 1) and (p[0][1] = 0) then exit;
MainForm.UpdateUndo;
p[0][0] := 1;
p[0][1] := 0;
end;
cp.TrianglesFromCP(MainTriangles);
UpdateFlame(True);
end;
procedure TEditForm.btnYpostClick(Sender: TObject);
begin
if (cp.xform[SelectedTriangle].p[1][0] = 0) and
(cp.xform[SelectedTriangle].p[1][1] = 1) then exit;
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].p[1][0] := 0;
cp.xform[SelectedTriangle].p[1][1] := 1;
cp.TrianglesFromCP(MainTriangles);
UpdateFlame(True);
end;
procedure TEditForm.btnOpostClick(Sender: TObject);
begin
if (cp.xform[SelectedTriangle].p[2][0] = 0) and
(cp.xform[SelectedTriangle].p[2][1] = 0) then exit;
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].p[2][0] := 0;
cp.xform[SelectedTriangle].p[2][1] := 0;
cp.TrianglesFromCP(MainTriangles);
UpdateFlame(True);
end;
// --Z-- copying functions is dumb... I am so lazy :-(
procedure TEditForm.PostCoefKeypress(Sender: TObject; var Key: Char);
begin
if key <> #13 then exit;
key := #0;
PostCoefValidate(Sender);
end;
procedure TEditForm.PostCoefValidate(Sender: TObject);
var
NewVal: double;
x, y, r, a: double; // dumb... must optimize
begin
try
NewVal := Round6(StrToFloat(TEdit(Sender).Text));
except on Exception do
begin
ShowSelectedInfo;
exit;
end;
end;
MainForm.UpdateUndo; // TODO - prevent unnecessary UpdateUndo...
with cp.xform[SelectedTriangle] do
begin
if btnCoefsRect.Down = true then
begin
if Sender = txtPost00 then p[0][0] := NewVal
else if Sender = txtPost01 then p[0][1] := -NewVal
else if Sender = txtPost10 then p[1][0] := -NewVal
else if Sender = txtPost11 then p[1][1] := NewVal
else if Sender = txtPost20 then p[2][0] := NewVal
else if Sender = txtPost21 then p[2][1] := -NewVal;
end
else begin
if (Sender = txtPost00) or (Sender = txtPost01) then begin
x := p[0][0];
y := -p[0][1];
end else
if (Sender = txtPost10) or (Sender = txtPost11) then begin
x := -p[1][0];
y := p[1][1];
end else
begin
x := p[2][0];
y := -p[2][1];
end;
r := Hypot(x, y);
a := arctan2(y, x);
if (Sender = txtPost00) or (Sender = txtPost10) or (Sender = txtPost20) then
r := NewVal
else
a := NewVal*PI/180;
x := r * cos(a);
y := r * sin(a);
if (Sender = txtPost00) or (Sender = txtPost01) then begin
p[0][0] := x;
p[0][1] := -y;
end else
if (Sender = txtPost10) or (Sender = txtPost11) then begin
p[1][0] := -x;
p[1][1] := y;
end else
begin
p[2][0] := x;
p[2][1] := -y;
end;
end;
end;
cp.TrianglesFromCP(MainTriangles);
//if tbAutoWeights.Down then cp.CalculateWeights;
ShowSelectedInfo;
UpdateFlame(true);
self.LastFocus := TEdit(sender);
end;
procedure TEditForm.btnResetCoefsClick(Sender: TObject);
begin
with cp.xform[SelectedTriangle] do
begin
if (c[0,0]<>1) or (c[0,1]<>0) or(c[1,0]<>0) or (c[1,1]<>1) or (c[2,0]<>0) or (c[2,1]<>0) then
begin
MainForm.UpdateUndo;
c[0, 0] := 1;
c[0, 1] := 0;
c[1, 0] := 0;
c[1, 1] := 1;
c[2, 0] := 0;
c[2, 1] := 0;
ShowSelectedInfo;
cp.TrianglesFromCP(MainTriangles);
if tbAutoWeights.Down then cp.CalculateWeights; // AV
UpdateFlame(True);
end;
end;
end;
procedure TEditForm.btnResetFlipClick(Sender: TObject);
begin
FlipPoint.x := 0;
FlipPoint.y := 0;
editFlipX.Text := '0';
editFlipY.Text := '0';
CalcFlip;
TriangleView.Invalidate;
end;
procedure TEditForm.btnResetPostCoefsClick(Sender: TObject);
begin
with cp.xform[SelectedTriangle] do
begin
if (p[0,0]<>1) or (p[0,1]<>0) or(p[1,0]<>0) or (p[1,1]<>1) or (p[2,0]<>0) or (p[2,1]<>0) then
begin
p[0, 0] := 1;
p[0, 1] := 0;
p[1, 0] := 0;
p[1, 1] := 1;
p[2, 0] := 0;
p[2, 1] := 0;
ShowSelectedInfo;
cp.TrianglesFromCP(MainTriangles);
UpdateFlame(True);
end;
end;
end;
procedure TEditForm.btnPivotModeClick(Sender: TObject);
begin
if PivotMode <> pivotLocal then
// with MainTriangles[SelectedTriangle] do
PivotMode := pivotLocal
else
// with MainTriangles[SelectedTriangle] do
PivotMode := pivotWorld;
TriangleView.Invalidate;
ShowSelectedInfo;
end;
procedure TEditForm.PivotValidate(Sender: TObject);
var
v: double;
begin
try
v := Round6(StrToFloat(TEdit(Sender).Text));
except on Exception do
begin
ShowSelectedInfo;
exit;
end;
end;
if Sender = editPivotX then
if v <> Round6(GetPivot.x) then begin
if PivotMode = pivotLocal then LocalPivot.x := v
else WorldPivot.x := v;
end
else exit
else
if v <> Round6(GetPivot.y) then begin
if PivotMode = pivotLocal then LocalPivot.y := v
else WorldPivot.y := v;
end
else exit;
TriangleView.Invalidate;
ShowSelectedInfo;
self.LastFocus := TEdit(sender);
end;
procedure TEditForm.PivotKeyPress(Sender: TObject; var Key: Char);
begin
if key <> #13 then exit;
key := #0;
PivotValidate(Sender);
end;
procedure TEditForm.btnResetPivotClick(Sender: TObject);
begin
if editMode = modePick then begin
editMode := oldMode;
oldMode := modeNone;
// hack: to generate MouseMove event
GetCursorPos(MousePos);
SetCursorPos(MousePos.x, MousePos.y);
//
end;
if PivotMode = pivotLocal then
begin
LocalPivot.x := 0;
LocalPivot.y := 0;
end
else begin
WorldPivot.x := 0;
WorldPivot.y := 0;
end;
TriangleView.Invalidate;
ShowSelectedInfo;
end;
procedure TEditForm.btnPickPivotClick(Sender: TObject);
begin
if editMode = modePick then begin
editMode := oldMode;
oldMode := modeNone;
TriangleView.Invalidate;
// hack: to generate MouseMove event
GetCursorPos(MousePos);
SetCursorPos(MousePos.x, MousePos.y);
//
exit;
end;
if oldMode <> modeNone then exit;
oldMode := editMode;
editMode := modePick;
TriangleView.Invalidate;
btnPickPivot.Down := true;
end;
procedure TEditForm.VEVarsDrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
var
supports3D, supportsDC : boolean;
col : TColor;
frect : TRect;
i: integer;
begin
if (ARow = 0) then exit; // AV
i := GetVariationIndex(VEVars.Keys[ARow]); // AV
if (i > NRLOCVAR) and not (gdSelected in State) then
begin
if IsDarkTheme then // AV: dark UI design requies another colors
begin
if i > NumBuiltinVars then
col := MidColor
else begin
col := BrightColor;
if (CurrentStyle = 'Auric') then // make the text more visible
VEVars.Canvas.Font.Color := WinColor
end;
end
else begin // classic variant
if i > NumBuiltinVars then
col := $e0ffff // orange
else
col := $ffe0e0; // blue
end;
VEVars.canvas.brush.Color := col;
VEVars.canvas.fillRect(Rect);
VEVars.canvas.TextOut(Rect.Left+2, Rect.Top+2, VEVars.Cells[ACol,ARow]);
end
else col := VEVars.canvas.brush.color;
if (Acol = 0) and (Arow > 0) then
begin
VEVars.Canvas.Font.Name := 'Arial';
VEVars.Canvas.Font.Size := 5;
supports3D := VarSupports3D(i); // i <-- (Arow - 1)
supportsDC := VarSupportsDC(i); // AV: separate methods
if (supports3D or supportsDC) then // AV: optimized calculations
begin
frect.Left := Rect.Right - 12;
frect.Right := Rect.Right;
frect.Top := Rect.Top;
frect.Bottom := Rect.Bottom;
VEVars.canvas.brush.Color := col;
VEVars.canvas.fillRect(frect);
if (supports3D) then begin
VEVars.Canvas.Font.Color := $a00000;
VEVars.Canvas.TextOut(frect.Left, frect.Top + 2, '3D');
end;
if (supportsDC) then begin
VEVars.Canvas.Font.Color := $0000a0;
VEVars.Canvas.TextOut(frect.Left, frect.Top + 9, 'DC');
end;
end;
end;
end;
procedure TEditForm.tbEnableFinalXformClick(Sender: TObject);
begin
MainForm.UpdateUndo;
EnableFinalXform := tbEnableFinalXform.Down;
if (cp.HasFinalXForm = false) then
begin
if (EnableFinalXform = true) then
begin
cbTransforms.Items.Add(TextByKey('editor-common-finalxformlistitem'));
SelectedTriangle := Transforms;
if (mouseOverTriangle > LastTriangle) then mouseOverTriangle := -1;
end
else begin
if cbTransforms.Items.Count = Transforms+1 then
cbTransforms.Items.Delete(Transforms);
if SelectedTriangle >= Transforms then SelectedTriangle := Transforms-1;
end;
end;
cp.finalXformEnabled := EnableFinalXform;
UpdateFlame(True);
TriangleView.Invalidate;
UpdateSyncTriangles; // AV
end;
procedure TEditForm.DragPanelMouseDown(Sender: TObject;
Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var dont :boolean;
begin
if Button <> mbLeft then exit;
// -X- why? its impossible!
assert(pnlDragMode = false); //?
if pnlDragMode = true then exit;
dont := false;
if (Sender = pnlWeight) then
if SelectedTriangle < Transforms then
pnlDragValue := cp.xform[SelectedTriangle].density
else exit
else if (Sender = pnlSymmetry) then
pnlDragValue := cp.xform[SelectedTriangle].symmetry
else if (Sender = pnlXformColor) then
pnlDragValue := cp.xform[SelectedTriangle].color
else if (Sender = pnlOpacity) then begin
if (txtOpacity.Enabled) then begin
pnlDragValue := cp.xform[SelectedTriangle].transOpacity;
end else dont := true;
end else if (Sender = pnlDC) then begin
if (txtDC.Enabled) then begin
pnlDragValue := cp.xform[SelectedTriangle].pluginColor;
end else dont := true;
end else assert(false);
if (not dont) then begin
pnlDragMode := true;
pnlDragPos := 0;
pnlDragOld := x;
varMM := false;
//SetCaptureControl(TControl(Sender));
Screen.Cursor := crHSplit;
//GetCursorPos(mousepos); // hmmm
mousePos := (Sender as TControl).ClientToScreen(Point(x, y));
HasChanged := false;
end;
end;
procedure TEditForm.DragPanelMouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
var
v: double;
pEdit: ^TEdit;
begin
if varMM then // hack: to skip MouseMove event
begin
varMM:=false;
end
else
if pnlDragMode and (x <> pnlDragOld) then
begin
Inc(pnlDragPos, x - pnlDragOld);
if GetKeyState(VK_MENU) < 0 then v := 100000
else if GetKeyState(VK_CONTROL) < 0 then v := 10000
else if GetKeyState(VK_SHIFT) < 0 then v := 100
else v := 1000;
v := Round6(pnlDragValue + pnlDragPos / v);
SetCursorPos(MousePos.x, MousePos.y); // hmmm
varMM:=true;
if (Sender = pnlWeight) then
begin
if v <= 0.000001 then v := 0.000001
else if v > MAX_WEIGHT then v := MAX_WEIGHT;
cp.xform[SelectedTriangle].density := v;
pEdit := @txtP;
end
else if (Sender = pnlSymmetry) then
begin
if v < -1 then v := -1
else if v > 1 then v := 1;
cp.xform[SelectedTriangle].symmetry := v;
pEdit := @txtSymmetry;
end
else if (Sender = pnlOpacity) then
begin
if (txtOpacity.Enabled) then begin
if v < 0 then v := 0
else if v > 1 then v := 1;
cp.xform[SelectedTriangle].transOpacity := v;
pEdit := @txtOpacity;
end else exit;
end
else if (Sender = pnlDC) then
begin
if (txtDC.Enabled) then begin
if v < 0 then v := 0
else if v > 1 then v := 1;
cp.xform[SelectedTriangle].pluginColor := v;
pEdit := @txtDC;
end else exit;
end
else if (Sender = pnlXformColor) then
begin
if v < 0 then v := 0
else if v > 1 then v := 1;
cp.xform[SelectedTriangle].color := v;
pnlXFormColor.Color := ColorValToColor(cp.cmap, v);
shColor.Brush.Color := pnlXformColor.Color;
updating := true;
scrlXformColor.Position := round(v*1000);
pEdit := @txtXformColor;
updating := false;
end
else begin
assert(false);
exit;
end;
pEdit^.Text := FloatToStr(v);
pEdit.Refresh;
HasChanged := True;
DrawPreview;
end;
end;
procedure TEditForm.DragPanelMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
if Button <> mbLeft then exit;
if pnlDragMode then
begin
//SetCaptureControl(nil);
pnlDragMode := false;
Screen.Cursor := crDefault;
if HasChanged then
begin
MainForm.UpdateUndo;
UpdateFlame(true);
HasChanged := False;
if (Sender = pnlWeight) and ChaosForm.Visible then // AV
ChaosForm.WeightVector.Invalidate;
end;
end;
end;
procedure TEditForm.DragPanelDblClick(Sender: TObject);
var
pValue: ^double;
pEdit: ^TEdit;
begin
if (Sender = pnlWeight) then
begin
if SelectedTriangle >= Transforms then exit; // hmm
pValue := @cp.xform[SelectedTriangle].density;
if pValue^ = 0.5 then exit;
pValue^ := 0.5;
pEdit := @txtP;
if ChaosForm.Visible then // AV
ChaosForm.WeightVector.Invalidate;
end
else if (Sender = pnlSymmetry) then
begin
pValue := @cp.xform[SelectedTriangle].symmetry;
if SelectedTriangle = Transforms then begin
if pValue^ = 1 then exit;
pValue^ := 1;
end
else begin
if pValue^ = 0 then exit;
pValue^ := 0;
end;
pEdit := @txtSymmetry;
end
else if (Sender = pnlXformColor) then
begin
pValue := @cp.xform[SelectedTriangle].color;
if pValue^ = 0 then exit;
pValue^ := 0;
pEdit := @txtXformColor;
end
else if (Sender = pnlOpacity) then
begin
if SelectedTriangle >= Transforms then exit; // hmm
pValue := @cp.xform[SelectedTriangle].transOpacity;
if pValue^ = 1.0 then begin
pValue^ := 0.0;
end else begin
pValue^ := 1.0;
end;
pEdit := @txtOpacity;
end
else if (Sender = pnlDC) then
begin
if SelectedTriangle >= Transforms then exit; // hmm
pValue := @cp.xform[SelectedTriangle].pluginColor;
if pValue^ = 1.0 then begin
pValue^ := 0.0;
end else begin
pValue^ := 1.0;
end;
pEdit := @txtDC;
end
else begin
assert(false);
exit;
end;
MainForm.UpdateUndo;
pEdit^.Text := FloatToStr(pValue^);
UpdateFlame(true);
end;
procedure TEditForm.mnuResetTrgRotationClick(Sender: TObject);
var
dx, dy: double;
ax, ay, da: integer;
nx0, ny0, nx2, ny2: double;
begin
with MainTriangles[SelectedTriangle] do
begin
// xx := x[0] - x[1];
// xy := y[0] - y[1];
// yx := x[2] - x[1];
// yy := y[2] - y[1];
ax := round( arctan2(xy, xx) / (pi/2) );
ay := round( arctan2(yy, yx) / (pi/2) );
dx := Hypot(xx, xy);
dy := Hypot(yx, yy);
if xx*yy - yx*xy >= 0 then da := 1 else da := -1;
if ax = ay then ay := ay + da
else if abs(ax-ay) = 2 then ay := ay - da;
nx0 := x[1] + dx*cos(ax*pi/2);
ny0 := y[1] + dx*sin(ax*pi/2);
nx2 := x[1] + dy*cos(ay*pi/2);
ny2 := y[1] + dy*sin(ay*pi/2);
if (x[0] = nx0) and (y[0] = ny0) and (x[2] = nx2) and (y[2] = ny2) then exit;
MainForm.UpdateUndo;
x[0] := nx0;
y[0] := ny0;
x[2] := nx2;
y[2] := ny2;
UpdateFlame(True);
end;
end;
procedure TEditForm.mnuResetTrgScaleClick(Sender: TObject);
var
dx, dy: double;
nx0, ny0, nx2, ny2: double;
begin
with MainTriangles[SelectedTriangle] do
begin
// xx := x[0] - x[1];
// xy := y[0] - y[1];
// yx := x[2] - x[1];
// yy := y[2] - y[1];
dx := Hypot(xx, xy);
dy := Hypot(yx, yy);
if dx <> 0 then begin
nx0 := x[1] + (x[0] - x[1])/dx;
ny0 := y[1] + (y[0] - y[1])/dx;
end
else begin
nx0 := x[1] + 1;
ny0 := y[1];
end;
if dx <> 0 then begin
nx2 := x[1] + (x[2] - x[1])/dy;
ny2 := y[1] + (y[2] - y[1])/dy;
end
else begin
nx2 := x[1];
ny2 := y[1] + 1;
end;
if (x[0] = nx0) and (y[0] = ny0) and (x[2] = nx2) and (y[2] = ny2) then exit;
MainForm.UpdateUndo;
x[0] := nx0;
y[0] := ny0;
x[2] := nx2;
y[2] := ny2;
UpdateFlame(True);
end;
end;
procedure TEditForm.RandomizeMatrixClick(Sender: TObject);
var i, j: integer;
begin
MainForm.UpdateUndo;
if Sender = RandomizeMatrix then
for i := 0 to Transforms-1 do
for j := 0 to Transforms-1 do
cp.xform[i].modWeights[j] := Round6(random)
else begin
if mnuChaosViewTo.Checked then
for j := 0 to Transforms-1 do
cp.xform[SelectedTriangle].modWeights[j] := Round6(random)
else for j := 0 to Transforms-1 do
cp.xform[j].modWeights[SelectedTriangle] := Round6(random);
end;
UpdateFlame(True);
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
procedure TEditForm.ResetAxisRotation(n: integer);
var
dx, dy, d: double;
a: integer;
nx, ny: double;
begin
with MainTriangles[SelectedTriangle] do
begin
if n = 1 then
begin
d := Hypot(x[1], y[1]);
if d = 0 then exit;
a := round( arctan2(y[1], x[1]) / (pi/2) );
nx := d*cos(a*pi/2);
ny := d*sin(a*pi/2);
if (x[1] = nx) and (y[1] = ny) then exit;
MainForm.UpdateUndo;
x[1] := nx;
y[1] := ny;
x[0] := x[1] + xx;
y[0] := y[1] + xy;
x[2] := x[1] + yx;
y[2] := y[1] + yy;
UpdateFlame(True);
end
else begin
dx := x[n] - x[1];
dy := y[n] - y[1];
a := round( arctan2(dy, dx) / (pi/2) );
d := Hypot(dx, dy);
nx := x[1] + d*cos(a*pi/2);
ny := y[1] + d*sin(a*pi/2);
if (x[n] = nx) and (y[n] = ny) then exit;
MainForm.UpdateUndo;
x[n] := nx;
y[n] := ny;
UpdateFlame(True);
end;
end;
end;
procedure TEditForm.ResetAxisScale(n: integer);
var
dx, dy, d: double;
nx, ny: double;
begin
with MainTriangles[SelectedTriangle] do
begin
if n = 1 then
begin
d := Hypot(x[1], y[1]);
if d = 0 then exit;
nx := x[1]/d;
ny := y[1]/d;
if (x[1] = nx) and (y[1] = ny) then exit;
MainForm.UpdateUndo;
x[1] := nx;
y[1] := ny;
x[0] := x[1] + xx;
y[0] := y[1] + xy;
x[2] := x[1] + yx;
y[2] := y[1] + yy;
UpdateFlame(True);
end
else begin
dx := x[n] - x[1];
dy := y[n] - y[1];
d := Hypot(dx, dy);
if d <> 0 then begin
nx := x[1] + dx / d;
ny := y[1] + dy / d;
end
else begin
nx := x[1] + ifthen(n=0, 1, 0);
ny := y[1] + ifthen(n=2, 1, 0);
end;
if (x[n] = nx) and (y[n] = ny) then exit;
MainForm.UpdateUndo;
x[n] := nx;
y[n] := ny;
UpdateFlame(True);
end;
end;
end;
procedure TEditForm.tbPostXswapClick(Sender: TObject);
begin
cp.GetFromTriangles(MainTriangles, cp.NumXForms);
with cp.xform[SelectedTriangle] do begin
{ // AV: it doesn't work then user press hotkey T...
if (sender = tbPostXswap) then tb2PostXswap.down := tbPostXswap.Down;
if (sender = tb2PostXswap) then tbPostXswap.Down := tb2PostXSwap.Down;
postXswap := TToolButton(sender).Down; }
if (sender = tbPostXswap) or (sender = tb2PostXswap) then
postXswap := TToolButton(sender).Down
else
postXswap := not postXswap;
tbPostXswap.Down := postXswap;
tb2PostXswap.Down := postXswap;
ShowSelectedInfo;
end;
cp.TrianglesFromCP(MainTriangles);
TriangleView.Refresh;
end;
procedure TEditForm.btnCopyTriangleClick(Sender: TObject);
begin
MemTriangle := MainTriangles[SelectedTriangle];
tbPasteTriangle.Enabled := True;
PasteTriangleCoordinates.Enabled := True;
end;
procedure TEditForm.btnFlipClick(Sender: TObject);
var px, py, fx, fy: double;
begin
px := GetPivot.x;
py := GetPivot.y;
if (PivotMode = pivotLocal) then
with MainTriangles[SelectedTriangle] do begin
fx := x[1] + (x[0] - x[1])* FlipPoint.x + (x[2] - x[1])* FlipPoint.y;
fy := y[1] + (y[0] - y[1])* FlipPoint.x + (y[2] - y[1])* FlipPoint.y;
end
else begin
fx := FlipPoint.x;
fy := FlipPoint.y;
end;
if (px = fx) and (py = fy) then exit;
MainForm.UpdateUndo;
MainTriangles[SelectedTriangle] :=
FlipTriangleLine(MainTriangles[SelectedTriangle], px, py, fx, fy);
UpdateFlame(true);
end;
procedure TEditForm.btnFullChaosClick(Sender: TObject);
begin
ChaosForm.Show;
end;
procedure TEditForm.btnPasteTriangleClick(Sender: TObject);
begin
if (MainTriangles[SelectedTriangle].x[0] <> MemTriangle.x[0]) or
(MainTriangles[SelectedTriangle].x[1] <> MemTriangle.x[1]) or
(MainTriangles[SelectedTriangle].x[2] <> MemTriangle.x[2]) or
(MainTriangles[SelectedTriangle].y[0] <> MemTriangle.y[0]) or
(MainTriangles[SelectedTriangle].y[1] <> MemTriangle.y[1]) or
(MainTriangles[SelectedTriangle].y[2] <> MemTriangle.y[2]) then
begin
MainForm.UpdateUndo;
MainTriangles[SelectedTriangle] := MemTriangle;
UpdateFlame(True);
end;
end;
procedure TEditForm.chkAutoZscaleClick(Sender: TObject);
begin
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].autoZscale := chkAutoZscale.Checked;
UpdateFlame(True);
end;
// --------------------------------------------------------------- Chaos Editor
procedure TEditForm.ValidateChaos;
var
i: integer;
NewVal, OldVal: double;
begin
i := vleChaos.Row - 1;
if mnuChaosViewTo.Checked then
OldVal := Round6(cp.xform[SelectedTriangle].modWeights[i])
else
OldVal := Round6(cp.xform[i].modWeights[SelectedTriangle]);
try
NewVal := Round6(StrToFloat(vleChaos.Cells[1, i+1]));
except
vleChaos.Cells[1, i+1] := Format('%.6g', [OldVal]);
exit;
end;
if (NewVal <> OldVal) then
begin
MainForm.UpdateUndo;
if mnuChaosViewTo.Checked then
cp.xform[SelectedTriangle].modWeights[i] := NewVal
else
cp.xform[i].modWeights[SelectedTriangle] := NewVal;
vleChaos.Cells[1, i+1] := Format('%.6g', [NewVal]);
ShowSelectedInfo;
UpdateFlame(True);
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
end;
procedure TEditForm.vleChaosExit(Sender: TObject);
begin
ValidateChaos;
end;
procedure TEditForm.vleChaosKeyPress(Sender: TObject; var Key: Char);
begin
if (Key = '-') then Key:= #0; // AV
if key = #13 then
begin
key := #0;
ValidateChaos;
end;
end;
procedure TEditForm.vleChaosValidate(Sender: TObject; ACol, ARow: Integer;
const KeyName, KeyValue: String);
begin
ValidateChaos;
end;
procedure TEditForm.VleChaosDrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
var
h,ax,ay,bx,by: integer;
trgColor: TColor;
begin
if (ACol > 0) or (ARow = 0) then exit;
trgColor := GetTriangleColor(ARow - 1);
with vleChaos.Canvas do begin
h := Rect.Bottom - Rect.Top - 2;
// TextOut(Rect.Left+h+2, Rect.Top+1, vleChaos.Cells[ACol, ARow]);
ax:=Rect.Right-3;
ay:=Rect.Top+2;
bx:=Rect.Right-h;
by:=Rect.Bottom-3;
pen.Color := clBlack;
Polyline([Point(ax+1, ay-2), Point(ax+1, by+1), Point(bx-2, by+1), Point(ax+1, ay-2)]);
pen.Color := trgColor;
brush.Color := pen.Color shr 1 and $7f7f7f;
Polygon([Point(ax, ay), Point(ax, by), Point(bx, by)]);
end;
end;
procedure TEditForm.mnuChaosViewToClick(Sender: TObject);
var
i: integer;
begin
mnuChaosViewTo.Checked := true;
for i := 1 to vleChaos.RowCount-1 do begin
vleChaos.Cells[0, i] := Format(TextByKey('editor-common-toprefix'), [i]);
vleChaos.Cells[1, i] := FloatToStr(cp.xform[SelectedTriangle].modWeights[i-1]);
end;
//ShowSelectedInfo;
end;
procedure TEditForm.mnuChaosViewFromClick(Sender: TObject);
var
i: integer;
begin
mnuChaosViewFrom.Checked := true;
for i := 1 to vleChaos.RowCount-1 do begin
vleChaos.Cells[0, i] := Format(TextByKey('editor-common-fromprefix'), [i]);
vleChaos.Cells[1, i] := FloatToStr(cp.xform[i-1].modWeights[SelectedTriangle]);
end;
//ShowSelectedInfo;
end;
procedure TEditForm.mnuCopyChaosClick(Sender: TObject);
var i: smallint;
begin
SetLength(MemChaos, NXFORMS);
if mnuChaosViewTo.Checked then
for i := 0 to high(MemChaos) do
MemChaos[i] := cp.xform[SelectedTriangle].modWeights[i]
else
for i := 0 to high(MemChaos) do
MemChaos[i] := cp.xform[i].modWeights[SelectedTriangle];
mnuPasteChaos.Enabled := True;
PasteChaos.Enabled := True;
end;
procedure TEditForm.mnuPasteChaosClick(Sender: TObject);
var i, t: smallint;
begin
MainForm.UpdateUndo;
if mnuChaosViewTo.Checked then
for t in SyncTriangles do
for i := 0 to high(MemChaos) do
cp.xform[t].modWeights[i] := MemChaos[i]
else
for t in SyncTriangles do
for i := 0 to high(MemChaos) do
cp.xform[i].modWeights[t] := MemChaos[i];
UpdateFlame(true);
if ChaosForm.Visible then ChaosForm.ChaosMatrix.Invalidate;
end;
(*
procedure TEditForm.chkPlotModeClick(Sender: TObject);
var newMode: boolean;
begin
if (SelectedTriangle < Transforms) then
begin
newMode := chkXformInvisible.Checked;
if cp.xform[SelectedTriangle].noPlot <> newMode then begin
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].noPlot := newMode;
UpdateFlame(true);
end;
end;
end;
*)
procedure TEditForm.mnuChangeGridClick(Sender: TObject); // AV
begin
if not TMenuItem(Sender).Checked then
begin
TMenuItem(Sender).Checked := True;
try
if Sender = RectGrid then // AV: classic arrows
begin
btTrgMoveUp.Glyph := nil;
IconsAV.GetBitmap(0, btTrgMoveUp.Glyph);
btTrgMoveDown.Glyph := nil;
IconsAV.GetBitmap(1, btTrgMoveDown.Glyph);
end else begin // AV: slope arrows
btTrgMoveUp.Glyph := nil;
IconsAV.GetBitmap(2, btTrgMoveUp.Glyph);
btTrgMoveDown.Glyph := nil;
IconsAV.GetBitmap(3, btTrgMoveDown.Glyph);
end;
finally
end;
end;
end;
procedure TEditForm.mnuChaosClearAllClick(Sender: TObject);
var
i: integer;
noEdit: boolean;
begin
noEdit := true;
for i := 1 to cp.NumXForms do
if mnuChaosViewTo.Checked then begin
if cp.xform[SelectedTriangle].modWeights[i-1] <> 0 then begin
noEdit := false;
break;
end;
end
else begin
if cp.xform[i-1].modWeights[SelectedTriangle] <> 0 then begin
noEdit := false;
break;
end;
end;
if noEdit then exit;
Mainform.UpdateUndo;
for i := 1 to cp.NumXForms do
if mnuChaosViewTo.Checked then
cp.xform[SelectedTriangle].modWeights[i-1] := 0
else
cp.xform[i-1].modWeights[SelectedTriangle] := 0;
UpdateFlame(true);
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
procedure TEditForm.mnuChaosSetAllClick(Sender: TObject);
var
i: integer;
noEdit: boolean;
begin
noEdit := true;
for i := 1 to cp.NumXForms do
if mnuChaosViewTo.Checked then begin
if cp.xform[SelectedTriangle].modWeights[i-1] <> 1 then begin
noEdit := false;
break;
end;
end
else begin
if cp.xform[i-1].modWeights[SelectedTriangle] <> 1 then begin
noEdit := false;
break;
end;
end;
if noEdit then exit;
Mainform.UpdateUndo;
for i := 1 to cp.NumXForms do
if mnuChaosViewTo.Checked then
cp.xform[SelectedTriangle].modWeights[i-1] := 1
else
cp.xform[i-1].modWeights[SelectedTriangle] := 1;
UpdateFlame(true);
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
procedure TEditForm.mnuLinkPostxformClick(Sender: TObject);
var
i, k: integer;
begin
if (Transforms < NXFORMS) and (SelectedTriangle <> Transforms) then
begin
MainForm.UpdateUndo;
MainTriangles[Transforms+1] := MainTriangles[Transforms];
cp.xform[Transforms+1].Assign(cp.xform[Transforms]);
MainTriangles[Transforms] := MainTriangles[-1];
cp.xform[Transforms].Clear;
if InheritWeights.Checked then
cp.xform[Transforms].density := cp.xform[SelectedTriangle].density
else cp.xform[Transforms].density := 0.5;
cp.xform[Transforms].SetVariation(0, 1);
for i := 0 to NXFORMS-1 do begin
if (i = Transforms) then continue;
cp.xform[Transforms].modWeights[i] := cp.xform[SelectedTriangle].modWeights[i];
cp.xform[SelectedTriangle].modWeights[i] := 0;
end;
for i := 0 to NXFORMS-1 do
cp.xform[i].modWeights[Transforms] := 0;
cp.xform[SelectedTriangle].modWeights[Transforms] := 1;
cp.xform[Transforms].symmetry := 1;
cp.xform[Transforms].transOpacity := cp.xform[SelectedTriangle].transOpacity;
cp.xform[SelectedTriangle].transOpacity := 0;
hasLinkX := True;
k := SelectedTriangle;
SelectedTriangle := Transforms;
cp.xform[SelectedTriangle].TransformName := 'Post-link for TX ' + IntToStr(k + 1);
Inc(Transforms);
UpdateXformsList;
UpdateFlame(True);
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
end;
procedure TEditForm.mnuLinkPreXformClick(Sender: TObject);
var
i, k: integer;
begin
if (Transforms < NXFORMS) and (SelectedTriangle <> Transforms) then
begin
MainForm.UpdateUndo;
MainTriangles[Transforms+1] := MainTriangles[Transforms];
cp.xform[Transforms+1].Assign(cp.xform[Transforms]);
MainTriangles[Transforms] := MainTriangles[-1];
cp.xform[Transforms].Clear;
if InheritWeights.Checked then
cp.xform[Transforms].density := cp.xform[SelectedTriangle].density
else cp.xform[Transforms].density := 0.5;
cp.xform[Transforms].SetVariation(0, 1);
for i := 0 to NXFORMS-1 do begin
if (i = Transforms) then continue;
cp.xform[i].modWeights[Transforms] := cp.xform[i].modWeights[SelectedTriangle];
cp.xform[i].modWeights[SelectedTriangle] := 0;
end;
for i := 0 to NXFORMS-1 do
cp.xform[Transforms].modWeights[i] := 0;
cp.xform[Transforms].modWeights[SelectedTriangle] := 1;
cp.xform[Transforms].symmetry := 1;
cp.xform[Transforms].transOpacity := 0;
hasLinkX := True;
k := SelectedTriangle;
SelectedTriangle := Transforms;
cp.xform[SelectedTriangle].TransformName := 'Pre-link for TX ' + IntToStr(k + 1);
Inc(Transforms);
UpdateXformsList;
UpdateFlame(True);
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
end;
procedure TEditForm.chkXformSoloClick(Sender: TObject);
begin
if chkXformSolo.Checked <> (cp.soloXform >=0) then begin
if chkXformSolo.Checked then begin
if (SelectedTriangle < Transforms) then begin
cp.soloXform := SelectedTriangle;
UpdateFlame(true);
end;
end
else begin
cp.soloXform := -1;
UpdateFlame(true);
end;
end;
end;
procedure TEditForm.mnuChaosRebuildClick(Sender: TObject);
begin
RebuildXaosLinks := not RebuildXaosLinks;
mnuChaosRebuild.Checked := RebuildXaosLinks;
end;
procedure TEditForm.chkCollapseVariationsClick(Sender: TObject);
var
i: integer;
s: string;
IsSupport: boolean;
begin
s := Trim(txtSearchBox.Text);
for i := 1 to VEVars.RowCount - 1 do
begin
if (Length(s) = 0) or ((Length(s) <= Length(VEVars.Cells[0, i])) and
(Pos(s, VEVars.Cells[0, i]) > 0)) then // AV: search text is not empty
begin
case cbCollapseVariations.ItemIndex of
0: VEVars.RowHeights[i] := VEVars.DefaultRowHeight; // all
1: if Assigned(cp) then
VEVars.RowHeights[i] := // active
IfThen((VEVars.Cells[1,i] = '0'), -1, VEVars.DefaultRowHeight)
else
VEVars.RowHeights[i] := -1;
2: VEVars.RowHeights[i] := // favourites
IfThen(FavouriteVariations[GetVariationIndex(VEVars.Cells[0,i])], // i-1
VEVars.DefaultRowHeight, -1);
3: // 3D
begin
IsSupport := VarSupports3D(GetVariationIndex(VEVars.Cells[0,i]));
VEVars.RowHeights[i] := IfThen(IsSupport, VEVars.DefaultRowHeight, -1);
end;
4: // DC
begin
IsSupport := VarSupportsDC(GetVariationIndex(VEVars.Cells[0,i]));
VEVars.RowHeights[i] := IfThen(IsSupport, VEVars.DefaultRowHeight, -1);
end;
end;
end
else
VEVars.RowHeights[i] := -1;
end;
{
s := Trim(txtSearchBox.Text);
for i:= 1 to VEVars.RowCount - 1 do
begin
if (Length(s) = 0) then
begin
if ((Assigned(cp)) and (VEVars.Cells[1,i]='0')) then
if chkCollapseVariations.Checked then
VEVars.RowHeights[i] := -1
else
VEVars.RowHeights[i] := VEVars.DefaultRowHeight
else
VEVars.RowHeights[i] := VEVars.DefaultRowHeight;
end
else begin
if (Length(s) > Length(VEVars.Cells[0, i])) then
VEVars.RowHeights[i] := -1
else if Pos(s, VEVars.Cells[0, i]) > 0 then
begin
if ((Assigned(cp)) and (VEVars.Cells[1,i]='0')) then
if chkCollapseVariations.Checked then
VEVars.RowHeights[i] := -1
else
VEVars.RowHeights[i] := VEVars.DefaultRowHeight
else
VEVars.RowHeights[i] := VEVars.DefaultRowHeight;
end
else
VEVars.RowHeights[i] := -1;
end;
end;
}
end;
procedure TEditForm.chkCollapseVariablesClick(Sender: TObject);
var
i, vari: integer;
begin
for i := 1 to vleVariables.RowCount - 1 do
begin
if chkCollapseVariables.Checked then
vleVariables.RowHeights[i] := vleVariables.DefaultRowHeight
else
begin
vari := GetVariationIndexFromVariableNameIndex(i-1);
if ( (vari = -1) or
((Assigned(cp)) and (cp.xform[SelectedTriangle].GetVariation(vari) = 0)) ) then
vleVariables.RowHeights[i] := -1
else
vleVariables.RowHeights[i] := vleVariables.DefaultRowHeight;
end;
end;
end;
procedure TEditForm.shColorMouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
DragPanelMouseDown(pnlXFormColor, Button, Shift, X, Y);
end;
procedure TEditForm.shColorMouseMove(Sender: TObject; Shift: TShiftState;
X, Y: Integer);
begin
DragPanelMouseMove(pnlXFormColor, Shift, X, Y);
end;
procedure TEditForm.shColorMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
begin
DragPanelMouseUp(pnlXFormColor, Button, Shift, X, Y);
end;
procedure TEditForm.bClearClick(Sender: TObject);
var
i:integer;
changed:boolean;
begin
changed := false;
for i := 0 to VEVars.RowCount - 1 do begin
if (cp.xform[SelectedTriangle].GetVariation(i) <> 0) then changed := true;
cp.xform[SelectedTriangle].SetVariation(i, 0);
end;
if changed then MainForm.UpdateUndo;
UpdateFlame(true);
end;
procedure TEditForm.ResetChaosClick(Sender: TObject);
var i, j: integer;
noEdit: boolean;
begin
noEdit := true;
for i := 0 to Transforms-1 do
begin
if not noEdit then break;
for j := 0 to Transforms-1 do
if cp.xform[i].modWeights[j] <> 1 then
begin
noEdit := false;
break;
end;
end;
if noEdit then exit;
MainForm.UpdateUndo;
for i := 0 to NXforms-1 do
for j := 0 to NXforms-1 do
cp.xform[i].modWeights[j] := 1;
UpdateFlame(True);
if ChaosForm.Visible then // AV
ChaosForm.ChaosMatrix.Invalidate;
end;
procedure TEditForm.mnuResetTrgFlipClick(Sender: TObject);
var
x0, y0, x1, y1, detT: double;
begin
with cp.xform[SelectedTriangle] do
if postXswap then
detT := det(p[0,0], p[1,0], p[0,1], p[1,1])
else detT := det(c[0,0], c[1,0], c[0,1], c[1,1]);
if (detT >= 0) then exit;
with MainTriangles[SelectedTriangle] do
begin
x0 := x[1];
y0 := y[1];
x1 := x[0] + x[2] - x0;
y1 := y[0] + y[2] - y0;
end;
MainForm.UpdateUndo;
MainTriangles[SelectedTriangle] :=
FlipTriangleLine(MainTriangles[SelectedTriangle], x0, y0, x1, y1);
UpdateFlame(true);
end;
procedure TEditForm.btResetparamsClick(Sender: TObject);
var
i: integer;
begin
for i:= 0 to GetNrVariableNames - 1 do begin
cp.xform[SelectedTriangle].ResetVariable(GetVariableNameAt(i));
end;
MainForm.UpdateUndo;
UpdateFlame(true);
end;
procedure TEditForm.btSwapCoefsClick(Sender: TObject);
var
i, j: byte;
t: double;
begin
MainForm.UpdateUndo;
with cp.xform[SelectedTriangle] do
for i := 0 to 2 do
for j := 0 to 1 do
begin
t := c[i,j];
c[i,j] := p[i,j];
p[i,j] := t;
end;
if not tbPostXSwap.Down then
cp.GetTriangle(MainTriangles[SelectedTriangle], SelectedTriangle)
else cp.GetPostTriangle(MainTriangles[SelectedTriangle], SelectedTriangle);
UpdateFlame(true);
end;
procedure TEditForm.ColorBarMouseUp(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
dx: double;
begin
// dx := Round(100 * X / ColorBar.Width) / 100; // <-- AV: it's not correct
dx := X / (ColorBarPicture.Width - 1); // AV: this gives the best results
txtXFormColor.Text := FloatToStrF(dx, ffFixed, 4, 3); // AV: default presision
txtXFormColorExit(nil);
end;
{
procedure TEditForm.btnLoadVVARClick(Sender: TObject);
var
fn:string;
i:integer;
begin
if OpenSaveFileDialog(EditForm, '.dll', 'Dynamic Link Libraries (*.dll)|*.dll', '.\Plugins', 'LoadPlugin...', fn, true, false, false, true) then begin
//if (fn <> '') then begin
LoadPlugin(fn);
VEVars.Strings.Clear;
vleVariables.Strings.Clear;
for i:= 0 to NRVAR - 1 do begin
VEVars.InsertRow(Varnames(i), '0', True);
end;
for i:= 0 to GetNrVariableNames - 1 do begin
vleVariables.InsertRow(GetVariableNameAt(i), '0', True);
end;
for i := 0 to Transforms - 1 do begin
cp.xform[i].InvokeAddRegVariations;
end;
end;
end;
end;
}
procedure TEditForm.txtNameKeyPress(Sender: TObject; var Key: Char);
begin
if SelectedTriangle >= Transforms then key := #0;
if key = #13 then
begin
{ Stop the beep }
Key := #0;
txtNameExit(sender);
end;
end;
procedure TEditForm.txtNameExit(Sender: TObject);
var
n:integer;
oldval,newval:string;
begin
oldval := cp.xform[SelectedTriangle].TransformName;
newval := txtName.Text;
if (oldval <> newval) then begin
MainForm.UpdateUndo;
cp.xform[SelectedTriangle].TransformName := newval;
n := SelectedTriangle + 1;
if (cp.xform[SelectedTriangle].TransformName <> '') then
cbTransforms.Items[SelectedTriangle] := IntToStr(n) + ' - ' + cp.xform[SelectedTriangle].TransformName
else
cbTransforms.Items[SelectedTriangle] := IntToStr(n);
//workaround..
if (SelectedTriangle >= Transforms) then
cbTransforms.Items[SelectedTriangle] := TextByKey('editor-common-finalxformlistitem');
cbTransforms.ItemIndex := SelectedTriangle;
UpdateFlame(True);
end;
end;
procedure TEditForm.TriangleOperationsClick(Sender: TObject);
begin
TMenuItem(Sender).Checked := True;
end;
procedure TEditForm.TrianglePanelResize(Sender: TObject);
begin
gbTrgOperations.Left := (TrianglePanel.CLientWidth - gbTrgOperations.Width) div 2;
gbCoordinates.Left := (TrianglePanel.CLientWidth - gbCoordinates.Width) div 2;
gbPivot.Left := (TrianglePanel.CLientWidth - gbPivot.Width) div 2;
gbFlip.Left := (TrianglePanel.CLientWidth - gbFlip.Width) div 2;
TriangleToolBar.Left := (TrianglePanel.CLientWidth - TriangleToolBar.Width) div 2;
end;
procedure TEditForm.ControlPanelResize(Sender: TObject);
begin
cbTransforms.ItemHeight := Panel1.Height - 6;
cbTransforms.Height := Panel1.Height;
PageControl.Top := Panel1.Height + Panel2.Height + pnlWeight.Height + 12;
PageControl.Height := ControlPanel.Height - PageControl.Top;
end;
procedure TEditForm.CopyTransformClick(Sender: TObject);
var
txt: string;
i, n: byte;
begin
MemCp.Clear;
MemCp.Name := 'Memorized XForm Parameters';
if (not UseTriangleSync) or (SelectedTriangle = Transforms) then
MemCp.xform[0].Assign(cp.xform[SelectedTriangle])
else begin // AV: copy all selected transforms
n := 0;
for i in SyncTriangles do
begin
MemCp.xform[n].Assign(cp.xform[i]);
inc(n);
end;
end;
txt := Trim(FlameToXML(MemCp));
Clipboard.SetTextBuf(PChar(txt));
PasteTransform.Enabled := True;
MainForm.mnuPaste.Enabled := False;
end;
procedure TEditForm.CopyVariationsClick(Sender: TObject);
begin
try
VEVars.Strings.SaveToFile(APPDATA + saved_variations);
VLEVariables.Strings.SaveToFile(APPDATA + saved_variables);
PasteVariations.Enabled := True;
except
// TODO
PasteVariations.Enabled := False;
end;
end;
procedure TEditForm.PasteTransformClick(Sender: TObject);
var
TempTriangles: TTriangles;
i, t: smallint;
begin
t := MemCp.NumXForms - 1;
if (t >= 0) and (Transforms + t < NXFORMS) then
begin
MainForm.UpdateUndo;
MemCp.TrianglesFromCP(TempTriangles);
for i := 0 to t do
begin
MainTriangles[Transforms+1] := MainTriangles[Transforms];
cp.xform[Transforms+1].Assign(cp.xform[Transforms]);
MainTriangles[Transforms] := TempTriangles[i];
cp.xform[Transforms].Assign(MemCp.xform[i]);
SelectedTriangle := Transforms;
Inc(Transforms);
end;
UpdateXformsList;
UpdateFlame(True);
end;
end;
procedure TEditForm.PasteVariationsClick(Sender: TObject);
var
i: integer;
v: double;
s: string;
begin
MainForm.UpdateUndo;
try
VEVars.Strings.LoadFromFile(APPDATA + saved_variations);
for i := 0 to NrVar-1 do
begin
s := VEVars.Strings.Names[i];
cp.xform[SelectedTriangle].SetVariation(GetVariationIndex(s),
StrToFloat(VEVars.Strings.Values[s]));
cp.xform[SelectedTriangle].ifs[i] := s;
end;
VLEVariables.Strings.LoadFromFile(APPDATA + saved_variables);
for i := 0 to GetNrVariableNames - 1 do
begin
v := StrToFloat(VLEVariables.Strings.ValueFromIndex[i]);
cp.xform[SelectedTriangle].SetVariable(VLEVariables.Strings.Names[i], v);
end;
UpdateFlame(true);
except
// restore defaults?
cp.xform[SelectedTriangle].SetVariation(0, 1);
cp.xform[SelectedTriangle].ifs[0] := 'linear';
VEVars.Strings.BeginUpdate;
VEVars.Strings[0] := 'linear=1';
for i := 1 to NrVar-1 do
begin
s := VarNames(i);
cp.xform[SelectedTriangle].SetVariation(i, 0);
cp.xform[SelectedTriangle].ifs[i] := s;
VEVars.Strings[i] := s + '=0';
end;
VEVars.Strings.EndUpdate;
VLEVariables.Strings.BeginUpdate;
for i := 0 to GetNrVariableNames - 1 do
begin
s := GetVariableNameAt(i);
cp.xform[SelectedTriangle].ResetVariable(s);
VLEVariables.Strings[i] := s + '=' + cp.xform[SelectedTriangle].GetVariableStr(s);
end;
VLEVariables.Strings.EndUpdate;
UpdateFlame(true);
end;
end;
procedure TEditForm.ScrollBox2Resize(Sender: TObject);
begin // AV: done
GroupBox1.Left := (ScrollBox2.ClientWidth - GroupBox1.Width) div 2;
GroupBox2.Left := (ScrollBox2.ClientWidth - GroupBox2.Width) div 2;
end;
procedure TEditForm.ScrollBox1Resize(Sender: TObject);
var sbw: integer; // AV: for speed
begin
sbw := (ScrollBox1.ClientWidth - GroupBox9.Width) div 2;
GroupBox7.Left := sbw;
GroupBox8.Left := sbw;
GroupBox9.Left := sbw;
chkAutoZscale.Left := sbw;
btSwapCoefs.Left := sbw;
btConjugate.Left := sbw + 116;
end;
procedure TEditForm.FlipPointKeyPress(Sender: TObject; var Key: Char);
begin
if key <> #13 then exit;
key := #0;
FlipPointValidate(Sender);
end;
procedure TEditForm.FlipPointValidate(Sender: TObject);
var
v: double;
begin
try
v := Round6(StrToFloat(TEdit(Sender).Text));
if Sender = editFlipX then
FlipPoint.x := v
else
FlipPoint.y := v;
except // restore old value
if Sender = editFlipX then v := FlipPoint.x
else v := FlipPoint.y;
end;
TEdit(Sender).Text := Format('%.6g',[v]);
TriangleView.Invalidate;
CalcFlip;
end;
procedure TEditForm.FormActivate(Sender: TObject);
begin
if EnableEditorPreview and PrevPnl.Visible then
begin
Splitter2.Height := 1;
Splitter2.Visible := false;
PrevPnl.Height := 1;
PrevPnl.Visible := false;
end
else if (not EnableEditorPreview) and (not PrevPnl.Visible) then
begin
Splitter2.Height := 8;
Splitter2.Visible := true;
PrevPnl.Height := 177;
PrevPnl.Visible := true;
end;
// AV: check if these parameters were changed in options
tbExtendedEdit.Down := ExtEditEnabled;
tbAxisLock.Down := TransformAxisLock;
mnuChaosRebuild.Checked := RebuildXaosLinks;
AdjustSyncTriangles; // AV
chkCollapseVariationsClick(nil);
end;
(* // AV: exactly the same as chkCollapseVariationsClick
procedure TEditForm.txtSearchBoxChange(Sender: TObject);
var
i: integer;
s: string;
begin
s := Trim(txtSearchBox.Text);
for i:= 1 to VEVars.RowCount - 1 do begin
if (Length(s) = 0) then begin
if ((Assigned(cp)) and (VEVars.Cells[1,i]='0')) then
if chkCollapseVariations.Checked then VEVars.RowHeights[i] := -1
else VEVars.RowHeights[i] := VEVars.DefaultRowHeight
else VEVars.RowHeights[i] := VEVars.DefaultRowHeight;
end else begin
if (Length(s) > Length(VEVars.Cells[0, i])) then
VEVars.RowHeights[i] := -1
else if Pos(s, VEVars.Cells[0, i]) > 0 then begin
if ((Assigned(cp)) and (VEVars.Cells[1,i]='0')) then
if chkCollapseVariations.Checked then VEVars.RowHeights[i] := -1
else VEVars.RowHeights[i] := VEVars.DefaultRowHeight
else VEVars.RowHeights[i] := VEVars.DefaultRowHeight;
end else VEVars.RowHeights[i] := -1;
end;
end;
end;
*)
procedure TEditForm.txtSearchBoxKeyPress(Sender: TObject; var Key: Char);
begin
// AV: exactly the same as chkCollapseVariationsClick
// txtSearchBoxChange(Sender);
chkCollapseVariationsClick(Sender); // AV
end;
procedure TEditForm.btnResetSearchClick(Sender: TObject);
begin
txtSearchBox.Text := '';
end;
procedure TEditForm.btnShowLineClick(Sender: TObject);
begin
ShowFlipLine := not ShowFlipLine;
if ShowFlipLine then btnShowLine.Caption := TextByKey('editor-tab-triangle-hideline')
else btnShowLine.Caption := TextByKey('editor-tab-triangle-showline');
TriangleView.Invalidate;
end;
procedure TEditForm.btnVarOrderClick(Sender: TObject);
var
i: integer;
begin
if (VarOrder.ShowModal = mrOK) then
if VarOrder.Changed then
begin
MainForm.UpdateUndo;
for i := 0 to NrVar - 1 do
cp.xform[SelectedTriangle].ifs[i] := VarOrder.VarListView.Items[i].Caption;
UpdateVariationList;
chkCollapseVariationsClick(Sender);
UpdateFlame(true);
end;
end;
procedure TEditForm.KeyInput(str:string);
var
Inp: TInput;
mapCh: UINT;
sym: byte;
i: Integer;
begin
Application.ProcessMessages;
for i := 1 to Length(Str) do
begin
{
Inp.Itype := INPUT_KEYBOARD;
Inp.ki.wVk := Ord(Str[i]);
Inp.ki.dwFlags := 0;
SendInput(1, Inp, SizeOf(Inp));
Inp.Itype := INPUT_KEYBOARD;
Inp.ki.wVk := Ord(Str[i]);
Inp.ki.dwFlags := KEYEVENTF_KEYUP;
SendInput(1, Inp, SizeOf(Inp));
}
// AV: hack - to "press" Enter when a numeric field is active
if Str[i] = #13 then
sym := VK_RETURN // for faster work
else
sym := VkKeyScan(Str[i]);
mapCh := MapVirtualKey(LOBYTE(sym), 0);
Inp.Itype := INPUT_KEYBOARD;
Inp.ki.dwFlags := KEYEVENTF_SCANCODE;
Inp.ki.wScan := mapCh;
SendInput(1, Inp, SizeOf(Inp));
Inp.Itype := INPUT_KEYBOARD;
Inp.ki.dwFlags := KEYEVENTF_KEYUP;
Inp.ki.wScan := mapCh;
SendInput(1, Inp, SizeOf(Inp));
end;
end;
end.