{ 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.