{ 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 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 , Curves, ControlPoint, XForm, cmap, CustomDrawControl, ClipBrd, RenderingInterface, Translation, RenderThread, System.ImageList, Vcl.Samples.Spin; 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; GroupBox5: 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; GroupBox6: 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; Label4: TLabel; txtSearchBox: TEdit; ToolButton5: TToolButton; btnMathPopup: TToolButton; tbPreLink: TToolButton; btnFullChaos: TToolButton; btnResetSearch: TSpeedButton; GroupBox3: 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; Copytrianglecoordinates1: TMenuItem; Copytransform1: TMenuItem; Pastetrianglecoordinates1: TMenuItem; Pastetransform1: 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; GroupBox10: 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; 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 chkUseXFormColorClick(Sender: TObject); // procedure chkHelpersClick(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 ValidateValue(Sender: TObject); 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 chkPlotModeClick(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 btnLoadVVARClick(Sender: TObject); procedure txtNameKeyPress(Sender: TObject; var Key: Char); procedure txtNameExit(Sender: TObject); procedure InsertPi1Click(Sender: TObject); procedure Copytransform1Click(Sender: TObject); procedure Pastetransform1Click(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 btnInvisibleClick(Sender: TObject); // procedure btnSoloClick(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); // 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 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; VarsCache: array of double; // AV: now length is sets dynamically // hack: to prevent slow valuelist redraw // -JF- 64 wasn't big enough... buffer overrun 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 TriangleViewPaint(Sender: TObject); procedure AutoZoom; procedure KeyInput(str: string); procedure CalcFlip; function ValidNumField: boolean; inline; // AV: check active edit 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 InvokeResetAll; 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 ); 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 OffsetTriangle(t: TTriangle; range: double): TTriangle; function ScaleTriangle(t: TTriangle; scale: double): TTriangle; function RotateTriangleCenter(t: TTriangle; rad: double): TTriangle; function RotateTrianglePoint(t: TTriangle; xr, yr: double; rad: double): TTriangle; function Centroid(t: TTriangle): TSPoint; function OffsetTriangleRandom(t: TTriangle): TTriangle; function ScaleTriangleCenter(t: TTriangle; scale: double): TTriangle; function ScaleTrianglePoint(t: TTriangle; x, y, scale: double): 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, Chaos, VarOrderForm; {$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 i: integer; svars: TStringList; begin svars := TStringList.Create; with cp.xform[SelectedTriangle] do for i := 0 to NrVar-1 do svars.AddPair(ifs[i], Round6(GetVariation(GetVariationIndex(ifs[i]))).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); 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 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 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 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.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 = GroupBox6) 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); // if not chkPreserve.Checked then ComputeWeights(cp, MainTriangles, transforms); 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; if CurvesForm.Visible then CurvesForm.SetCp(MainCp); 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')), PChar('Apophysis AV'), 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')), PChar('Apophysis AV'), 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')), PChar('Apophysis AV'), 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.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.BitBlt(Handle, 0, 0, Windows.AlphaBlend(Handle, 0, 0, TriangleView.Width, TriangleView.Height, bm.Canvas.Handle, 0, 0, //$CC0020); 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'); Copytrianglecoordinates1.Caption := TextByKey('editor-popup-transform-copycoords'); Copytransform1.Caption := TextByKey('editor-popup-transform-copywhole'); tbPaste.Hint := TextByKey('common-paste'); tbPasteTriangle.Hint := TextByKey('editor-popup-transform-pastecoords'); Pastetrianglecoordinates1.Caption := TextByKey('editor-popup-transform-pastecoords'); Pastetransform1.Caption := TextByKey('editor-popup-transform-pastewhole'); tbUndo.Caption := TextByKey('common-undo'); tbUndo.Hint := TextByKey('common-undo'); mnuUndo.Caption := TextByKey('common-undo'); tbRedo.Caption := TextByKey('common-redo'); 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'); tabVariations.Caption := TextByKey('editor-tab-variations-title'); VEVars.TitleCaptions[0] := TextByKey('editor-tab-variations-name'); VEVars.TitleCaptions[1] := TextByKey('editor-tab-variations-value'); //chkCollapseVariations.Caption := TextByKey('editor-tab-variations-togglehideunused'); cbCollapseVariations.Items[0] := TextByKey('editor-tab-variations-toggleshowall'); cbCollapseVariations.Items[1] := TextByKey('editor-tab-variations-togglehideunused'); cbCollapseVariations.Items[2] := TextByKey('editor-tab-variations-togglefavourites'); 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'); GroupBox3.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'); GroupBox10.Caption := TextByKey('editor-tab-triangle-reflection'); GroupBox5.Caption := TextByKey('editor-tab-triangle-transforms'); GroupBox6.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'); Label4.Caption := TextByKey('editor-tab-variations-search'); // 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'); 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'); GroupBox5.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'); 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; // tbExtendedEdit.ImageIndex := imgExtMove; 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); // btnResetFlip.Glyph.Assign(btnResetPivot.Glyph); PageControl.ActivePage := tabVariations; // AV cbCollapseVariations.ItemIndex := 0; // AV end; procedure TEditForm.FormDestroy(Sender: TObject); begin cp.free; Render.free; 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 //and ((rgPivot.ItemIndex = 1) or (rgPivot.ItemIndex = 4)) 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; 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; 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 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; // chkUseXFormColor.checked := UseTransformColors; // chkHelpers.Checked := HelpersEnabled; if ExtendedEdit then tbExtendedEdit.Down := true else tbMove.Down := true; 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 := det(c[0,0], c[0,1], c[1,0], c[1,1]); if (abs(deta) < 1E-4) then begin Application.MessageBox(PChar(TextByKey('editor-status-warninvert')), PChar('Apophysis AV'), 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 := det(p[0,0], p[0,1], p[1,0], p[1,1]); if (abs(deta) < 1E-4) then begin Application.MessageBox(PChar(TextByKey('editor-status-warninvert')), PChar('Apophysis AV'), 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 TriangleView.Invalidate; 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; 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')), PChar('Apophysis AV'), 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: integer; 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 then Exit; if (sum > 0) then 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: integer; 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: integer; 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: integer; 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; begin MainForm.UpdateUndo; 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; //AutoZoom; UpdateFlame(True); end; procedure TEditForm.mnuFlipHorizontalClick(Sender: TObject); var p: double; begin MainForm.UpdateUndo; 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; //AutoZoom; UpdateFlame(True); end; procedure TEditForm.cbTransformsChange(Sender: TObject); var n: integer; begin n := cbTransforms.ItemIndex; if (n <> SelectedTriangle) and (n >= 0) and (n <= LastTriangle) then begin SelectedTriangle := n; UpdateVariationList; // AV ShowSelectedInfo; TriangleView.Invalidate; end; 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: integer; 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: integer; 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); 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; //chkCollapseVariationsClick(nil); //chkCollapseVariablesClick(nil); 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')), PChar('Apophysis AV'), 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: integer; 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:integer; 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.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]); MainForm.UpdateUndo; if RotateXYO.Checked then MainTriangles[SelectedTriangle] := RotateTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, (PI/180)*angle) else if RotateX.Checked then MainTriangles[SelectedTriangle] := RotateTriangleXY(MainTriangles[SelectedTriangle], 0, (PI/180)*angle) else if RotateY.Checked then MainTriangles[SelectedTriangle] := RotateTriangleXY(MainTriangles[SelectedTriangle], 2, (PI/180)*angle) else //if RotateO.Checked then MainTriangles[SelectedTriangle] := RotateTriangleO(MainTriangles[SelectedTriangle], WorldPivot.x, WorldPivot.y, (PI/180)*angle); HasChanged := True; UpdateFlame(true); end; procedure TEditForm.btTrgRotateLeft90Click(Sender: TObject); begin MainForm.UpdateUndo; MainTriangles[SelectedTriangle] := RotateTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, PI/2); HasChanged := True; UpdateFlame(true); 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]); MainForm.UpdateUndo; if RotateXYO.Checked then MainTriangles[SelectedTriangle] := RotateTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, -(PI/180)*angle) else if RotateX.Checked then begin MainTriangles[SelectedTriangle] := RotateTriangleXY(MainTriangles[SelectedTriangle], 0, -(PI/180)*angle); if tbAutoWeights.Down then cp.CalculateWeights; // AV end else if RotateY.Checked then begin MainTriangles[SelectedTriangle] := RotateTriangleXY(MainTriangles[SelectedTriangle], 2, -(PI/180)*angle); if tbAutoWeights.Down then cp.CalculateWeights; // AV end else //if RotateO.Checked then MainTriangles[SelectedTriangle] := RotateTriangleO(MainTriangles[SelectedTriangle], WorldPivot.x, WorldPivot.y, -(PI/180)*angle); HasChanged := True; UpdateFlame(true); end; procedure TEditForm.btTrgRotateRight90Click(Sender: TObject); begin MainForm.UpdateUndo; MainTriangles[SelectedTriangle] := RotateTrianglePoint(MainTriangles[SelectedTriangle], GetPivot.x, GetPivot.y, -PI/2); HasChanged := True; UpdateFlame(true); end; procedure TEditForm.PaintBackground; begin assert(false); TriangleViewPaint(TriangleView); end; procedure TEditForm.TrgMove(dx, dy: double); var i: integer; 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; 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; // 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; 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 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); if tbAutoWeights.Down then cp.CalculateWeights; // AV HasChanged := True; UpdateFlame(true); end; procedure TEditForm.btTrgScaleDownClick(Sender: TObject); var scale: double; 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 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); 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; 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! 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.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.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} //chkCollapseVariationsClick(nil); //chkCollapseVariablesClick(nil); 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; 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 := 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 MainForm.SaveXMLFlame(MainCp, MainCp.name, OpenFile) then if MainForm.SortFlames.Checked then ListXML(OpenFile, 2, MainCp.name) // show the new item else ListXML(OpenFile, 0); // show the last item end; 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; VarSupports(i, supports3D, supportsDC); // Arow - 1 frect.Left := Rect.Right - 12; frect.Right := Rect.Right; frect.Top := Rect.Top; frect.Bottom := Rect.Bottom; if (supports3D or supportsDC) then begin VEVars.canvas.brush.Color := col; VEVars.canvas.fillRect(frect); end; 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; 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; 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; PasteTriangleCoordinates1.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; //if (px = fx) then MainTriangles[SelectedTriangle] := // FlipTriangleHorizontal(MainTriangles[SelectedTriangle]) //else if (py = fy) then MainTriangles[SelectedTriangle] := // FlipTriangleVertical(MainTriangles[SelectedTriangle]) else 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.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; begin s := Trim(txtSearchBox.Text); for i := 1 to VEVars.RowCount - 1 do begin if (Length(s) = 0) then 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); end; end else begin // AV: search text is not empty if (Length(s) > Length(VEVars.Cells[0, i])) then VEVars.RowHeights[i] := -1 else if Pos(s, VEVars.Cells[0, i]) > 0 then 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])], VEVars.DefaultRowHeight, -1); end; end else VEVars.RowHeights[i] := -1; end; 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; //Extended; 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 GroupBox5.Left := (TrianglePanel.CLientWidth - GroupBox5.Width) div 2; GroupBox6.Left := (TrianglePanel.CLientWidth - GroupBox6.Width) div 2; GroupBox3.Left := (TrianglePanel.CLientWidth - GroupBox3.Width) div 2; GroupBox10.Left := (TrianglePanel.CLientWidth - GroupBox10.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.Copytransform1Click(Sender: TObject); var txt: string; begin MemCp.Clear; MemCp.Name := 'Memorized XForm Parameters'; MemCp.xform[0].Assign(cp.xform[SelectedTriangle]); txt := Trim(MainForm.RetrieveXML(MemCp)); Clipboard.SetTextBuf(PChar(txt)); Pastetransform1.Enabled := True; MainForm.mnuPaste.Enabled := False; end; procedure TEditForm.Pastetransform1Click(Sender: TObject); var TempTriangles: TTriangles; i: integer; begin if (MemCp.NumXForms > 0) and (Transforms < NXFORMS) then begin MainForm.UpdateUndo; MemCp.TrianglesFromCP(TempTriangles); for i := 0 to MemCp.NumXForms - 1 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.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; 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.