8145 lines
244 KiB
ObjectPascal
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.
|
|
|