unit Unit1; 

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Math, Printers, PrintersDlgs, LResources, Forms,
  Controls, Graphics, Dialogs, FPImage, ExtCtrls, Buttons, StdCtrls, Spin,
  ExtDlgs, ComCtrls, MaskEdit, ColorBox, PairSplitter, ValEdit, FileCtrl, Arrow,
  Grids, CheckLst, ButtonPanel, ComboEx, Menus, LCLType, LCLProc, PopupNotifier,
  ShellCtrls, ShlepsUtils, Dispatcher_iface, CADEngine, tpg, eventlog, unit2, unit3, unit4,
  unit5, unit6, unit7, unit8, Unit9, Config, TreeFilterEdit, Types, ClipBrd, EditBtn,
  Dispatcher, uPSComponent, ArrangeDialog, HTTPSend
  {$IFDEF LINUX}
  {$ELSE}
  , mmsystem
  {$ENDIF};

type

  { TForm1 }

  TForm1 = class(TForm)
    ActionGroupBox: TGroupBox;
    AddPortSpeedButton: TSpeedButton;
    AddNodeSpeedButton: TSpeedButton;
    AEdit: TFloatSpinEdit;
    AutoSimplifyButton: TSpeedButton;
    AxisButton: TSpeedButton;
    AxisModeCheckBox: TCheckBox;
    BGColorButton: TColorButton;
    BoldButton: TSpeedButton;
    BookMarkNameEdit: TEdit;
    BookmarkOpenButton: TSpeedButton;
    BookMarkSaveButton: TSpeedButton;
    BookmarkSpeedButton: TSpeedButton;
    BorderColorButton: TColorButton;
    ArrangeSpeedButton: TSpeedButton;
    ImportCommandFileMenuItem: TMenuItem;
    SearchSpeedButton: TSpeedButton;
    StartStyleComboBox: TComboBox;
    DelNodeSpeedButton: TSpeedButton;
    EndingStyleGroupBox: TGroupBox;
    SourceEdit: TEdit;
    CAStyleRadioGroup: TRadioGroup;
    OpenPictureDialog: TOpenPictureDialog;
    PickFileSpeedButton: TSpeedButton;
    ReloadSourceSpeedButton: TSpeedButton;
    SourceGroupBox: TGroupBox;
    Panel2: TPanel;
    SlideByLinkMenuItem: TMenuItem;
    OpComboBox: TComboBox;
    GoToStyleComboBox: TComboBox;
    CreateRelCASpeedButton: TSpeedButton;
    CopyHereMenuItem: TMenuItem;
    ArrangeMenuItem: TMenuItem;
    GotoSearchSpeedButton: TSpeedButton;
    ArrangeRectMenuItem: TMenuItem;
    ArrangePlanetMenuItem: TMenuItem;
    ArrangeDialogMenuItem: TMenuItem;
    Panel1: TPanel;
    SlideByLinkMenu: TPopupMenu;
    PortArrangeButton: TSpeedButton;
    GotoFoundModeDropSpeedButton: TSpeedButton;
    ActionMenuButton: TSpeedButton;
    PortArrangeILORButton: TSpeedButton;
    PortArrangeIROLButton: TSpeedButton;
    PortArrangeITOLButton: TSpeedButton;
    PortArrangeITOBButton: TSpeedButton;
    PortArrangeITORButton: TSpeedButton;
    PortArrangeIBOLButton: TSpeedButton;
    PortArrangeIBOTButton: TSpeedButton;
    PortArrangeIBORButton: TSpeedButton;
    SlideByLinkSpeedButton: TSpeedButton;
    AutoCreatePortSpeedButton: TSpeedButton;
    AutoUpdateDelaySpinEdit: TSpinEdit;
    AutoUpdateTimer: TTimer;
    EndStyleComboBox: TComboBox;
    UpdateAllSpeedButton: TSpeedButton;
    ZoomToSelMenuItem: TMenuItem;
    ZoomToSelectionMenuItem: TMenuItem;
    RemoveFromGroupMenuItem: TMenuItem;
    MoveHereMenuItem: TMenuItem;
    NavigatePopupMenu: TPopupMenu;
    GotoKeepScaleMenuItem: TMenuItem;
    GotoEditorMenuItem: TMenuItem;
    GotoFullScreenMenuItem: TMenuItem;
    ZoomToSceneMenuItem: TMenuItem;
    OriginToZeroMenuItem: TMenuItem;
    NonPortConnListBox: TListBox;
    ResetOriginPopupMenu: TPopupMenu;
    RelatedCAtoolPanel: TPanel;
    RelatedCAListBox: TListBox;
    LoadFromDirMenuItem: TMenuItem;
    OperationMenu: TPopupMenu;
    DeleteMenuItem: TMenuItem;
    AddToGroupMenuItem: TMenuItem;
    SaveAsDirMenuItem: TMenuItem;
    DelItemButton: TSpeedButton;
    ActionMenu: TPopupMenu;
    InsPointGroupBox: TGroupBox;
    Label10: TLabel;
    Label11: TLabel;
    Label12: TLabel;
    Label9: TLabel;
    LibraryShellTreeView: TShellTreeView;
    ObjStyleRadioGroup: TRadioGroup;
    RefreshSpeedLabel: TLabel;
    SceneBGColorDialog: TColorDialog;
    SearchEdit: TEdit;
    SearchListBox: TListBox;
    SEdit: TFloatSpinEdit;
    MultiSelOperationComboBox: TComboBox;
    DetachToolsButton: TSpeedButton;
    MenuItem1: TMenuItem;
    InspectorPageControl: TPageControl;
    Panel7: TPanel;
    InspectorPanel: TPanel;
    SelectionListPanel: TPanel;
    ConnectionActionLabel1: TLabel;
    ConnectionActionPanel1: TPanel;
    CalloutList: TListBox;
    CallFilterEdit: TEdit;
    CreateBookMarkSpeedButton: TSpeedButton;
    DelCallButton: TSpeedButton;
    CurrentEditingNameEdit: TEdit;
    SearchFilterCurlSpeedButton: TSpeedButton;
    SearchFilterObjectSpeedButton: TSpeedButton;
    SearchFilterConnSpeedButton: TSpeedButton;
    SearchFilterCalloutSpeedButton: TSpeedButton;
    DetachBookmarkSpeedButton: TSpeedButton;
    SettingsSpeedButton: TSpeedButton;
    PropTabSheet: TTabSheet;
    ActionsTabSheet: TTabSheet;
    EditCalloutButton: TSpeedButton;
    DelConnButton: TSpeedButton;
    DelPortSpeedButton: TSpeedButton;
    BaseObjectEdit: TEdit;
    EditObjButton: TSpeedButton;
    EditConnButton: TSpeedButton;
    FontComboBox: TComboBox;
    FontGroupBox: TGroupBox;
    FontSizeEdit: TSpinEdit;
    CalloutButton: TSpeedButton;
    BindingGroupBox: TGroupBox;
    GotoCallButton: TSpeedButton;
    CurrentEditingNameGroupBox: TGroupBox;
    Label15: TLabel;
    InspectorScrollBox: TScrollBox;
    CalloutsTabSheet: TTabSheet;
    BookMarkListBox: TListBox;
    LoadFromFileMenuItem: TMenuItem;
    LoadFromWebMenuItem: TMenuItem;
    SaveToServerMenuItem: TMenuItem;
    SaveToFileAsMenuItem: TMenuItem;
    SaveToFileMenuItem: TMenuItem;
    NumCalloutsLabel: TLabel;
    Panel3: TPanel;
    BindModeRadioGroup: TRadioGroup;
    LoadPopupMenu: TPopupMenu;
    Panel6: TPanel;
    SavePopupMenu: TPopupMenu;
    SelAllCurlSpeedButton: TSpeedButton;
    Send2SceneSpeedButton: TSpeedButton;
    FindObjectSpeedButton: TSpeedButton;
    FullScreenSpeedButton: TSpeedButton;
    AutoButton: TSpeedButton;
    Splitter2: TSplitter;
    RelatedCATabSheet: TTabSheet;
    TextMemo: TMemo;
    TextTabSheet: TTabSheet;
    TagEdit: TEdit;
    TagGroupBox: TGroupBox;
    WheelTimer: TTimer;
    TPGEditGroupBox: TGroupBox;
    RenameCallButton: TSpeedButton;
    SelAllCallSpeedButton: TSpeedButton;
    DetachDetailsSpeedButton: TSpeedButton;
    TPGEditMemo: TMemo;
    TPGEditPanel: TPanel;
    DetachTPGSpeedButton: TSpeedButton;
    Splitter5: TSplitter;
    ItalicButton: TSpeedButton;
    Panel5: TPanel;
    PeekBGColorButton: TColorButton;
    PeekFontFaceColorButton: TColorButton;
    PortFileOpenButton: TSpeedButton;
    PortOpenDialog: TOpenDialog;
    GotoConnButton: TSpeedButton;
    ConnNodesGroupBox: TGroupBox;
    NumConnectionsLabel: TLabel;
    ConnectionActionLabel: TLabel;
    ConnectionActionPanel: TPanel;
    ConnFilterEdit: TEdit;
    ConnectionList: TListBox;
    CoordStyleComboBox: TComboBox;
    GotoObjButton: TSpeedButton;
    BackgroundGroupBox: TGroupBox;
    CornerGroupBox: TGroupBox;
    LineCutGroupBox: TGroupBox;
    LineToBtn: TBitBtn;
    MoveToBtn: TBitBtn;
    NaviPanel: TPanel;
    ConnPanel: TPanel;
    ConnPortStringGrid: TStringGrid;
    PortPageControl: TPageControl;
    PortSaveButton: TSpeedButton;
    PortStringGrid: TStringGrid;
    RenameConnButton: TSpeedButton;
    PortSaveDialog: TSaveDialog;
    ConnectorButton: TSpeedButton;
    SelAllConnSpeedButton: TSpeedButton;
    SelectFontButton: TSpeedButton;
    SimplifyGroupBox: TGroupBox;
    LdXGEdit: TSpinEdit;
    LdYGEdit: TSpinEdit;
    LX2GEdit: TSpinEdit;
    LY2GEdit: TSpinEdit;
    LY1GEdit: TSpinEdit;
    ObjectActionLabel: TLabel;
    SelAllObjSpeedButton: TSpeedButton;
    RRectButton: TSpeedButton;
    ScaledTextButton: TSpeedButton;
    NewGroupSpeedButton: TSpeedButton;
    GroupStringGrid: TStringGrid;
    AddToGroupSpeedButton: TSpeedButton;
    Splitter4: TSplitter;
    StrikeButton: TSpeedButton;
    TabSheet1: TTabSheet;
    ConnectionsTabSheet: TTabSheet;
    ConnTabSheet: TTabSheet;
    PortsTabSheet: TTabSheet;
    ObjectLinksTabSheet: TTabSheet;
    TemplateListFilterEdit: TEdit;
    RectGroupBox: TGroupBox;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    LdXEdit: TFloatSpinEdit;
    LdYEdit: TFloatSpinEdit;
    LFiEdit: TFloatSpinEdit;
    LineGroupBox: TGroupBox;
    FigurePanel: TPanel;
    LLEdit: TFloatSpinEdit;
    LX1Edit: TFloatSpinEdit;
    LX2Edit: TFloatSpinEdit;
    LY1Edit: TFloatSpinEdit;
    LY2Edit: TFloatSpinEdit;
    RectSpeedButton: TSpeedButton;
    EllipseSpeedButton: TSpeedButton;
    RRectSpeedButton: TSpeedButton;
    LX1GEdit: TSpinEdit;
    TransparentBGCheckBox: TCheckBox;
    TreeFilterEdit1: TTreeFilterEdit;
    UnderButton: TSpeedButton;
    SelectionListEditor: TValueListEditor;
    ActionListEditor: TValueListEditor;
    VectorTextSpeedButton: TSpeedButton;
    TemplateGroupBox: TGroupBox;
    BookmarkOpenDialog: TOpenDialog;
    Mul2Button: TSpeedButton;
    Div2Button: TSpeedButton;
    BookMarkPanel: TPanel;
    BookMarkSaveDialog: TSaveDialog;
    ShowSceneDetailsButton: TSpeedButton;
    DelGroupButton: TSpeedButton;
    HintLabel: TLabel;
    NumTemplatesLabel: TLabel;
    NumSceneLabel: TLabel;
    NumGroupsLabel: TLabel;
    NumObjectsLabel: TLabel;
    Panel11: TPanel;
    EditButton: TSpeedButton;
    ShowTPGEditButton: TSpeedButton;
    ObjectFilterEdit: TEdit;
    TextRectButton: TSpeedButton;
    WidthButton5: TSpeedButton;
    WidthButton1: TSpeedButton;
    WidthButton2: TSpeedButton;
    WidthButton3: TSpeedButton;
    WidthButton4: TSpeedButton;
    XEdit: TFloatSpinEdit;
    YCoordLabel: TLabel;
    NumCurlsLabel: TLabel;
    EllipseButton: TSpeedButton;
    XcoordLabel: TLabel;
    CurlList: TListBox;
    DelCurlsButton: TSpeedButton;
    DelObjsButton: TSpeedButton;
    DelTemplButton: TSpeedButton;
    DrawingPanel: TPanel;
    FileOpenButton: TSpeedButton;
    FontPanel: TPanel;
    GridButton: TSpeedButton;
    GridGapEdit: TFloatSpinEdit;
    GroupItemsList: TListBox;
    GroupsTabSheet: TTabSheet;
    GUI2SceneBtn: TBitBtn;
    Image1: TImage;
    FileNewButton: TSpeedButton;
    PageControl2: TPageControl;
    PanRightButton: TSpeedButton;
    PanUpButton: TSpeedButton;
    PanDownButton: TSpeedButton;
    PenPanel: TPanel;
    PanLeftButton: TSpeedButton;
    PrintLineSpinEdit: TSpinEdit;
    LineTabSheet: TTabSheet;
    ObjectTabSheet: TTabSheet;
    FontTabSheet: TTabSheet;
    FigureTabSheet: TTabSheet;
    LineButton: TSpeedButton;
    LoadTemplateButton: TSpeedButton;
    NavigateButton: TSpeedButton;
    ObjButton: TSpeedButton;
    ObjectList: TListBox;
    ObjectsTabSheet: TTabSheet;
    PrimitivesPageControl: TPageControl;
    CurlActionPanel: TPanel;
    ObjectActionPanel: TPanel;
    Panel8: TPanel;
    TemplateActionPanel: TPanel;
    RenameObjectButton: TSpeedButton;
    RenameTemplateButton: TSpeedButton;
    SaveTemplateButton: TSpeedButton;
    Scene2GUIBtn: TBitBtn;
    SceneMemo: TMemo;
    SceneTabSheet: TTabSheet;
    SimplifyCurlButton: TSpeedButton;
    CurlsTabSheet: TTabSheet;
    TemplatesTabSheet: TTabSheet;
    TemplateList: TListBox;
    ToObjectButton: TSpeedButton;
    ToTemplateButton: TSpeedButton;
    CoordPanel: TPanel;
    ToolsPanel: TPanel;
    ToolOptionsPanel: TPanel;
    PenButton: TSpeedButton;
    PrintButton: TSpeedButton;
    RectButton: TSpeedButton;
    ResetCoordButton: TSpeedButton;
    SaveButton: TSpeedButton;
    SaveGButton: TSpeedButton;
    ViewScaleEdit: TFloatSpinEdit;
    SceneDetailsPanel: TPanel;
    ControlButton: TSpeedButton;
    SnapToGridButton: TSpeedButton;
    OpenTemplateDialog: TOpenDialog;
    TextButton: TSpeedButton;
    TLabelEdit: TEdit;
    TNameEdit: TEdit;
    ViewAngleEdit: TFloatSpinEdit;
    ViewXEdit: TFloatSpinEdit;
    ViewYEdit: TFloatSpinEdit;
    ColorDialog: TColorDialog;
    FontDialog: TFontDialog;
    PrintDialog: TPrintDialog;
    PrinterSetupDialog: TPrinterSetupDialog;
    OpenSceneDialog: TOpenDialog;
    SaveGDialog: TSavePictureDialog;
    SaveSceneDialog: TSaveDialog;
    Splitter1: TSplitter;
    YEdit: TFloatSpinEdit;
    procedure ActionListEditorEditingDone(Sender: TObject);
    procedure ActionMenuButtonClick(Sender: TObject);
    procedure AddNodeSpeedButtonClick(Sender: TObject);
    Procedure ArrangeDialogMenuItemClick(Sender: TObject);
    Procedure ArrangePlanetMenuItemClick(Sender: TObject);
    Procedure ArrangeSpeedButtonClick(Sender: TObject);
    Procedure AutoUpdateDelaySpinEditChange(Sender: TObject);
    Procedure AutoUpdateDelaySpinEditEditingDone(Sender: TObject);
    Procedure AutoUpdateTimerTimer(Sender: TObject);
    procedure BGColorButtonClick(Sender: TObject);
    Procedure CallFilterEditChange(Sender: TObject);
    procedure CalloutListDblClick(Sender: TObject);
    procedure CAStyleRadioGroupSelectionChanged(Sender: TObject);
    procedure ConnectionListDblClick(Sender: TObject);
    Procedure ConnFilterEditChange(Sender: TObject);
    Procedure ConnPortStringGridDblClick(Sender: TObject);
    procedure ConnPortStringGridEditingDone(Sender: TObject);
    procedure CurlListDblClick(Sender: TObject);
    Procedure DelNodeSpeedButtonClick(Sender: TObject);
    procedure EndingStyleGroupBoxClick(Sender: TObject);
    procedure GotoEditorMenuItemClick(Sender: TObject);
    Procedure GotoFullScreenMenuItemClick(Sender: TObject);
    procedure GotoKeepScaleMenuItemClick(Sender: TObject);
    Procedure GoToStyleComboBoxChange(Sender: TObject);
    Procedure Image1MouseEnter(Sender: TObject);
    procedure ArrangeRectMenuItemClick(Sender: TObject);
    procedure ImportCommandFileMenuItemClick(Sender: TObject);
    Procedure Label15MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    Procedure LoadFromWebMenuItemClick(Sender: TObject);
    Procedure OpComboBoxChange(Sender: TObject);
//    Procedure OperationSpeedButtonClick(Sender: TObject);
    Procedure OperationMenuSpeedButtonClick(Sender: TObject);
    procedure AddToGroupSpeedButtonClick(Sender: TObject);
    procedure AutoButtonClick(Sender: TObject);
    procedure AxisButtonClick(Sender: TObject);
    procedure AxisModeCheckBoxChange(Sender: TObject);
    procedure BaseObjectEditEditingDone(Sender: TObject);
    procedure BindModeRadioGroupSelectionChanged(Sender: TObject);
    procedure BoldButtonClick(Sender: TObject);
    Procedure BookmarkOpenButtonClick(Sender: TObject);
    Procedure BookMarkSaveButtonClick(Sender: TObject);
    procedure BookmarkSpeedButtonClick(Sender: TObject);
    procedure CalloutListKeyPress(Sender: TObject; var Key: char);
    procedure CalloutListMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    Procedure CalloutListSelectionChange(Sender: TObject; User: boolean);
    procedure CreateRelCASpeedButtonClick(Sender: TObject);
    procedure CurrentEditingNameEditClick(Sender: TObject);
    Procedure DelItemButtonClick(Sender: TObject);
    procedure DetachBookmarkSpeedButtonClick(Sender: TObject);
    procedure DisplayStatsCheckBoxChange(Sender: TObject);
    Procedure EditCalloutButtonClick(Sender: TObject);
    procedure FindObjectSpeedButtonClick(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure FullScreenSpeedButtonClick(Sender: TObject);
    procedure GotoCallButtonClick(Sender: TObject);
    procedure GotoSearchSpeedButtonClick(Sender: TObject);
    procedure Image1Click(Sender: TObject);
    procedure Image1DblClick(Sender: TObject);
    procedure Label15Click(Sender: TObject);
    Procedure LdXEditClick(Sender: TObject);
    Procedure LdXEditKeyPress(Sender: TObject; Var Key: char);
    Procedure LdXEditMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    Procedure LdYEditClick(Sender: TObject);
    Procedure LdYEditKeyPress(Sender: TObject; Var Key: char);
    Procedure LdYEditMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    Procedure LFiEditMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure LibraryShellTreeViewMouseMove(Sender: TObject;
      Shift: TShiftState; X, Y: Integer);
    Procedure LLEditClick(Sender: TObject);
    Procedure LLEditKeyPress(Sender: TObject; Var Key: char);
    Procedure LLEditMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure LoadFromDirMenuItemClick(Sender: TObject);
    procedure LoadFromFileMenuItemClick(Sender: TObject);
    procedure ConnectionListSelectionChange(Sender: TObject; User: boolean);
    procedure CoordStyleComboBoxChange(Sender: TObject);
    procedure CreateBookMarkSpeedButtonClick(Sender: TObject);
    Procedure DelConnButtonClick(Sender: TObject);
    Procedure DelGroupButtonClick(Sender: TObject);
    procedure DelPortSpeedButtonClick(Sender: TObject);
    procedure Div2ButtonClick(Sender: TObject);
    procedure Edit2Change(Sender: TObject);
    procedure EditConnButtonClick(Sender: TObject);
    procedure EditObjButtonClick(Sender: TObject);
    procedure GotoConnButtonClick(Sender: TObject);
    procedure GotoObjButtonClick(Sender: TObject);
    procedure GroupStringGridCheckboxToggled(sender: TObject; aCol,
      aRow: Integer; aState: TCheckboxState);
    procedure GroupStringGridEditingDone(Sender: TObject);
    procedure GroupStringGridSelection(Sender: TObject; aCol, aRow: Integer);
    procedure Image1MouseLeave(Sender: TObject);
    procedure BookMarkListBoxDblClick(Sender: TObject);
    Procedure LX1EditClick(Sender: TObject);
    Procedure LX1EditKeyPress(Sender: TObject; Var Key: char);
    Procedure LX1EditMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure LX1EditMouseEnter(Sender: TObject);
    Procedure LX2EditClick(Sender: TObject);
    Procedure LX2EditKeyPress(Sender: TObject; Var Key: char);
    Procedure LX2EditMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    Procedure LY1EditClick(Sender: TObject);
    Procedure LY1EditKeyPress(Sender: TObject; Var Key: char);
    Procedure LY1EditMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    Procedure LY2EditClick(Sender: TObject);
    Procedure LY2EditKeyPress(Sender: TObject; Var Key: char);
    Procedure LY2EditMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    Procedure DeleteMenuItemClick(Sender: TObject);
    procedure MoveHereMenuItemClick(Sender: TObject);
    procedure NewGroupSpeedButtonClick(Sender: TObject);
    procedure ObjectFilterEditChange(Sender: TObject);
    procedure ObjectListDblClick(Sender: TObject);
    Procedure ObjectListMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure ObjStyleRadioGroupSelectionChanged(Sender: TObject);
    procedure OriginToZeroMenuItemClick(Sender: TObject);
    Procedure PageControl2Change(Sender: TObject);
    Procedure PickFileSpeedButtonClick(Sender: TObject);
    procedure PortArrangeButtonClick(Sender: TObject);
    procedure PortFileOpenButtonClick(Sender: TObject);
    procedure PortPageControlChange(Sender: TObject);
    procedure PortPageControlMouseEnter(Sender: TObject);
    procedure PortSaveButtonClick(Sender: TObject);
    Procedure PortStringGridEditingDone(Sender: TObject);
    procedure PortStringGridMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    Procedure PrimitivesPageControlChange(Sender: TObject);
    procedure RectSpeedButtonClick(Sender: TObject);
    procedure RelatedCAListBoxDblClick(Sender: TObject);
    procedure ReloadSourceSpeedButtonClick(Sender: TObject);
    procedure RenameConnButtonClick(Sender: TObject);
    procedure SaveAsDirMenuItemClick(Sender: TObject);
    procedure SaveToFileAsMenuItemClick(Sender: TObject);
    procedure SaveToFileMenuItemClick(Sender: TObject);
    Procedure SearchSpeedButtonClick(Sender: TObject);
    Procedure StartStyleComboBoxChange(Sender: TObject);
    Procedure UpdateAllSpeedButtonClick(Sender: TObject);
    Procedure UpdateAllSpeedButtonDblClick(Sender: TObject);
    Procedure ViewScaleEditEditingDone(Sender: TObject);
    Procedure ViewScaleEditKeyUp(Sender: TObject; Var Key: Word; Shift: TShiftState
      );
    procedure SearchEditKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState
      );
    procedure SearchFilterCurlSpeedButtonClick(Sender: TObject);
    procedure SearchListBoxClick(Sender: TObject);
    Procedure SelAllConnSpeedButtonClick(Sender: TObject);
    procedure SelAllCurlSpeedButtonClick(Sender: TObject);
    procedure SelAllObjSpeedButtonClick(Sender: TObject);
    procedure DetachToolsButtonClick(Sender: TObject);
    procedure SelectionListEditorDblClick(Sender: TObject);
    procedure SelectionListEditorKeyUp(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure SettingsSpeedButtonClick(Sender: TObject);
    procedure LibraryShellTreeViewSelectionChanged(Sender: TObject);
    Procedure SlideByLinkSpeedButtonClick(Sender: TObject);
    procedure SnapToGridButtonClick(Sender: TObject);
    procedure AddPortSpeedButtonClick(Sender: TObject);
    procedure DetachDetailsSpeedButtonClick(Sender: TObject);
    procedure Send2SceneSpeedButtonClick(Sender: TObject);
    procedure SourceEditChange(Sender: TObject);
    procedure SourceEditEditingDone(Sender: TObject);
    procedure FontComboBoxChange(Sender: TObject);
    procedure Mul2ButtonClick(Sender: TObject);
    procedure PeekFontFaceColorButtonClick(Sender: TObject);
    procedure DelCurlsButtonClick(Sender: TObject);
    procedure DelObjsButtonClick(Sender: TObject);
    procedure DelTemplButtonClick(Sender: TObject);
    procedure FileNewButtonClick(Sender: TObject);
    procedure GUI2SceneBtnClick(Sender: TObject);
    procedure LdXEditChange(Sender: TObject);
    procedure LdXEditEditingDone(Sender: TObject);
    procedure LdYEditChange(Sender: TObject);
    procedure LdYEditEditingDone(Sender: TObject);
    procedure LFiEditChange(Sender: TObject);
    procedure LFiEditEditingDone(Sender: TObject);
    procedure LineToBtnClick(Sender: TObject);
    procedure LLEditChange(Sender: TObject);
    procedure LLEditEditingDone(Sender: TObject);
    procedure LoadTemplateButtonClick(Sender: TObject);
    procedure LX1EditChange(Sender: TObject);
    procedure LX1EditEditingDone(Sender: TObject);
    procedure LX2EditChange(Sender: TObject);
    procedure LX2EditEditingDone(Sender: TObject);
    procedure LY1EditChange(Sender: TObject);
    procedure LY1EditEditingDone(Sender: TObject);
    procedure LY2EditChange(Sender: TObject);
    procedure LY2EditEditingDone(Sender: TObject);
    procedure MoveToBtnClick(Sender: TObject);
    procedure ObjectListSelectionChange(Sender: TObject; User: boolean);
    procedure PanDownButtonClick(Sender: TObject);
    procedure PanLeftButtonClick(Sender: TObject);
    procedure PanRightButtonClick(Sender: TObject);
    procedure PanUpButtonClick(Sender: TObject);
    procedure PeekColorButtonClick(Sender: TObject);
    procedure CurlListSelectionChange(Sender: TObject; User: boolean);
    procedure DrawingPanelResize(Sender: TObject);
    procedure FileOpenButtonClick(Sender: TObject);
    procedure FontSizeEditChange(Sender: TObject);
    procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
    procedure FormCreate(Sender: TObject);
    procedure GridButtonClick(Sender: TObject);
    procedure GridGapEditChange(Sender: TObject);
    procedure Image1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Image1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure Image1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure Image1MouseWheel(Sender: TObject; Shift: TShiftState;
      WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
    procedure Image1Paint(Sender: TObject);
    procedure PenButtonClick(Sender: TObject);
    procedure PrintButtonClick(Sender: TObject);
    procedure RenameObjectButtonClick(Sender: TObject);
    procedure RenameTemplateButtonClick(Sender: TObject);
    procedure ResetCoordButtonClick(Sender: TObject);
    procedure SaveButtonClick(Sender: TObject);
    procedure SaveGButtonClick(Sender: TObject);
    procedure SaveTemplateButtonClick(Sender: TObject);
    procedure ViewScaleEditChange(Sender: TObject);
    procedure Scene2GUIBtnClick(Sender: TObject);
    procedure SelectFontButtonClick(Sender: TObject);
    procedure ShowPaletteButtonClick(Sender: TObject);
    procedure ShowSceneDetailsButtonClick(Sender: TObject);
    procedure ShowTPGEditButtonClick(Sender: TObject);
    procedure SimplifyCurlButtonClick(Sender: TObject);
    procedure GotoFoundModeDropSpeedButtonClick(Sender: TObject);
    procedure Splitter2ChangeBounds(Sender: TObject);
    procedure Splitter2Moved(Sender: TObject);
    procedure TemplateListFilterEditChange(Sender: TObject);
    procedure TemplateListSelectionChange(Sender: TObject; User: boolean);
    procedure TextMemoChange(Sender: TObject);
    procedure TLabelEditChange(Sender: TObject);
    procedure TLabelEditKeyPress(Sender: TObject; var Key: char);
    procedure TNameEditEditingDone(Sender: TObject);
    procedure TNameEditKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure ToObjectButtonClick(Sender: TObject);
    procedure ToolOptionsPanelClick(Sender: TObject);
    procedure ToolsPanelClick(Sender: TObject);
    procedure ToTemplateButtonClick(Sender: TObject);
    procedure DetachTPGSpeedButtonClick(Sender: TObject);
    Procedure TransparentBGCheckBoxChange(Sender: TObject);
    procedure WheelTimerTimer(Sender: TObject);
    procedure WidthButton1Click(Sender: TObject);
    procedure ViewXEditChange(Sender: TObject);
    procedure XEditChange(Sender: TObject);
    procedure ZoomToSceneMenuItemClick(Sender: TObject);
    procedure ZoomToSelectionMenuItemClick(Sender: TObject);
    procedure ZoomToSelMenuItemClick(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

  TCPoint=Class(TObject)
       xw,yw,xs,ys,dx,dy,ddx,ddy,dxdy,dydx:Extended;
     End;


var
  Form1: TForm1;
  ICommands:TStringList;

  SceneFileName:String;//для работы с диалогами
  DocumentName:String;//для выяснения отличается ли загруженный от указанного в закладке
  DocumentURL,DocumentProto,DocumentPath:String;
  FileName,vFileName:String;


  Bookmarks:TStringList;
  OriginalList:TStringList;

  //Control modes
  Drawing,JustDrawing: Boolean; // user's pen is down and curl drawing in progress, drawing just started - first line
  //Scaling,
  GettingPoint:Boolean;// select base point for conversion curl -> object
  Renaming:Boolean;
  Moving:Boolean;

  EditMode:String; //'curl object callout connection'
  Resizing:Boolean; //mouse down over handle
  ClickNotDrag:Boolean; //True if close to mousedown point than SamePlaceZone
  AllowMove:Boolean; //set in mousedown used in mouseup
  MovingConnectionPort:Boolean; //used for rubber new connection
  ActiveSelHandle:TVSelHandle;
  ActiveNodeNum:Longint; //number of selected node of zigzag connection
  UnderMouseDOWN,UnderMouseUP:TStringList;

  LockBackUpdate:Boolean; //prevents propagation of changed fields to another object
  LockSelectionUpdate:Boolean; //prevents redraw selected objects while selection in progress
  LockCoordUpdate:Boolean; // prevents repaint due to Coord Controls update while program requested change coord base
  LockRepaint:Boolean; //prevents double repaints
  BasisChanging:Boolean;
  UpdateFrom:Longint;

  ReadyEditor:String;

  CurrentXs,CurrentYs,
  CurrentXGs,CurrentYGs,
  LastXs,LastYs,                   // for rubber
  SelectX1s,SelectX2s,SelectY1s,SelectY2s:Longint;
  CurrentXw,CurrentYw,
  CurrentXGw,CurrentYGw,
  CurrentXNGw,CurrentYNGw,
  LastXw,LastYw,
  SelectX1w,SelectX2w,
  SelectX1NGw,SelectX2NGw,
  SelectY1w,SelectY2w,SelectY1NGw,SelectY2NGw:Extended;

  CopyOriginX,CopyOriginY:Extended;
  CopyDX,CopyDY:Extended;

  InitScalerY:Longint; //used for non-wheel scale
  InitScale:Extended;

  SelHandleZone,PortHandleZone,SamePlaceZone:Longint;

  LastWheelTime:TDateTime;
  WheelTimeDelta:Longint; //time

  SelRect:TRect;
  CurrentColor:TColor;

  Scene:TVScene;
  Drawer:TDrawer;
  WCanvas:TCanvas;
  RubberDisplayList:TStringList;

  SourceObj:TVObject;
  SourcePort:TVPort;

  RefreshRate:Extended;
//  RedrawTime:String;
//  AxisColor:TColor;
  BufferDrawing:Boolean;
  BufBitMap:TBitMap;

  NavigationMode:String; // teleport telezoom hover hoverzoom fly
  NavigationDst:String;//Item name for use with navigation menu
  OperationMenuInvokedFromButton:Boolean;

Procedure InitModule;
Function ExecCommand(Command:String):String;
Procedure RepaintView;
Function ExpandURL(ShortURL:String):String;
Function LoadTextFromURL(URL:String;S:TStringList):Boolean;
Procedure LoadImageFromURL(URL:String;Var Picture:TPicture);
Procedure UnselectAllBut(SelName:String);
Procedure AddItemToSelection(ItemName:String);
Procedure NavigateTo(Destination:String);
Function ComputeSelectionDST:String;
Function ComputeSelectionZoomDST:String;
Function ComputeItemDST(ItemName:String):String;
Function ComputeItemZoomDST(ItemName:String):String;
Procedure UpdateMultiSelection;
Function GetTypeByName(Scene:TVScene;Name:String):String;
procedure PrepareObjectPropEdit(Obj:TVObject);
procedure PrepareCalloutPropEdit(Callout:TVCallout);
procedure PrepareConnectionPropEdit(Conn:TVConnection);

implementation


Const
  updGUI=0;
  updX1=1;updGX1=11;
  updY1=2;updGY1=12;
  updX2=3;updGX2=13;
  updY2=4;updGY2=14;
  upddX=5;updGdX=15;
  upddY=6;updGdY=16;
  updL=7;
  updFI=8;
  TitleString='ChaosWarehouse pencil 20220102';

Procedure InitModule;
Begin
  {всё переехало в Dispatcher.pas
    'cad_updatedraw'
    'cad_updatecoordbase'
    'cad_updatescale'
    'cad_peekviewposition'
    'cad_scene2gui'
    'cad_reloadsource'
    'cad_gui2scene'
    'cad_loadscenefile'
    'cad_savescenefile'
    'cad_teleport'
    'cad_hover'
    'cad_fly'
    'cad_createobject'
    'cad_createobjectport'
    'cad_arrangeportsbyrect'
    'cad_arrangeportsbylines'
    'cad_createcallout'
    'cad_createconnection'
    'cad_createnpconnection'
    'cad_setsource'
    'cad_settext'
    'cad_getattr:item name:attr name'
    'cad_setattr:item name:attr name:value'
    'cad_select:item name'
    'cad_unselect:item name'
    'cad_unselectall'
    'cad_copy'
    'cad_paste'
    'cad_deleteselection'
    'cad_deleteitem'
    'cad_moveto'
  }
End;


Function ComputeFI(dx,dy:Extended):Extended;
Var Fi:Extended;
Begin
  Fi:=999;
  If (dx=0) And (dy>0) Then Fi:=pi/2;
  If (dx=0) And (dy<0) Then Fi:=-pi/2;
  If (dx<0) And (dy=0) Then Fi:=-pi;
  If (dx>0) And (dy=0) Then Fi:=0;
  If (dx=0) And (dy=0) Then Fi:=0;
  If Fi=999 Then Begin
    If Abs(dy)>Abs(dx) Then Fi:=ArcTan(dx/dy)
    Else Fi:=ArcTan(dy/dx);
    If (dx<0) And (dy>0) Then Fi:=Fi+pi;
    If (dx<0) And (dy<0) Then Fi:=Fi-pi;
  end;
  Result:=Fi;
end;

{ TForm1 }
{Function Min (A,B:Extended):Extended;
Begin
  If A<B Then Result:=A Else Result:=B;
End;
Function Max (A,B:Extended):Extended;
Begin
  If A>B Then Result:=A Else Result:=B;
End;}
Function MinI (A,B:Longint):Longint;
Begin
  If A<B Then Result:=A Else Result:=B;
End;
Function MaxI (A,B:Longint):Longint;
Begin
  If A>B Then Result:=A Else Result:=B;
End;

Function GetTypeByName(Scene:TVScene;Name:String):String;
Var I:Longint;
Begin
  If Scene.VCurlList.IndexOf(Name)>=0 Then Begin Result:='curl';Exit;End;
  If Scene.VObjectList.IndexOf(Name)>=0 Then Begin Result:='object';Exit;End;
  If Scene.VConnectionList.IndexOf(Name)>=0 Then Begin Result:='connection';Exit;End;
  If Scene.VCalloutList.IndexOf(Name)>=0 Then Begin Result:='callout';Exit;End;
  If Scene.VTemplateList.IndexOf(Name)>=0 Then Begin Result:='template';Exit;End;
  If Scene.VGroupList.IndexOf(Name)>=0 Then Begin Result:='group';Exit;End;
  Result:='none';
  //добавить обработку ошибки доступа к несусествующему элементу - проверку none при вызове
End;

Function GetNewName(Scene:TVScene;List:TStringList;Prefix:String):String;
Var CName:String;Numerator:Longint;
Begin
  Numerator:=List.Count;
  Repeat
    If List=Scene.VCurlList Then CName:=Prefix+'Curl'+IntToStr(Numerator);
    If List=Scene.VObjectList Then CName:=Prefix+'Object'+IntToStr(Numerator);
    If List=Scene.VConnectionList Then CName:=Prefix+'Connection'+IntToStr(Numerator);
    If List=Scene.VTemplateList Then CName:=Prefix+'Template'+IntToStr(Numerator);
    If List=Scene.VGroupList Then CName:=Prefix+'Group'+IntToStr(Numerator);
    If List=Scene.VCalloutList Then CName:=Prefix+'Callout'+IntToStr(Numerator);
    Inc(Numerator);
  Until (Scene.VCurlList.IndexOf(CName)<0)And
        (Scene.VObjectList.IndexOf(CName)<0)And
        (Scene.VConnectionList.IndexOf(CName)<0)And
        (Scene.VTemplateList.IndexOf(CName)<0)And
        (Scene.VGroupList.IndexOf(CName)<0)And
        (Scene.VCalloutList.IndexOf(CName)<0);
  Result:=CName;
  // старый именователь
  // соотвестствующий список пуст - начинаем с 0
  // иначе - берем имя последнего и прибавляем 1
  // не учитывает переименование в нестандартные имена
{  If Scene.VCurlList.Count=0 Then CName:='curl0'
  Else CName:=((Scene.VCurlList.Objects[Scene.VCurlList.Count-1]) As TVCurl).Name;
  TI:=IntToStr(StrToInt(Copy(CName,5,Length(CName)-4))+1);
  Scene.VCurlList.AddObject('curl'+TI,Curl);
  Curl.Name:='curl'+TI;}
End;

Procedure UpdateScreenShell(Drawer:TDrawer);
Var x1,x2,x3,x4,y1,y2,y3,y4,lx,ly,rx,ry:Extended;
Begin
{  Drawer.StoW(-Drawer.Wx+Form1.DrawingPanel.Left,-Drawer.Wy+Form1.DrawingPanel.Top,x1,y1);
  Drawer.StoW(-Drawer.Wx+Form1.DrawingPanel.Left,+Drawer.Wy+Form1.DrawingPanel.Top,x2,y2);
  Drawer.StoW(Drawer.Wx+Form1.DrawingPanel.Left,-Drawer.Wy+Form1.DrawingPanel.Top ,x3,y3);
  Drawer.StoW(Drawer.Wx+Form1.DrawingPanel.Left,+Drawer.Wy+Form1.DrawingPanel.Top,x4,y4);}
  Drawer.StoW(0,Drawer.Wy,x1,y1);
  Drawer.StoW(0,0,x2,y2);
  Drawer.StoW(Drawer.Wx+Form1.DrawingPanel.Left,Drawer.Wy,x3,y3);
  Drawer.StoW(Drawer.Wx+Form1.DrawingPanel.Left,0,x4,y4);

  With Scene Do Begin
    ScreenShell.X1:=Math.maxExtended;
    ScreenShell.X2:=-Math.maxExtended+Math.minExtended;
    ScreenShell.Y1:=Math.MaxExtended;
    ScreenShell.Y2:=-Math.maxExtended+Math.minExtended;
    If x1<ScreenShell.X1 Then ScreenShell.X1:=x1;
    If x2<ScreenShell.X1 Then ScreenShell.X1:=x2;
    If x3<ScreenShell.X1 Then ScreenShell.X1:=x3;
    If x4<ScreenShell.X1 Then ScreenShell.X1:=x4;
    If x1>ScreenShell.X2 Then ScreenShell.X2:=x1;
    If x2>ScreenShell.X2 Then ScreenShell.X2:=x2;
    If x3>ScreenShell.X2 Then ScreenShell.X2:=x3;
    If x4>ScreenShell.X2 Then ScreenShell.X2:=x4;
    If y1<ScreenShell.Y1 Then ScreenShell.Y1:=y1;
    If y2<ScreenShell.Y1 Then ScreenShell.Y1:=y2;
    If y3<ScreenShell.Y1 Then ScreenShell.Y1:=y3;
    If y4<ScreenShell.Y1 Then ScreenShell.Y1:=y4;
    If y1>ScreenShell.Y2 Then ScreenShell.Y2:=y1;
    If y2>ScreenShell.Y2 Then ScreenShell.Y2:=y2;
    If y3>ScreenShell.Y2 Then ScreenShell.Y2:=y3;
    If y4>ScreenShell.Y2 Then ScreenShell.Y2:=y4;
  end;
End;

Procedure DrawScene(Drawer:TDrawer;Buffer:Boolean);
Var I,J,N,N1:Longint; G,GX,Gr,GY,x1,x2,x3,x4,y1,y2,y3,y4,lx,ly,rx,ry:Extended;
    Cmd,TemplName,sX,sY,sA,sS,Buf,ParsedBuf:String;
    Sm,Rm,Scm,tmpm,OldTransM:TMatrix2D;
    DisplayList:TStringList;
    X,Y,A,S:Extended;
    SubDrawer:TDrawer; Curl:TVCurl; Obj:TVObject; Templ:TVTemplate; Port:TVPort;
    SelHandle,SelHandle1:TVSelHandle; DupHandles:Boolean;
    T1,T2:TDateTime;
    OrigCanvas:TCanvas;
    OCW,OCH:Longint;
begin
  OrigCanvas:=Drawer.Canvas;
  If Buffer Then Begin Drawer.Canvas:=BufBitMap.Canvas;
    //грязный хак - должно быть OrigCanvas.Width
    OCW:=Form1.DrawingPanel.ClientWidth;
    OCH:=Form1.DrawingPanel.ClientHeight;
    BufBitMap.SetSize(OCW,OCH);
  End;
  //кажется тут вычисляется оболочка экрана
  UpdateScreenShell(Drawer);
  Drawer.Canvas.AutoRedraw:=False;
  Drawer.Canvas.Pen.Mode:=pmCopy;
  Drawer.EnforcedPenColor:=clNone;
  Drawer.EnforcedPenStyle:=psClear;
  Drawer.Canvas.Pen.Style:=psSolid;
  Drawer.EnforcedBrushColor:=clNone;
  Drawer.ExecCommand('SetBGColor '+Config.ConfigFile.Values['SceneBGColor'],ZeroAcc);
  Drawer.Canvas.Rectangle(-10000,-10000,10000,10000);

  If Form1.GridButton.Down Then Begin
    Drawer.ExecCommand('SetWidth 1',ZeroAcc);
    Drawer.ExecCommand('SetColor '+Config.ConfigFile.Values['AxisColor'],ZeroAcc);
    G:=Form1.GridGapEdit.Value;
    GX:=Round(Scene.ScreenShell.X1/G)*G;
    GR:=Round(Scene.ScreenShell.X2/G)*G;
    If ((Scene.ScreenShell.X2-Scene.ScreenShell.X1)/G)<=(Drawer.Wx div 4) then Begin //какая-то хуйня
      While GX<=GR Do Begin
        Drawer.ExecCommand('MoveTo '+FloatToStr(GX)+','+FloatToStr(Scene.ScreenShell.Y1),ZeroAcc);
        Drawer.ExecCommand('LineTo '+FloatToStr(GX)+','+FloatToStr(Scene.ScreenShell.Y2),ZeroAcc);
        Gx:=Gx+G;
      End;
      GY:=Round(Scene.ScreenShell.Y1/G)*G;
      GR:=Round(Scene.ScreenShell.Y2/G)*G;
      While Gy<=GR Do Begin
        Drawer.ExecCommand('MoveTo '+FloatToStr(Scene.ScreenShell.X1)+','+FloatToStr(Gy),ZeroAcc);
        Drawer.ExecCommand('LineTo '+FloatToStr(Scene.ScreenShell.X2)+','+FloatToStr(Gy),ZeroAcc);
        Gy:=Gy+G;
      End;
    End;
  End;
  If Form1.AxisButton.Down Then Begin
    Drawer.ExecCommand('SetWidth 2',ZeroAcc);
    Drawer.ExecCommand('SetColor '+Config.ConfigFile.Values['AxisColor'],ZeroAcc);
    Drawer.ExecCommand('MoveTo '+FloatToStr(Scene.ScreenShell.X1+20*Form1.ViewScaleEdit.Value)+',0',ZeroAcc);
    Drawer.ExecCommand('LineTo '+FloatToStr(Scene.ScreenShell.X2-20*Form1.ViewScaleEdit.Value)+',0',ZeroAcc);
    Drawer.ExecCommand('MoveTo 0,'+FloatToStr(Scene.ScreenShell.Y1+20*Form1.ViewScaleEdit.Value),ZeroAcc);
    Drawer.ExecCommand('LineTo 0,'+FloatToStr(Scene.ScreenShell.Y2-20*Form1.ViewScaleEdit.Value),ZeroAcc);
{
    Drawer.ExecCommand('MoveTo '+FloatToStr((x1+x2)/2)+',0',ZeroAcc);
    Drawer.ExecCommand('LineTo '+FloatToStr((x3+x4)/2)+',0',ZeroAcc);
    Drawer.ExecCommand('LineTo '+FloatToStr( (x3+x4)/2-50*ViewScaleEdit.Value)+','+FloatToStr(5*ViewScaleEdit.Value),ZeroAcc);
    Drawer.ExecCommand('MoveTo '+FloatToStr((x3+x4)/2)+',0',ZeroAcc);
    Drawer.ExecCommand('LineTo '+FloatToStr( (x3+x4)/2-50*ViewScaleEdit.Value)+','+FloatToStr(-5*ViewScaleEdit.Value),ZeroAcc);
    Drawer.ExecCommand('MoveTo 0,'+FloatToStr(-(y1+y4)/2),ZeroAcc);
    Drawer.ExecCommand('LineTo 0,'+FloatToStr((y2+y3)/2),ZeroAcc);
    Drawer.ExecCommand('LineTo '+FloatToStr(5*ViewScaleEdit.Value)+','+FloatToStr( (y2+y3)/2-50*ViewScaleEdit.Value),ZeroAcc);
    Drawer.ExecCommand('MoveTo 0,'+FloatToStr((y2+y3)/2),ZeroAcc);
    Drawer.ExecCommand('LineTo '+FloatToStr(-5*ViewScaleEdit.Value)+','+FloatToStr( (y2+y3)/2-50*ViewScaleEdit.Value),ZeroAcc);
    }
  End;
  If Scene.View.Count>0 Then Begin
    For I:=0 To Scene.View.Count-1 Do Begin
      Scene.ExecCommand(Scene.View[I],ZeroAcc,0);
    End;
  End;

  // подсвечиваем выделенное
  // Drawer.EnforcedPenColor:=clRed;
  // Drawer.EnforcedPenStyle:=psClear;
  Drawer.Canvas.Pen.Mode:=pmNotCopy;

{ //
  If Form1.CurlList.SelCount>0 Then
    For I:=0 To Form1.CurlList.Count-1 Do
      If Form1.CurlList.Selected[I] Then
        Scene.ExecCommand('DrawCurl '+Form1.CurlList.Items[I],ZeroAcc,0);
  If Form1.ObjectList.SelCount>0 Then
    For I:=0 To Form1.ObjectList.Count-1 Do
      If Form1.ObjectList.Selected[I] Then
        Scene.ExecCommand('DrawObject '+Form1.ObjectList.Items[I],ZeroAcc,0);}


  Drawer.Canvas.Pen.Mode:=pmCopy;
  If Scene.VCalloutList.Count>0 Then
    For I:=0 To Scene.VCalloutList.Count-1 Do
        Scene.ExecCommand('DrawCallout '+Scene.VCalloutList[I],ZeroAcc,0);
  //рисуем связи
  Drawer.Canvas.Pen.Mode:=pmCopy;
  If Scene.VConnectionList.Count>0 Then
      For I:=0 To Scene.VConnectionList.Count-1 Do
         Scene.ExecCommand('DrawConnection '+Scene.VConnectionList[I],ZeroAcc,0);

  If Form1.DrawingPanel.Color=clBlack Then Scene.Drawer.Canvas.Pen.Mode:=pmWhite//pmNotCopy;
  Else Scene.Drawer.Canvas.Pen.Mode:=pmNotCopy;//pmNotCopy;
  Drawer.EnforcedPenColor:=clRed;
  If Scene.SelectedList.Count>0 Then
    For I:=0 To Scene.SelectedList.Count-1 Do Begin
      If GetTypeByName(Scene,Scene.SelectedList[I])='connection' Then
        Scene.ExecCommand('DrawConnection '+Scene.SelectedList[I],ZeroAcc,0);
    end;
{  If (Form1.ConnectionList.SelCount>0) And (Form1.ConnectionList.Count>0) Then
    For I:=0 To Form1.ConnectionList.Count-1 Do
      If Form1.ConnectionList.Selected[I] Then
        Scene.ExecCommand('DrawConnection '+Form1.ConnectionList.Items[I],ZeroAcc,0);}
  Drawer.EnforcedPenColor:=clNone;
  Drawer.Canvas.Pen.Mode:=pmCopy;
  //рисуем подписи
  If Scene.ShowObjectNames Then Begin
    Drawer.ExecCommand('SetFont '+SettingsForm.ONameFontDialog.Font.Name+','+IntToStr(SettingsForm.ONameFontDialog.Font.Size)+','+(ConfigFile.Values['ObjectNameColor'])+',',ZeroAcc);
    If SettingsForm.ONameBGColorButton.ButtonColor<>clBlack Then Begin
      Drawer.ExecCommand('SetTextStyle Opaque',ZeroAcc);
      Drawer.ExecCommand('SetBGColor '+(ConfigFile.Values['ObjectNameBGColor']),ZeroAcc);
    End Else
      Drawer.ExecCommand('SetTextStyle Transparent',ZeroAcc);
    If Scene.VCurlList.Count>0 Then
      For I:=0 To Scene.VcurlList.Count-1 Do Begin
        Curl:=Scene.VCurlList.Objects[I] As TVCurl;
        Drawer.ExecCommand('TextOut '+FloatToStr((Curl.Shell.X1+Curl.Shell.X2)/2)+','+FloatToStr((Curl.Shell.Y1+Curl.Shell.Y2)/2)+','+Curl.Name,ZeroAcc);
//      своих координат у кривой нет - придётся воспользоваться шеллом
      End;
    If Scene.VObjectList.Count>0 Then
      For I:=0 To Scene.VObjectList.Count-1 Do Begin
        Obj:=Scene.VObjectList.Objects[I] As TVObject;
     //   Drawer.ExecCommand('TextOut '+FloatToStr(Obj.X)+','+FloatToStr(Obj.Y)+','+Obj.Name,ZeroAcc);
        Drawer.ExecCommand('TextOut '+FloatToStr((Obj.Shell.X1+Obj.Shell.X2)/2)+','+FloatToStr((Obj.Shell.Y1+Obj.Shell.Y2)/2)+','+Obj.Name,ZeroAcc);
        If Scene.ShowPortNames Then
          If Obj.PortList.Count>0 Then Begin
            Drawer.ExecCommand('SetFont '+SettingsForm.ONameFontDialog.Font.Name+','+IntToStr(SettingsForm.ONameFontDialog.Font.Size)+','+ColorToString(SettingsForm.ONameFontDialog.Font.Color)+',b',ZeroAcc);
            Drawer.ExecCommand('SetTextStyle Transparent',ZeroAcc);
            For J:=0 To Obj.PortList.Count-1 Do Begin
              Port:=Obj.PortList.Objects[J] As TVPort;
              Drawer.ExecCommand('TextOut '+FloatToStr(Port.AX)+','+FloatToStr(port.AY)+','+Port.Name,ZeroAcc);
            End;
         End;
      End;
  End;
  Drawer.Canvas.Pen.Mode:=pmXor;
  Drawer.ExecCommand('SetWidth 0',ZeroAcc);
  If Scene.VHandleList.Count>0 Then
    For I:=0 To Scene.VHandleList.Count-1 Do Begin
      SelHandle:=Scene.VHandleList.Objects[I] As TVSelHandle;
      DupHandles:=False;
      If I>0 Then Begin
        DupHandles:=False;
        For J:=0 To I-1 Do Begin
          SelHandle1:=Scene.VHandleList.Objects[J] As TVSelHandle;
          If (Abs(SelHandle.Xw-SelHandle1.Xw)/Drawer.ViewScale<2)And(Abs(SelHandle.Yw-SelHandle1.Yw)/Drawer.ViewScale<2) Then Begin
            DupHandles:=True;Break;
          End;
        End;
      end;
      If Not DupHandles Then
        Drawer.ExecCommand('UnScaled '+FloatToStr(SelHandle.Xw)+','+FloatToStr(SelHandle.Yw)+',box,'+IntToStr(SelHandleZone),ZeroAcc);
{        Case SelHandle.Style Of
        'Box': Drawer.ExecCommand('UnScaled '+FloatToStr(SelHandle.Xw)+','+FloatToStr(SelHandle.Yw)+',box,'+IntToStr(SelHandleZone),ZeroAcc);
        'LT': Drawer.ExecCommand('UnScaled '+FloatToStr(SelHandle.Xw)+','+FloatToStr(SelHandle.Yw)+',LT,'+IntToStr(SelHandleZone),ZeroAcc);
        'MT': Drawer.ExecCommand('UnScaled '+FloatToStr(SelHandle.Xw)+','+FloatToStr(SelHandle.Yw)+',MT,'+IntToStr(SelHandleZone),ZeroAcc);
        'RT': Drawer.ExecCommand('UnScaled '+FloatToStr(SelHandle.Xw)+','+FloatToStr(SelHandle.Yw)+',RT,'+IntToStr(SelHandleZone),ZeroAcc);
        'LB': Drawer.ExecCommand('UnScaled '+FloatToStr(SelHandle.Xw)+','+FloatToStr(SelHandle.Yw)+',LB,'+IntToStr(SelHandleZone),ZeroAcc);
        'MB': Drawer.ExecCommand('UnScaled '+FloatToStr(SelHandle.Xw)+','+FloatToStr(SelHandle.Yw)+',MB,'+IntToStr(SelHandleZone),ZeroAcc);
        'RB': Drawer.ExecCommand('UnScaled '+FloatToStr(SelHandle.Xw)+','+FloatToStr(SelHandle.Yw)+',RB,'+IntToStr(SelHandleZone),ZeroAcc);
        'LM': Drawer.ExecCommand('UnScaled '+FloatToStr(SelHandle.Xw)+','+FloatToStr(SelHandle.Yw)+',LM,'+IntToStr(SelHandleZone),ZeroAcc);
        'RM': Drawer.ExecCommand('UnScaled '+FloatToStr(SelHandle.Xw)+','+FloatToStr(SelHandle.Yw)+',LM,'+IntToStr(SelHandleZone),ZeroAcc);
        end;}
    End;
  Drawer.Canvas.Pen.Mode:=pmCopy;
  Scene.Drawer.Canvas:=OrigCanvas;
  Drawer.Canvas:=OrigCanvas;
End;

Procedure RepaintView;
Var I,J,N,N1:Longint; G,GX,Gr,GY,x1,x2,x3,x4,y1,y2,y3,y4,lx,ly,rx,ry:Extended;
    Cmd,TemplName,sX,sY,sA,sS,Buf,ParsedBuf:String;
    Sm,Rm,Scm,tmpm,OldTransM:TMatrix2D;
    DisplayList:TStringList;
    X,Y,A,S:Extended;
    SubDrawer:TDrawer; Curl:TVCurl; Obj:TVObject; Templ:TVTemplate; Port:TVPort;
    T1,T2:TDateTime;
    StatLine:String;
begin
  T1:=Now;
  GOPS:=0;
  Drawer.Canvas:=Form1.DrawingPanel.Canvas;
  DrawScene(Drawer,BufferDrawing);//!!!! true-false
  Drawer.Updated:=False;
  If BufferDrawing Then Begin
   { Form1.Image1.Canvas.CopyRect(
    Rect(1,1,Form1.DrawingPanel.ClientWidth,Form1.DrawingPanel.ClientHeight),BufBitMap.Canvas,
    Rect(1,1,Form1.DrawingPanel.ClientWidth,Form1.DrawingPanel.ClientHeight));}
    Form1.DrawingPanel.Invalidate;
    //.Repaint;
//    Form1.Image1Paint(nil);
//    Form1.DrawingPanel.Canvas.CopyRect(Rect(0,0,Form1.DrawingPanel.ClientWidth,Form1.DrawingPanel.ClientHeight),BufBitMap.Canvas,Rect(0,0,Form1.DrawingPanel.ClientWidth,Form1.DrawingPanel.ClientHeight));
//    Form1.DrawingPanel.Refresh; //- work but blinking
  End;
 // Form1.DrawingPanel.Update;
 // Form1.DrawingPanel.Invalidate;  - not work
 // Form1.DrawingPanel.Repaint; - work but blinking
  LockRepaint:=True;
  T2:=Now;
  RefreshRate:=(T2-T1)*msecsPerDay;
  StatLine:='Refresh rate: '+FloatToStrF(RefreshRate,ffNumber,6,0)+' ms';
  If RefreshRate>0 Then Begin
    StatLine:=StatLine+#10#13+IntToStr(GOPS)+' primitives '+#10#13+IntToStr(Round(GOPS/((T2-T1)*msecsPerDay/1000)))+' GOps';
  end;
  Form1.RefreshSpeedLabel.Caption:=StatLine;
  LockRepaint:=False;
end;

procedure TForm1.Image1Paint(Sender: TObject);
Var I,J,N,N1:Longint; G,GX,Gr,GY,x1,x2,x3,x4,y1,y2,y3,y4,lx,ly,rx,ry:Extended;
    Cmd,TemplName,sX,sY,sA,sS,Buf,ParsedBuf:String;
    Sm,Rm,Scm,tmpm,OldTransM:TMatrix2D;
    DisplayList:TStringList;
    X,Y,A,S:Extended;
    SubDrawer:TDrawer; Curl:TVCurl; Obj:TVObject; Templ:TVTemplate; Port:TVPort;
    T1,T2:TDateTime;
    StatLine:String;
begin
  If Sender is TImage Then Exit;
  If LockRepaint Then Exit;
  If Drawer.Updated Then Begin
    T1:=Now;
    GOPS:=0;
    Drawer.Canvas:=Form1.DrawingPanel.Canvas;
    DrawScene(Drawer,BufferDrawing);//
    Drawer.Updated:=False;
    T2:=Now;
    StatLine:='Refresh rate: '+FloatToStrF((T2-T1)*msecsPerDay,ffNumber,6,0)+' ms';
    If (T2-T1)*msecsPerDay>0 Then Begin
      StatLine:=StatLine+#10#13+IntToStr(GOPS)+' primitives '+#10#13+IntToStr(Round(GOPS/((T2-T1)*msecsPerDay/1000)))+' GOps';
    end;
    Form1.RefreshSpeedLabel.Caption:=StatLine;
  end;
  If BufferDrawing Then Begin
    Form1.DrawingPanel.Canvas.CopyRect(Rect(0,0,Form1.DrawingPanel.ClientWidth,Form1.DrawingPanel.ClientHeight),BufBitMap.Canvas,Rect(0,0,Form1.DrawingPanel.ClientWidth,Form1.DrawingPanel.ClientHeight));
//    DrawingPanel.DoubleBuffered:=False;
  end;
end;

Function ComputeItemDST(ItemName:String):String;
Var ObjName:String;
    Curl:TVCurl;
    Obj:TVObject;
    Conn:TVConnection;
    Callout:TVCallout;
    I,J,N:Longint;
    X1,X2,Y1,Y2:Extended;
begin
  X1:=+MaxExtended;X2:=-MaxExtended;
  Y1:=+MaxExtended;Y2:=-MaxExtended;
  N:=Scene.VCurlList.IndexOf(ItemName);
  If N>=0 Then Begin
    Curl:=Scene.VCurlList.Objects[N] As TVcurl;
    X1:=Min(X1,Curl.Shell.X1);Y1:=Min(Y1,Curl.Shell.Y1);
    X2:=Max(X2,Curl.Shell.X2);Y2:=Max(Y2,Curl.Shell.Y2);
  End;
  N:=Scene.VObjectList.IndexOf(ItemName);
  If N>=0 Then Begin
    Obj:=Scene.VObjectList.Objects[N] As TVObject;
    X1:=Min(X1,Obj.Shell.X1);Y1:=Min(Y1,Obj.Shell.Y1);
    X2:=Max(X2,Obj.Shell.X2);Y2:=Max(Y2,Obj.Shell.Y2);
  End;
  N:=Scene.VConnectionList.IndexOf(ItemName);
  If N>=0 Then Begin
    Conn:=Scene.VObjectList.Objects[N] As TVConnection;
    X1:=Min(X1,Conn.Shell.X1);Y1:=Min(Y1,Conn.Shell.Y1);
    X2:=Max(X2,Conn.Shell.X2);Y2:=Max(Y2,Conn.Shell.Y2);
  End;
  N:=Scene.VCalloutList.IndexOf(ItemName);
  If N>=0 Then Begin
    Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
    X1:=Min(X1,Callout.Shell.X1);Y1:=Min(Y1,Callout.Shell.Y1);
    X2:=Max(X2,Callout.Shell.X2);Y2:=Max(Y2,Callout.Shell.Y2);
  End;
  Result:='X='+FloatToStr((X1+X2)/2)+'&Y='+FloatToStr((Y1+Y2)/2)+
         '&A='+FloatToStr(Scene.Drawer.ViewAngle)+'&S='+FloatToStr(Scene.Drawer.ViewScale);
End;

Function ComputeSelectionDST:String;
Var ObjName:String;
    Obj:TVObject;
    Callout:TVCallout;
    Connection:TVConnection;
    Curl:TVCurl;
    I,J,N:Longint;
    X1,X2,Y1,Y2:Extended;
begin
  X1:=+MaxExtended;X2:=-MaxExtended;
  Y1:=+MaxExtended;Y2:=-MaxExtended;
  If Scene.SelectedList.Count<=0 Then Exit;
  For I:=0 To Scene.SelectedList.Count-1 Do Begin
    If Scene.SelectedList.Objects[I] is TVCurl Then Begin
      Curl:=Scene.SelectedList.Objects[I] As TVCurl;
      X1:=Min(X1,Curl.Shell.X1);Y1:=Min(Y1,Curl.Shell.Y1);
      X2:=Max(X2,Curl.Shell.X2);Y2:=Max(Y2,Curl.Shell.Y2);
    end;
    If Scene.SelectedList.Objects[I] is TVConnection Then Begin
      Connection:=Scene.SelectedList.Objects[I] As TVConnection;
      X1:=Min(X1,Connection.Shell.X1);Y1:=Min(Y1,Connection.Shell.Y1);
      X2:=Max(X2,Connection.Shell.X2);Y2:=Max(Y2,Connection.Shell.Y2);
    end;
    If Scene.SelectedList.Objects[I] is TVCallout Then Begin
      Callout:=Scene.SelectedList.Objects[I] As TVCallout;
      X1:=Min(X1,Callout.Shell.X1);Y1:=Min(Y1,Callout.Shell.Y1);
      X2:=Max(X2,Callout.Shell.X2);Y2:=Max(Y2,Callout.Shell.Y2);
    end;
    If Scene.SelectedList.Objects[I] is TVObject Then Begin
      Obj:=Scene.SelectedList.Objects[I] As TVObject;
      X1:=Min(X1,Obj.Shell.X1);Y1:=Min(Y1,Obj.Shell.Y1);
      X2:=Max(X2,Obj.Shell.X2);Y2:=Max(Y2,Obj.Shell.Y2);
    End;
  end;
  Result:='X='+FloatToStr((X1+X2)/2)+'&Y='+FloatToStr((Y1+Y2)/2)+
         '&A='+FloatToStr(Scene.Drawer.ViewAngle)+'&S='+FloatToStr(Scene.Drawer.ViewScale);
End;

Function ComputeItemZoomDST(ItemName:String):String;
Var ObjName,S:String;
    Curl:TVCurl;
    Obj:TVObject;
    Conn:TVConnection;
    Callout:TVCallout;
    I,J,N:Longint;
    X1,X2,Y1,Y2:Extended;
begin
  X1:=+MaxExtended;X2:=-MaxExtended;
  Y1:=+MaxExtended;Y2:=-MaxExtended;
  N:=Scene.VCurlList.IndexOf(ItemName);
  If N>=0 Then Begin
    Curl:=Scene.VCurlList.Objects[N] As TVcurl;
    X1:=Min(X1,Curl.Shell.X1);Y1:=Min(Y1,Curl.Shell.Y1);
    X2:=Max(X2,Curl.Shell.X2);Y2:=Max(Y2,Curl.Shell.Y2);
  End;
  N:=Scene.VObjectList.IndexOf(ItemName);
  If N>=0 Then Begin
    Obj:=Scene.VObjectList.Objects[N] As TVObject;
    X1:=Min(X1,Obj.Shell.X1);Y1:=Min(Y1,Obj.Shell.Y1);
    X2:=Max(X2,Obj.Shell.X2);Y2:=Max(Y2,Obj.Shell.Y2);
  End;
  N:=Scene.VConnectionList.IndexOf(ItemName);
  If N>=0 Then Begin
    Conn:=Scene.VObjectList.Objects[N] As TVConnection;
    X1:=Min(X1,Conn.Shell.X1);Y1:=Min(Y1,Conn.Shell.Y1);
    X2:=Max(X2,Conn.Shell.X2);Y2:=Max(Y2,Conn.Shell.Y2);
  End;
  N:=Scene.VCalloutList.IndexOf(ItemName);
  If N>=0 Then Begin
    Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
    X1:=Min(X1,Callout.Shell.X1);Y1:=Min(Y1,Callout.Shell.Y1);
    X2:=Max(X2,Callout.Shell.X2);Y2:=Max(Y2,Callout.Shell.Y2);
  End;
  S:='X='+FloatToStr((X1+X2)/2)+'&Y='+FloatToStr((Y1+Y2)/2)+'&A='+FloatToStr(Scene.Drawer.ViewAngle);
  If (X2-X1)/Scene.Drawer.Wx > (Y2-Y1)/Scene.Drawer.Wy
  Then Result:=S+'&S='+FloatToStr((X2-X1)*1.500/Scene.Drawer.Wx)
  Else Result:=S+'&S='+FloatToStr((Y2-Y1)*1.500/Scene.Drawer.Wy);
End;

Function ComputeSelectionZoomDST:String;
Var ObjName,S:String;
    Obj:TVObject;
    Callout:TVCallout;
    Connection:TVConnection;
    Curl:TVCurl;
    I,J,N:Longint;
    X1,X2,Y1,Y2:Extended;
begin
  X1:=+MaxExtended;X2:=-MaxExtended;
  Y1:=+MaxExtended;Y2:=-MaxExtended;
  If Scene.SelectedList.Count<=0 Then Exit;
  For I:=0 To Scene.SelectedList.Count-1 Do Begin
    If Scene.SelectedList.Objects[I] is TVCurl Then Begin
      Curl:=Scene.SelectedList.Objects[I] As TVCurl;
      X1:=Min(X1,Curl.Shell.X1);Y1:=Min(Y1,Curl.Shell.Y1);
      X2:=Max(X2,Curl.Shell.X2);Y2:=Max(Y2,Curl.Shell.Y2);
    end;
    If Scene.SelectedList.Objects[I] is TVConnection Then Begin
      Connection:=Scene.SelectedList.Objects[I] As TVConnection;
      X1:=Min(X1,Connection.Shell.X1);Y1:=Min(Y1,Connection.Shell.Y1);
      X2:=Max(X2,Connection.Shell.X2);Y2:=Max(Y2,Connection.Shell.Y2);
    end;
    If Scene.SelectedList.Objects[I] is TVCallout Then Begin
      Callout:=Scene.SelectedList.Objects[I] As TVCallout;
      X1:=Min(X1,Callout.Shell.X1);Y1:=Min(Y1,Callout.Shell.Y1);
      X2:=Max(X2,Callout.Shell.X2);Y2:=Max(Y2,Callout.Shell.Y2);
    end;
    If Scene.SelectedList.Objects[I] is TVObject Then Begin
      Obj:=Scene.SelectedList.Objects[I] As TVObject;
      X1:=Min(X1,Obj.Shell.X1);Y1:=Min(Y1,Obj.Shell.Y1);
      X2:=Max(X2,Obj.Shell.X2);Y2:=Max(Y2,Obj.Shell.Y2);
    End;
  end;
  If (X2-X1)/Scene.Drawer.Wx > (Y2-Y1)/Scene.Drawer.Wy
  Then  Form1.ViewScaleEdit.Value:=(X2-X1)*1.01001/Scene.Drawer.Wx
  Else  Form1.ViewScaleEdit.Value:=(Y2-Y1)*1.01001/Scene.Drawer.Wy;
  S:='X='+FloatToStr((X1+X2)/2)+'&Y='+FloatToStr((Y1+Y2)/2)+'&A='+FloatToStr(Scene.Drawer.ViewAngle);
  If (X2-X1)/Scene.Drawer.Wx > (Y2-Y1)/Scene.Drawer.Wy
  Then Result:=S+'&S='+FloatToStr((X2-X1)*1.01001/Scene.Drawer.Wx)
  Else Result:=S+'&S='+FloatToStr((Y2-Y1)*1.01001/Scene.Drawer.Wy);
End;

Procedure ReloadSource(Scene:TVScene;Name:String);
Var Callout:TVCallout;
    Obj:TVObject;
    I:Longint;
    StrToLinesBuffer:TStringList;
Begin
  If GetTypeByName(Scene,Name)='object' Then Begin
     I:=Scene.VObjectList.IndexOf(Name);
     If I>=0 Then Begin
       Obj:=Scene.VObjectList.Objects[I] As TVObject;
       //обновление, если объект - контейнтер
       If (Obj.A=720+3*360)Or(Obj.A=720+4*360) Then Begin
         UpdateCacheItem(Obj.Source);
       End;
       If Obj.RelatedCAList.Count>0 Then Begin
         For I:=0 To Obj.RelatedCAList.Count-1 Do Begin
           ReloadSource(Scene,Obj.RelatedCAList[I]);
         end;
       end;
     End;
  end;
  If GetTypeByName(Scene,Name)='callout' Then Begin
    I:=Scene.VCalloutList.IndexOf(Name);
    If I>=0 Then Begin
      Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
      If Callout.Source<>'' Then Begin
        StrToLinesBuffer:=TStringList.Create;
//        StrToLinesBuffer.Text:=(Dispatcher.ExecCommand(Callout.Source));
        LoadTextFromURL(Callout.Source,StrToLinesBuffer);
        Callout.Text:=StrToLinesBuffer.CommaText;
        Scene.UpdateCalloutDisplayList(Callout);
        StrToLinesBuffer.Free;
      end;
    end;
  end;
end;

Procedure UpdateAll;
Var I:Longint;
    Callout:TVCallout;
    Obj:TVObject;
Begin
  If Scene.VCalloutList.Count>0 Then
    For I:=0 To Scene.VCalloutList.Count-1 Do Begin
      Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
      If Callout.Source<>'' Then
        Dispatcher.QueueCommand('self::CAD_ReloadSource:'+Callout.Name);
//      ReloadSource(Scene,Callout.Name);
    end;
  If Scene.VObjectList.Count>0 Then
    For I:=0 To Scene.VObjectList.Count-1 Do Begin
      Obj:=Scene.VObjectList.Objects[I] As TVObject;
      If Obj.Source<>'' Then
        Dispatcher.QueueCommand('self::CAD_ReloadSource:'+Obj.Name);
      //ReloadSource(Scene,Obj.Name);
    end;
  Dispatcher.QueueCommand('self::CAD_UpdateDraw');
end;

Procedure FixAll;
Var I:Longint;
    Callout:TVCallout;
    Obj:TVObject;
Begin
  If Scene.VCalloutList.Count>0 Then
    For I:=0 To Scene.VCalloutList.Count-1 Do Begin
      Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
        Dispatcher.ExecCommand('self::CAD_FixItem:'+Callout.Name);
    end;
  If Scene.VObjectList.Count>0 Then
    For I:=0 To Scene.VObjectList.Count-1 Do Begin
      Obj:=Scene.VObjectList.Objects[I] As TVObject;
        Dispatcher.ExecCommand('self::CAD_FixItem:'+Obj.Name);
    end;
end;


procedure LoadTemplateFile(TemplateFileName:String);  //Loading Template from directly pointed path
Var I,N:Longint;Template:TVTemplate;
    AccObject:TAccObject;
    B,ext,Name,SubTemplateName,SubTemplateFileName,Cmd,Buf,ParsedBuf:String;
    E:TMatrix2D;
Begin
  Template:=TVTemplate.Create;
  Template.DisplayList.LoadFromFile(TemplateFileName);
  If Template.DisplayList.Count>0 Then
    For N:=0 To Template.DisplayList.Count-1 Do Begin
      Cmd:=Template.DisplayList[N];
      If Pos('DrawTemplate',Cmd)=1 Then Begin//loading recursive templates
        GetNextToken(Cmd,ParsedBuf,' ');
        Buf:=ParsedBuf;
        SubTemplateName:=GetNextToken(Buf,ParsedBuf,' ');
        If Form1.TemplateList.Items.IndexOf(SubTemplateName)<0 Then Begin
          SubTemplateFileName:=FindInSubDir(OSPath(ConfigFile.Values['TemplateDir']),SubTemplateName);
          If SubTemplateFileName<>'' Then LoadTemplateFile(SubTemplateFileName);
        end;
      End;
      AccObject:=TAccObject.Create;
      AccObject.AcceleratedCommand:=AccelerateCommand(Template.DisplayList[N]);
      Template.DisplayList.Objects[N]:=AccObject;
    end;
  Ext:=ExtractFileExt(TemplateFileName);
  Name:=ExtractFileName(TemplateFileName);
  Template.Name:=Copy(Name,1,
                      Length(Name)
                     -Length(Ext));
  Scene.VTemplateList.AddObject(Template.Name,Template);
  E:=GenShift(0,0);
  Template.Shell:=Scene.RenderShell(Template.DisplayList,E);
  Form1.TemplateList.Items.Add(Template.Name);
End;

procedure LoadTemplate(TemplateName:String);  //loading template by it's name, path to file is guessed considering relative library
Var I,N:Longint;Template:TVTemplate;
    AccObject:TAccObject;
    B,ext,Name,TemplateFileName,SubTemplateName,SubTemplateFileName,Cmd,Buf,ParsedBuf:String;
    E:TMatrix2D;
    Loaded:Boolean;
Begin
  Template:=TVTemplate.Create;
  Loaded:=False;
  Case DocumentProto Of
  'file://': Begin
               If FileExists(OSPath(DocumentPath+'/library')) Then Begin
                 If FileExists(OSPath(DocumentPath+'/library/'+TemplateName+'.tpg')) Then Begin
                   Template.DisplayList.LoadFromFile(OSPath(DocumentPath+'/library/'+TemplateName+'.tpg'));
                   Loaded:=True;
                 End;
               End;
               If Not Loaded Then Begin
                 TemplateFileName:=FindInSubDir(OSPath(ConfigFile.Values['TemplateDir']),TemplateName);
                 If TemplateFileName<>'' Then Begin
                   Template.DisplayList.LoadFromFile(TemplateFileName);
                   Loaded:=True;
                 End;
               End;
             End;
  'http://': Begin
               If LoadTextFromURL('http://'+DocumentPath+'/library/'+TemplateName+'.tpg',Template.DisplayList) Then
                 Loaded:=True;
               If Not Loaded Then Begin
                 TemplateFileName:=FindInSubDir(OSPath(ConfigFile.Values['TemplateDir']),TemplateName);
                 If TemplateFileName<>'' Then Begin
                   Template.DisplayList.LoadFromFile(TemplateFileName);
                   Loaded:=True;
                 End;
               End;

             End;
  End;
  If Not Loaded Then Exit;
  If Template.DisplayList.Count>0 Then
    For N:=0 To Template.DisplayList.Count-1 Do Begin
      Cmd:=Template.DisplayList[N];
      If Pos('DrawTemplate',Cmd)=1 Then Begin//loading recursive templates
        GetNextToken(Cmd,ParsedBuf,' ');
        Buf:=ParsedBuf;
        SubTemplateName:=GetNextToken(Buf,ParsedBuf,' ');
        If Form1.TemplateList.Items.IndexOf(SubTemplateName)<0 Then Begin
          LoadTemplate(SubTemplateName);
        end;
      End;
      AccObject:=TAccObject.Create;
      AccObject.AcceleratedCommand:=AccelerateCommand(Template.DisplayList[N]);
      Template.DisplayList.Objects[N]:=AccObject;
    end;
{  Ext:=ExtractFileExt(TemplateFileName);
  Name:=ExtractFileName(TemplateFileName);
  Template.Name:=Copy(Name,1,
                      Length(Name)
                     -Length(Ext));
                     }
  Template.Name:=TemplateName;
  Scene.VTemplateList.AddObject(Template.Name,Template);
  E:=GenShift(0,0);
  Template.Shell:=Scene.RenderShell(Template.DisplayList,E);
  Form1.TemplateList.Items.Add(Template.Name);
End;

Function ExpandURL(ShortURL:String):String;
Var Proto,Path,Name:String;
Begin
  Path:=ExtractFilePath(ShortURL);
  Name:=ExtractFileName(ShortURL);
  If Pos('://',Path)=0 Then Begin
    Result:=DocumentProto+DocumentPath+Path+Name;
  End Else Begin
    Proto:=Copy(Path,1,Pos('://',Path)+2);
    Delete(Path,1,Pos('://',Path)+2);
    If Proto='file://' Then Begin
      {$IFDEF LINUX}
        If Pos('/',Path)=1 Then
      {$ELSE}
        If Pos(':',Path)=2 Then
      {$ENDIF}
        // абсолютный путь
        Result:=Proto+Path+Name
      Else
        //относительный путь
        If DocumentPath='' Then Result:=Proto+OSPath(GetCurrentDir+'/'+Name) //относительно рабочей директории
        Else Result:=Proto+OSPath(DocumentPath+'/'+Path+Name); //относительно загруженного документа
    End;
    If Proto='http://' Then Begin
      Result:=Proto+Path+Name; //относительно загруженного документа
    End;
  End;
End;


Function LoadTextFromURL(URL:String;S:TStringList):Boolean;
Var Proto,Path,Name:String;
    HTTP: THTTPSend;
Begin
  Path:=ExtractFilePath(URL);
  Name:=ExtractFileName(URL);
  Proto:=Copy(Path,1,Pos('://',Path)+2);
  Delete(Path,1,Pos('://',Path)+2);
  Case Proto Of
  'file://': Begin
               Try
                 S.LoadFromFile(Path+Name);
                 Result:=True;
               Except
                 Result:=False;
               end;
             End;
  'http://': Begin
               HTTP:=THTTPSend.Create;
               If HTTPURLForm<>Nil Then Begin
                 If HTTPUrlForm.ProxyServerEdit.Text<>'' Then Begin
                   HTTP.ProxyHost:=HTTPUrlForm.ProxyServerEdit.Text;
                   HTTP.ProxyPort:=HTTPUrlForm.ProxyPortEdit.Text;
                 End;
               End;
               Try
                 If Not HTTP.HTTPMethod('GET', URL) Then Begin
                    LogMessage(1,'Error retrieving '+URL+' '+IntToStr(HTTP.Resultcode));
                    Result:=False;
                 End Else Begin
        {writeln(Http.Resultcode, ' ', Http.Resultstring);
        writeln(Http.headers.text);}
                   S.LoadFromStream(HTTP.Document);
                   Result:=True;
                 end;
               Finally
                 HTTP.Free;
               End;
             End;
  'exec://': Begin
               S.Text:=Dispatcher.ExecShellCmd(Path+Name);
//               Dispatcher.ExecCommand(Callout.Source);
             End;
  End;
End;

Procedure LoadImageFromURL(URL:String;Var Picture:TPicture);
Var Proto,Path,Name:String;
    HTTP: THTTPSend;
Begin
  Path:=ExtractFilePath(URL);
  Name:=ExtractFileName(URL);
  Proto:=Copy(Path,1,Pos('://',Path)+2);
  Delete(Path,1,Pos('://',Path)+2);
  Case Proto Of
  'file://': Begin
               If FileExists(Path+Name) Then
                 Try Picture.LoadFromFile(Path+Name);
                 finally
                 end;
             End;
  'http://': Begin
               HTTP:=THTTPSend.Create;
               If HTTPURLForm<>Nil Then Begin
                 If HTTPUrlForm.ProxyServerEdit.Text<>'' Then Begin
                   HTTP.ProxyHost:=HTTPUrlForm.ProxyServerEdit.Text;
                   HTTP.ProxyPort:=HTTPUrlForm.ProxyPortEdit.Text;
                 End;
               End;
               Try
                 If Not HTTP.HTTPMethod('GET', URL) Then Begin
                   LogMessage(1,'Error retrieving '+URL+' '+IntToStr(HTTP.Resultcode));
                 End Else Begin
                   Picture.LoadFromStream(HTTP.Document);
                 end;
               Finally
                 HTTP.Free;
               End;
             End;
  'exec://': Begin
             End;
  End;
End;


Procedure LoadDocument(DocumentURL:String);
Var I,J,N:Longint;
    Obj:TVObject;Template:TVTemplate;
    Port:TVPort;Conn:TVConnection;
    VGroup:TVGroup;Callout:TVCallout;
    AccObject:TAccObject;
    Cmd,TemplateName,TemplateFileName,Buf,ParsedBuf:String;
    NumTemplatesBefore,NumTemplatesAfter:Longint;
    E,Sm,Rm,Scm,tmpm,TransM:TMatrix2D;
    Proto,Path,Name:String;
    FileBuffer:TStringList;
Begin
    DocumentURL:=ExpandURL(DocumentURL);
    Path:=ExtractFilePath(DocumentURL);
    Name:=ExtractFileName(DocumentURL);
    DocumentProto:=Copy(Path,1,Pos('://',Path)+2);
    Delete(Path,1,Pos('://',Path)+2);
    DocumentPath:=Path;
    FileBuffer:=TStringList.Create;
    LoadTextFromURL(DocumentURL,FileBuffer);
    Scene.LoadFile(FileBuffer);
    FileBuffer.Free;
    If Scene.VObjectList.Count>0 Then
      For I:=0 To Scene.VObjectList.Count-1 Do Begin
        Obj:=Scene.VObjectList.Objects[I] As TVObject;
        If Obj.DisplayList.Count>0 Then
          For J:=0 To Obj.DisplayList.Count-1 Do Begin
            //look for DrawTemplate
            Buf:=Obj.DisplayList[J];
            Cmd:=GetNextToken(Buf,ParsedBuf,' ');
            Buf:=ParsedBuf;
            If LowerCase(Cmd)='drawtemplate' Then Begin
              TemplateName:=GetNextToken(Buf,ParsedBuf,' ');
              If Form1.TemplateList.Items.IndexOf(TemplateName)<0 Then Begin
                LoadTemplate(TemplateName);
{                TemplateFileName:=FindInSubDir(OSPath(ConfigFile.Values['TemplateDir']),TemplateName);
                If TemplateFileName<>'' Then LoadTemplate(OSPath(TemplateFileName)) Else ShowMessage('Can''t find template file for '+TemplateName);// search}
              end;
            End;
          End;
      End;
    Repeat //парсим темплейты пока не перестанут загружаться новые
      NumTemplatesBefore:=Form1.TemplateList.Count;
      If Scene.VTemplateList.Count>0 Then
        For I:=0 To Scene.VTemplateList.Count-1 Do Begin
        Template:=Scene.VTemplateList.Objects[I] As TVTemplate;
        If Template.DisplayList.Count>0 Then
          For J:=0 To Template.DisplayList.Count-1 Do Begin
            //look for DrawTemplate
            Buf:=Template.DisplayList[J];
            Cmd:=GetNextToken(Buf,ParsedBuf,' ');
            Buf:=ParsedBuf;
            If LowerCase(Cmd)='drawtemplate' Then Begin
              TemplateName:=GetNextToken(Buf,ParsedBuf,' ');
              If Form1.TemplateList.Items.IndexOf(TemplateName)<0 Then Begin
                LoadTemplate(TemplateName);
{                TemplateFileName:=FindInSubDir(OSPath(ConfigFile.Values['TemplateDir']),TemplateName);
                If TemplateFileName<>'' Then LoadTemplate(OSPath(TemplateFileName))  Else ShowMessage('Can''t find template file for '+TemplateName);// search}
              end;
            End;
          End;
      End;
      NumTemplatesAfter:=Form1.TemplateList.Count;
    Until NumTemplatesBefore=NumTemplatesAfter;
    //пересчитать оболочки и добавить отрисовку портов в дисплейные списки
    If Scene.VObjectList.Count>0 Then
      For I:=0 To Scene.VObjectList.Count-1 Do Begin
        Obj:=Scene.VObjectList.Objects[I] As TVObject;
        If Obj.DisplayList.Count=0 Then Begin
          //Shell пустого объекта = точке вставки?
          Obj.Shell.X1:=Obj.X;
          Obj.Shell.X2:=Obj.X;
          Obj.Shell.Y1:=Obj.Y;
          Obj.Shell.Y2:=Obj.Y;
        End Else Begin
          Scene.RenderObjectShell(Obj);
          If Obj.PortList.Count>0 Then
            For J:=0 To Obj.PortList.Count-1 Do Begin
              Port:=Obj.PortList.Objects[J] As TVPort;
              If Not InfiniteShell(Obj.Shell) Then Begin
                If Port.AR='A' Then Begin
                  Port.X:=(Port.AX-Obj.Shell.X1)/(Obj.Shell.X2-Obj.Shell.X1);
                  Port.Y:=(Port.AY-Obj.Shell.Y1)/(Obj.Shell.Y2-Obj.Shell.Y1);
                End Else Begin
                  Port.AX:=Obj.Shell.X1+Port.X*(Obj.Shell.X2-Obj.Shell.X1);
                  Port.AY:=Obj.Shell.Y1+Port.Y*(Obj.Shell.Y2-Obj.Shell.Y1);
                End;
              End;
              //Добавление портов в DisplayList
              AccObject:=TAccObject.Create;
              AccObject.AcceleratedCommand:=AccelerateCommand('UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone));
              Obj.DisplayList.AddObject('UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone),AccObject);
            end;
        End;
      end;
    //после пересчета координат портов можно пересчитывать координаты связей
    If Scene.VConnectionList.Count>0 Then
      For I:=0 To Scene.VConnectionList.Count-1 Do Begin
        Conn:=Scene.VConnectionList.Objects[I] As TVConnection;
        Conn.DisplayList.Clear;
        Scene.UpdateConnectionDisplayList(Conn);
      end;
    //после пересчета оболочек объектов можно пересчитывать координаты выносов и создавать списки связанных
    If Scene.VCalloutList.Count>0 Then
      For I:=0 To Scene.VCalloutList.Count-1 Do Begin
        Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
        If Callout.RelatedObj<>'' Then Begin
          N:=Scene.VObjectList.IndexOf(Callout.RelatedObj);
          If N>=0 Then Begin
            Obj:=Scene.VObjectList.Objects[N] As TVObject;
           ///////// dup? Obj.RelatedCAList.AddObject(Callout.Name,Callout);
          End;
        End;
        Scene.UpdateCalloutDisplayList(Callout);
      end;
    //Если есть источник, но нет текста - надо перечитать источники
    If Scene.VCalloutList.Count>0 Then
          For I:=0 To Scene.VCalloutList.Count-1 Do Begin
            Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
            If (Callout.Text='') And (Callout.Source<>'') Then Begin
              ReloadSource(Scene,Callout.Name);
            End;
            Scene.UpdateCalloutDisplayList(Callout);
          end;
{    //построение групп
    If Scene.VGroupList.Count>0 Then
      For I:=0 To Scene.VGroupList.Count-1 Do Begin
        VGroup:=Scene.VGroupList.Objects[I] As TVGroup;
        If VGroup.DisplayList.Count>0 Then
          For J:=0 To VGroup.DisplayList.Count-1 Do Begin
            N:=Scene.VObjectList.IndexOf(VGroup.DisplayList[J]);
            If N>=0 Then Begin
              Obj:=Scene.VObjectList.Objects[N] As TVObject;
              Obj.GroupList.AddObject(VGroup.Name,VGroup);
            end;
            N:=Scene.VConnectionList.IndexOf(VGroup.DisplayList[J]);
            If N>=0 Then Begin
              Conn:=Scene.VConnectionList.Objects[N] As TVConnection;
              Conn.GroupList.AddObject(VGroup.Name,VGroup);
            end;
          end;
      end;    }
    Dispatcher.ExecCommand('self::CAD_UpdateScale');
    Dispatcher.ExecCommand('self::CAD_Scene2GUI');
    Dispatcher.ExecCommand('self::CAD_UpdateDraw');
    //scene2gui
end;

Procedure GoToBookMark(Addr:String);
Var Buf,ParsedBuf,url,path,coord,proto,server:String;
    FileName,KeyVal,Key,Val,x,y,a,s:String;
    XV,YV,AV,SV:Extended;
    ObjName:String;
    Curl:TVCurl;
    Obj:TVObject;
    Conn:TVConnection;
    Callout:TVCallout;
    I,J,N:Longint;
    X1,X2,Y1,Y2:Extended;
begin
 //file://DocumentName?X=0&Y=0&A=0&S=1&N=objectname
   ObjName:='';X:='';Y:='';A:='';S:='';
   If Pos('?',Addr)<>0 Then Begin
     // надо загружать новый документ
     url:=GetNextToken(Addr,Coord,'?');
     proto:=GetNextToken(url,path,'://');
     Case Proto of
     'file': Begin
               FileName:=path;
               If FileName<>DocumentName Then Begin
                 LoadDocument(FileName);
                 Form1.Caption:=TitleString+' '+FileName;
               end;
             End;
     'http': Begin
               ShowMessage('remote sources not implemented yet in '+Addr);Exit;
             End;
     End;
   end Else Begin
     // нет протокола и документа - навигация внутри этого документа
     Coord:=Addr;
   End;
   Buf:=Coord;
   Repeat
     KeyVal:=GetNextToken(Buf,ParsedBuf,'&');
     Buf:=ParsedBuf;
     Key:=GetNextToken(KeyVal,Val,'=');
     Case Key Of
     'X': Begin
            X:=Val;
            If Not TryStrToFloat(Val,XV) Then Begin
            ShowMessage('Wrong X in address:'+Addr);Exit;
          End;End;
     'Y': Begin
            Y:=Val;
            If Not TryStrToFloat(Val,YV) Then Begin
            ShowMessage('Wrong Y in address:'+Addr);Exit;
          End;End;
     'A': Begin
            A:=Val;
            If Not TryStrToFloat(Val,AV) Then Begin
            ShowMessage('Wrong A in address:'+Addr);Exit;
          End;End;
     'S': Begin
            S:=Val;
            If Not TryStrToFloat(Val,SV) Then Begin
            ShowMessage('Wrong S in address:'+Addr);Exit;
          End;End;
     'N': ObjName:=Val;
     end;
   Until KeyVal='';
   BasisChanging:=True;
   If ObjName<>'' Then Begin
     X1:=+MaxExtended;X2:=-MaxExtended;
     Y1:=+MaxExtended;Y2:=-MaxExtended;
     N:=Scene.VCurlList.IndexOf(ObjName);
     If N>=0 Then Begin
       Curl:=Scene.VCurlList.Objects[N] As TVCurl;
       X1:=Min(X1,Curl.Shell.X1);Y1:=Min(Y1,Curl.Shell.Y1);
       X2:=Max(X2,Curl.Shell.X2);Y2:=Max(Y2,Curl.Shell.Y2);
     End;
     N:=Scene.VObjectList.IndexOf(ObjName);
     If N>=0 Then Begin
       Obj:=Scene.VObjectList.Objects[N] As TVObject;
       X1:=Min(X1,Obj.Shell.X1);Y1:=Min(Y1,Obj.Shell.Y1);
       X2:=Max(X2,Obj.Shell.X2);Y2:=Max(Y2,Obj.Shell.Y2);
     End;
     N:=Scene.VConnectionList.IndexOf(ObjName);
     If N>=0 Then Begin
       Conn:=Scene.VObjectList.Objects[N] As TVConnection;
       X1:=Min(X1,Conn.Shell.X1);Y1:=Min(Y1,Conn.Shell.Y1);
       X2:=Max(X2,Conn.Shell.X2);Y2:=Max(Y2,Conn.Shell.Y2);
     End;
     N:=Scene.VCalloutList.IndexOf(ObjName);
     If N>=0 Then Begin
       Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
       X1:=Min(X1,Callout.Shell.X1);Y1:=Min(Y1,Callout.Shell.Y1);
       X2:=Max(X2,Callout.Shell.X2);Y2:=Max(Y2,Callout.Shell.Y2);
     End;
     Form1.ViewXEdit.Value:=(X1+X2)/2;
     Form1.ViewYEdit.Value:=(Y1+Y2)/2;
     If (X2-X1)/Scene.Drawer.Wx > (Y2-Y1)/Scene.Drawer.Wy
     Then Form1.ViewScaleEdit.Value:=(X2-X1)*1.01001/Scene.Drawer.Wx
     Else Form1.ViewScaleEdit.Value:=(Y2-Y1)*1.01001/Scene.Drawer.Wy;
   end;
   If X<>'' Then Form1.ViewXEdit.Value:=XV;
   If Y<>'' Then Form1.ViewYEdit.Value:=YV;
   If A<>'' Then Form1.ViewAngleEdit.Value:=AV;
   If S<>'' Then Form1.ViewScaleEdit.Value:=SV;
   Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
   BasisChanging:=False;
   JustDrawing:=True;
End;

Procedure HoverToBookMark(Steps:Longint;Addr:String);
Var Buf,ParsedBuf,url,path,coord,proto,server:String;
    FileName,KeyVal,Key,Val,x,y,a,s:String;
    XV,YV,AV,SV,Xst,Xe,Yst,Ye,Ast,Ae,Sst,Se:Extended;
    ObjName:String;
    Curl:TVCurl;
    Obj:TVObject;
    Conn:TVConnection;
    Callout:TVCallout;
    I,J,N:Longint;
    X1,X2,Y1,Y2:Extended;
begin
   //X=0&Y=0&A=0&S=1&N=objectname
   // есть протокол и документ, и он отличается от текущего - загружаем
   // нет протокола и документа - навигация внутри этого документа
   If Pos('?',Addr)<>0 Then Begin
     url:=GetNextToken(Addr,Coord,'?');
     proto:=GetNextToken(url,path,'://');
     Case Proto of
     'file': Begin
               FileName:=path;
               If FileName<>DocumentName Then Begin
                 LoadDocument(FileName);
                 Form1.Caption:=TitleString+' '+FileName;
               end;
             End
     else Begin ShowMessage('remote sources not implemented yet in '+Addr);Exit;End;;
     End;
   End Else Coord:=Addr;
   ObjName:='';X:='';Y:='';A:='';S:='';

   Buf:=Coord;
   Xst:=Form1.ViewXEdit.Value;
   Yst:=Form1.ViewYEdit.Value;
   Ast:=Form1.ViewAngleEdit.Value;
   Sst:=Form1.ViewScaleEdit.Value;
   Ae:=Ast;
   Se:=Sst;
   Repeat
     KeyVal:=GetNextToken(Buf,ParsedBuf,'&');
     Buf:=ParsedBuf;
     Key:=GetNextToken(KeyVal,Val,'=');
     Case Key Of
     'X': Begin
            X:=Val;
            If Not TryStrToFloat(Val,Xe) Then Begin
            ShowMessage('Wrong X in address:'+Addr);Exit;
          End;End;
     'Y': Begin
            Y:=Val;
            If Not TryStrToFloat(Val,Ye) Then Begin
            ShowMessage('Wrong Y in address:'+Addr);Exit;
          End;End;
     'A': Begin
            A:=Val;
            If Not TryStrToFloat(Val,Ae) Then Begin
            ShowMessage('Wrong A in address:'+Addr);Exit;
          End;End;
     'S': Begin
            S:=Val;
            If Not TryStrToFloat(Val,Se) Then Begin
            ShowMessage('Wrong S in address:'+Addr);Exit;
          End;End;
     'N': ObjName:=Val;
     end;
   Until KeyVal='';
   If ObjName<>'' Then Begin
     X1:=+MaxExtended;X2:=-MaxExtended;
     Y1:=+MaxExtended;Y2:=-MaxExtended;
     N:=Scene.VCurlList.IndexOf(ObjName);
     If N>=0 Then Begin
       Curl:=Scene.VCurlList.Objects[N] As TVCurl;
       X1:=Min(X1,Curl.Shell.X1);Y1:=Min(Y1,Curl.Shell.Y1);
       X2:=Max(X2,Curl.Shell.X2);Y2:=Max(Y2,Curl.Shell.Y2);
     End;
     N:=Scene.VObjectList.IndexOf(ObjName);
     If N>=0 Then Begin
       Obj:=Scene.VObjectList.Objects[N] As TVObject;
       X1:=Min(X1,Obj.Shell.X1);Y1:=Min(Y1,Obj.Shell.Y1);
       X2:=Max(X2,Obj.Shell.X2);Y2:=Max(Y2,Obj.Shell.Y2);
     End;
     N:=Scene.VConnectionList.IndexOf(ObjName);
     If N>=0 Then Begin
       Conn:=Scene.VObjectList.Objects[N] As TVConnection;
       X1:=Min(X1,Conn.Shell.X1);Y1:=Min(Y1,Conn.Shell.Y1);
       X2:=Max(X2,Conn.Shell.X2);Y2:=Max(Y2,Conn.Shell.Y2);
     End;
     N:=Scene.VCalloutList.IndexOf(ObjName);
     If N>=0 Then Begin
       Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
       X1:=Min(X1,Callout.Shell.X1);Y1:=Min(Y1,Callout.Shell.Y1);
       X2:=Max(X2,Callout.Shell.X2);Y2:=Max(Y2,Callout.Shell.Y2);
     End;
     Xe:=(X1+X2)/2;
     Ye:=(Y1+Y2)/2;
     If (X2-X1)/Scene.Drawer.Wx > (Y2-Y1)/Scene.Drawer.Wy
     Then Se:=(X2-X1)*1.01001/Scene.Drawer.Wx
     Else Se:=(Y2-Y1)*1.01001/Scene.Drawer.Wy;
   end;

   For I:=1 To Steps Do Begin
     Xv:=Xst+(Xe-Xst)*I/(Steps);
     Yv:=Yst+(Ye-Yst)*I/(Steps);
     Av:=Ast+(Ae-Ast)*I/(Steps);
     Sv:=Sst+(Se-Sst)*I/(Steps);
     Drawer.ViewX:=Xv;
     Drawer.ViewY:=Yv;
     Drawer.ViewScale:=Sv;
     Drawer.ViewAngle:=Av/180*pi;
     Drawer.Wx:=Form1.DrawingPanel.Width;
     Drawer.Wy:=Form1.DrawingPanel.Height;
     Drawer.RecalcMatrix;
     UpdateScreenShell(Drawer);
     Scene.UpdateVisibility;
     Drawer.Updated:=True;
     Drawer.Canvas:=Form1.DrawingPanel.Canvas;
     DrawScene(Drawer,True);//!!!! true-false
     Form1.DrawingPanel.Refresh;
   end;
   BasisChanging:=True;
   Form1.ViewXEdit.Value:=XV;
   Form1.ViewYEdit.Value:=YV;
   Form1.ViewAngleEdit.Value:=AV;
   Form1.ViewScaleEdit.Value:=SV;
   BasisChanging:=False;
   JustDrawing:=True;
End;

Procedure FlyToBookMark(Steps:Longint;Addr:String);
//ToDo: implement flying instead of hovering
Var Buf,ParsedBuf,url,path,coord,proto,server:String;
    FileName,KeyVal,Key,Val,x,y,a,s:String;
    XV,YV,AV,SV,Xst,Xc,Xe,Yst,Yc,Ye,Ast,Ac,Ae,Sst,Sc,Se:Extended;
    ObjName:String;
    Curl:TVCurl;
    Obj:TVObject;
    Conn:TVConnection;
    Callout:TVCallout;
    I,J,N:Longint;
    X1,X2,Y1,Y2:Extended;
begin
   //X=0&Y=0&A=0&S=1&N=objectname
   // есть протокол и документ, и он отличается от текущего - загружаем
   // нет протокола и документа - навигация внутри этого документа
   If Pos('?',Addr)<>0 Then Begin
     url:=GetNextToken(Addr,Coord,'?');
     proto:=GetNextToken(url,path,'://');
     Case Proto of
     'file': Begin
               FileName:=path;
               If FileName<>DocumentName Then Begin
                 LoadDocument(FileName);
                 Form1.Caption:=TitleString+' '+FileName;
               end;
             End
     else Begin ShowMessage('remote sources not implemented yet in '+Addr);Exit;End;;
     End;
   End Else Coord:=Addr;
   ObjName:='';X:='';Y:='';A:='';S:='';

   Buf:=Coord;
   Xst:=Form1.ViewXEdit.Value;
   Yst:=Form1.ViewYEdit.Value;
   Ast:=Form1.ViewAngleEdit.Value;
   Sst:=Form1.ViewScaleEdit.Value;
   Ae:=Ast;
   Se:=Sst;
   Repeat
     KeyVal:=GetNextToken(Buf,ParsedBuf,'&');
     Buf:=ParsedBuf;
     Key:=GetNextToken(KeyVal,Val,'=');
     Case Key Of
     'X': Begin
            X:=Val;
            If Not TryStrToFloat(Val,Xe) Then Begin
            ShowMessage('Wrong X in address:'+Addr);Exit;
          End;End;
     'Y': Begin
            Y:=Val;
            If Not TryStrToFloat(Val,Ye) Then Begin
            ShowMessage('Wrong Y in address:'+Addr);Exit;
          End;End;
     'A': Begin
            A:=Val;
            If Not TryStrToFloat(Val,Ae) Then Begin
            ShowMessage('Wrong A in address:'+Addr);Exit;
          End;End;
     'S': Begin
            S:=Val;
            If Not TryStrToFloat(Val,Se) Then Begin
            ShowMessage('Wrong S in address:'+Addr);Exit;
          End;End;
     'N': ObjName:=Val;
     end;
   Until KeyVal='';
   If ObjName<>'' Then Begin
     X1:=+MaxExtended;X2:=-MaxExtended;
     Y1:=+MaxExtended;Y2:=-MaxExtended;
     N:=Scene.VCurlList.IndexOf(ObjName);
     If N>=0 Then Begin
       Curl:=Scene.VCurlList.Objects[N] As TVCurl;
       X1:=Min(X1,Curl.Shell.X1);Y1:=Min(Y1,Curl.Shell.Y1);
       X2:=Max(X2,Curl.Shell.X2);Y2:=Max(Y2,Curl.Shell.Y2);
     End;
     N:=Scene.VObjectList.IndexOf(ObjName);
     If N>=0 Then Begin
       Obj:=Scene.VObjectList.Objects[N] As TVObject;
       X1:=Min(X1,Obj.Shell.X1);Y1:=Min(Y1,Obj.Shell.Y1);
       X2:=Max(X2,Obj.Shell.X2);Y2:=Max(Y2,Obj.Shell.Y2);
     End;
     N:=Scene.VConnectionList.IndexOf(ObjName);
     If N>=0 Then Begin
       Conn:=Scene.VObjectList.Objects[N] As TVConnection;
       X1:=Min(X1,Conn.Shell.X1);Y1:=Min(Y1,Conn.Shell.Y1);
       X2:=Max(X2,Conn.Shell.X2);Y2:=Max(Y2,Conn.Shell.Y2);
     End;
     N:=Scene.VCalloutList.IndexOf(ObjName);
     If N>=0 Then Begin
       Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
       X1:=Min(X1,Callout.Shell.X1);Y1:=Min(Y1,Callout.Shell.Y1);
       X2:=Max(X2,Callout.Shell.X2);Y2:=Max(Y2,Callout.Shell.Y2);
     End;
     Xe:=(X1+X2)/2;
     Ye:=(Y1+Y2)/2;
     If (X2-X1)/Scene.Drawer.Wx > (Y2-Y1)/Scene.Drawer.Wy
     Then Se:=(X2-X1)*1.01001/Scene.Drawer.Wx
     Else Se:=(Y2-Y1)*1.01001/Scene.Drawer.Wy;
   end;
   Xc:=(Xe+Xst)/2;
   Yc:=(Ye+Yst)/2;
   Ac:=(Ae+Ast)/2;
   Sc:=Max(Abs(Ye-Yst),Abs(Xe-Xst))/Min(Scene.Drawer.Wx,Scene.Drawer.Wy);
   For I:=1 To Steps Do Begin
     Xv:=Xst+(Xc-Xst)*I/(Steps);
     Yv:=Yst+(Yc-Yst)*I/(Steps);
     Av:=Ast+(Ac-Ast)*I/(Steps);
     Sv:=Sst+(Sc-Sst)*I/(Steps);
     Drawer.ViewX:=Xv;
     Drawer.ViewY:=Yv;
     Drawer.ViewScale:=Sv;
     Drawer.ViewAngle:=Av/180*pi;
     Drawer.Wx:=Form1.DrawingPanel.Width;
     Drawer.Wy:=Form1.DrawingPanel.Height;
     Drawer.RecalcMatrix;
     UpdateScreenShell(Drawer);
     Scene.UpdateVisibility;
     Drawer.Updated:=True;
     Drawer.Canvas:=Form1.DrawingPanel.Canvas;

     DrawScene(Drawer,True);//!!!! true-false
     Form1.DrawingPanel.Refresh;
   end;
   For I:=1 To Steps Do Begin
     Xv:=Xc+(Xe-Xc)*I/(Steps);
     Yv:=Yc+(Ye-Yc)*I/(Steps);
     Av:=Ac+(Ae-Ac)*I/(Steps);
     Sv:=Sc+(Se-Sc)*I/(Steps);
     Drawer.ViewX:=Xv;
     Drawer.ViewY:=Yv;
     Drawer.ViewScale:=Sv;
     Drawer.ViewAngle:=Av/180*pi;
     Drawer.Wx:=Form1.DrawingPanel.Width;
     Drawer.Wy:=Form1.DrawingPanel.Height;
     Drawer.RecalcMatrix;
     UpdateScreenShell(Drawer);
     Scene.UpdateVisibility;
     Drawer.Updated:=True;
     Drawer.Canvas:=Form1.DrawingPanel.Canvas;
     DrawScene(Drawer,True);//!!!! true-false
     Form1.DrawingPanel.Refresh;
   end;

   BasisChanging:=True;
   Form1.ViewXEdit.Value:=XV;
   Form1.ViewYEdit.Value:=YV;
   Form1.ViewAngleEdit.Value:=AV;
   Form1.ViewScaleEdit.Value:=SV;
   BasisChanging:=False;
   JustDrawing:=True;
End;

Procedure NavigateTo(Destination:String);
Begin
  Case LowerCase(NavigationMode) Of
  'teleport','telezoom': Begin GoToBookMark(Destination);End;
  'hover','hoverzoom': Begin HoverToBookMark(15,Destination); End;
  'fly','flyzoom': Begin FlyToBookMark(15,Destination);End;
  End;
End;

Procedure NavigateToItem(ItemName:String);  //navigate
begin
  BasisChanging:=True;
  NavigateTo(ComputeItemDST(ItemName));
  BasisChanging:=False;
End;

Procedure NavigateToItemZoom(ItemName:String);
begin
  BasisChanging:=True;
  NavigateTo(ComputeItemZoomDST(ItemName));
  BasisChanging:=False;
End;

Procedure ZoomToScene;
Var ObjName:String;
    Obj:TVObject;
    Callout:TVCallout;
    Curl:TVCurl;
    I,J,N:Longint;
    X1,X2,Y1,Y2:Extended;
begin
  X1:=+MaxExtended;X2:=-MaxExtended;
  Y1:=+MaxExtended;Y2:=-MaxExtended;
  If Scene.VObjectList.Count>0 Then
    For I:=0 To Scene.VObjectList.Count-1 Do Begin
      Obj:=Scene.VObjectList.Objects[I] As TVObject;
      X1:=Min(X1,Obj.Shell.X1);Y1:=Min(Y1,Obj.Shell.Y1);
      X2:=Max(X2,Obj.Shell.X2);Y2:=Max(Y2,Obj.Shell.Y2);
    End;
  If Scene.VCurlList.Count>0 Then
    For I:=0 To Scene.VCurlList.Count-1 Do Begin
      Curl:=Scene.VCurlList.Objects[I] As TVCurl;
      X1:=Min(X1,Curl.Shell.X1);Y1:=Min(Y1,Curl.Shell.Y1);
      X2:=Max(X2,Curl.Shell.X2);Y2:=Max(Y2,Curl.Shell.Y2);
    End;
  If Scene.VCalloutList.Count>0 Then
    For I:=0 To Scene.VCalloutList.Count-1 Do Begin
      Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
      X1:=Min(X1,Callout.Shell.X1);Y1:=Min(Y1,Callout.Shell.Y1);
      X2:=Max(X2,Callout.Shell.X2);Y2:=Max(Y2,Callout.Shell.Y2);
    End;

  BasisChanging:=True;
  Form1.ViewXEdit.Value:=(X1+X2)/2;
  Form1.ViewYEdit.Value:=(Y1+Y2)/2;
  If (X2-X1)/Scene.Drawer.Wx > (Y2-Y1)/Scene.Drawer.Wy
  Then  Form1.ViewScaleEdit.Value:=(X2-X1)*1.01001/Scene.Drawer.Wx
  Else  Form1.ViewScaleEdit.Value:=(Y2-Y1)*1.01001/Scene.Drawer.Wy;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  BasisChanging:=False;
End;

Procedure NavigateToSelection;
begin
  BasisChanging:=True;
  NavigateTo(ComputeSelectionDST);
  BasisChanging:=False;
End;

Procedure ZoomToSelection;
begin
  BasisChanging:=True;
  NavigateTo(ComputeSelectionZoomDST);
  BasisChanging:=False;
End;


Procedure RemoveItemFromSelection(ItemName:String);
Var I,J,N:Longint;
Begin
  N:=Scene.SelectedList.IndexOf(ItemName);
  If N<0 Then Exit;
  If Scene.SelectedList.Objects[N] Is TVObject Then Begin
    LockSelectionUpdate:=True;
    I:=Form1.ObjectList.Items.IndexOf(ItemName);
    If I>=0 Then Form1.ObjectList.Selected[I]:=False;
    LockSelectionUpdate:=False;
    Scene.DeleteSelHandles(ItemName);
  End;
  If Scene.SelectedList.Objects[N] Is TVCallout Then Begin
    LockSelectionUpdate:=True;
    I:=Form1.CalloutList.Items.IndexOf(ItemName);
    If I>=0 Then Form1.CalloutList.Selected[I]:=False;
    LockSelectionUpdate:=False;
    Scene.DeleteSelHandles(ItemName);
  End;
  If Scene.SelectedList.Objects[N] Is TVCurl Then Begin
    LockSelectionUpdate:=True;
    I:=Form1.CurlList.Items.IndexOf(ItemName);
    If I>=0 Then Form1.CurlList.Selected[I]:=False;
    LockSelectionUpdate:=False;
  End;
  If Scene.SelectedList.Objects[N] Is TVConnection Then Begin
    LockSelectionUpdate:=True;
    I:=Form1.ConnectionList.Items.IndexOf(ItemName);
    If I>=0 Then Form1.ConnectionList.Selected[I]:=False;
    LockSelectionUpdate:=False;
    Scene.ExecCommand('DrawConnection '+ItemName,ZeroAcc,0);
  End;
  J:=Form1.SelectionListEditor.Cols[1].IndexOf(ItemName);
  If J>=1 Then Form1.SelectionListEditor.DeleteRow(J);
  Scene.SelectedList.Delete(N);
  RepaintView;
End;

Procedure AddItemToSelection(ItemName:String);
Var I,N:Longint;
    Obj:TVObject;
    Callout:TVCallout;
    Connection:TVConnection;
    Curl:TVCurl;
Begin
  LockSelectionUpdate:=True;
  Case GetTypeByName(Scene,ItemName) Of
  'object': Begin
              I:=Form1.ObjectList.Items.IndexOf(ItemName);
              If I>=0 Then
                If Not Form1.ObjectList.Selected[I] Then Begin

                  Form1.ObjectList.Selected[I]:=True;
                  If Form1.ObjectList.SelCount=1 Then Form1.ObjectList.ItemIndex:=I;

                End;
              If Form1.SelectionListEditor.Cols[1].IndexOf(ItemName)<0 Then Begin
                If Form1.SelectionListEditor.Cells[1,Form1.SelectionListEditor.RowCount-1]<>''
                Then Form1.SelectionListEditor.RowCount:=Form1.SelectionListEditor.RowCount+1;
                Form1.SelectionListEditor.Cells[0,Form1.SelectionListEditor.RowCount-1]:='object';
                Form1.SelectionListEditor.Cells[1,Form1.SelectionListEditor.RowCount-1]:=ItemName;
              End;
              N:=Scene.VObjectList.IndexOf(ItemName);
              Obj:=Scene.VObjectList.Objects[N] As TVObject;
              If Scene.SelectedList.IndexOf(ItemName)<0 Then
                Scene.SelectedList.AddObject(ItemName,Obj);
              Scene.CreateSelHandles(ItemName);
            End;
  'callout': Begin
              I:=Form1.CalloutList.Items.IndexOf(ItemName);
              If I>=0 Then
                If Not Form1.CalloutList.Selected[I] Then Begin
             //     LockSelectionUpdate:=True;
                  Form1.CalloutList.Selected[I]:=True;
                  If Form1.CalloutList.SelCount=1 Then Form1.CalloutList.ItemIndex:=I;
            //      LockSelectionUpdate:=False;
                End;
              If Form1.SelectionListEditor.Cols[1].IndexOf(ItemName)<0 Then Begin
                If Form1.SelectionListEditor.Cells[1,Form1.SelectionListEditor.RowCount-1]<>''
                Then Form1.SelectionListEditor.RowCount:=Form1.SelectionListEditor.RowCount+1;
                Form1.SelectionListEditor.Cells[0,Form1.SelectionListEditor.RowCount-1]:='callout';
                Form1.SelectionListEditor.Cells[1,Form1.SelectionListEditor.RowCount-1]:=ItemName;
              End;
              N:=Scene.VCalloutList.IndexOf(ItemName);
              Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
              If Scene.SelectedList.IndexOf(ItemName)<0 Then
                Scene.SelectedList.AddObject(ItemName,Callout);
              Scene.CreateSelHandles(ItemName);
            End;
  'curl': Begin
              I:=Form1.CurlList.Items.IndexOf(ItemName);
              If I>=0 Then
                If Not Form1.CurlList.Selected[I] Then Begin
            //      LockSelectionUpdate:=True;
                  Form1.CurlList.Selected[I]:=True;
                  If Form1.CurlList.SelCount=1 Then Form1.CurlList.ItemIndex:=I;
            //      LockSelectionUpdate:=False;
                End;
              If Form1.SelectionListEditor.Cols[1].IndexOf(ItemName)<0 Then Begin
                If Form1.SelectionListEditor.Cells[1,Form1.SelectionListEditor.RowCount-1]<>''
                Then Form1.SelectionListEditor.RowCount:=Form1.SelectionListEditor.RowCount+1;
                Form1.SelectionListEditor.Cells[0,Form1.SelectionListEditor.RowCount-1]:='curl';
                Form1.SelectionListEditor.Cells[1,Form1.SelectionListEditor.RowCount-1]:=ItemName;
              End;

              If Scene.SelectedList.IndexOf(ItemName)<0 Then
                Scene.SelectedList.AddObject(ItemName,Curl);
              //hilite instead of selhandles
            End;
  'connection': Begin
              I:=Form1.ConnectionList.Items.IndexOf(ItemName);
              If I>=0 Then
                If Not Form1.ConnectionList.Selected[I] Then Begin
                  LockSelectionUpdate:=True;
                  Form1.ConnectionList.Selected[I]:=True;
                  If Form1.ConnectionList.SelCount=1 Then Form1.ConnectionList.ItemIndex:=I;
                  LockSelectionUpdate:=False;
                End;
              If Form1.SelectionListEditor.Cols[1].IndexOf(ItemName)<0 Then Begin
                If Form1.SelectionListEditor.Cells[1,Form1.SelectionListEditor.RowCount-1]<>''
                Then Form1.SelectionListEditor.RowCount:=Form1.SelectionListEditor.RowCount+1;
                Form1.SelectionListEditor.Cells[0,Form1.SelectionListEditor.RowCount-1]:='connection';
                Form1.SelectionListEditor.Cells[1,Form1.SelectionListEditor.RowCount-1]:=ItemName;
              End;
              N:=Scene.VConnectionList.IndexOf(ItemName);
              Connection:=Scene.VConnectionList.Objects[N] As TVConnection;
              If Scene.SelectedList.IndexOf(ItemName)<0 Then
                Scene.SelectedList.AddObject(ItemName,Connection);
              //hilite instead of selhandles
              If Form1.DrawingPanel.Color=clBlack Then Scene.Drawer.Canvas.Pen.Mode:=pmWhite//pmNotCopy;
              Else Scene.Drawer.Canvas.Pen.Mode:=pmNotCopy;//pmNotCopy;
              Scene.ExecCommand('DrawConnection '+ItemName,ZeroAcc,0);

              Scene.CreateSelHandles(ItemName);
              Scene.Drawer.Canvas.Pen.Mode:=pmCopy;
                End;
  'none':
  End;
  LockSelectionUpdate:=False;
  RepaintView;
End;

Procedure UpdateMultiSelection;
Var I,J,N,BaseN:Longint;
    SelHandle,SelHandle1:TVSelHandle;
    Obj:TVObject;
    Callout:TVCallout;
    Connection:TVConnection;
    DupHandles:Boolean;
Begin
  With Form1 Do Begin
    SelectionListEditor.Clear;
    SelectionListEditor.RowCount:=Scene.SelectedList.Count+1; //.SelCount+ObjectList.SelCount+CalloutList.SelCount+1;
    BaseN:=1;
    For I:=0 To Scene.SelectedList.Count-1 Do Begin
      If GetTypeByName(Scene,Scene.SelectedList[I])='curl' Then Begin
        N:=CurlList.Items.IndexOf(Scene.SelectedList[I]);
        If N>=0 Then CurlList.Selected[N]:=True; //а не надо ли ещё скидывать выбранность у тех, кто не значится?
        SelectionListEditor.Cells[0,BaseN]:='curl';
        SelectionListEditor.Cells[1,BaseN]:=Scene.SelectedList[I];
        Inc(BaseN);
      End;
    end;
    For I:=0 To Scene.SelectedList.Count-1 Do Begin
      If GetTypeByName(Scene,Scene.SelectedList[I])='object' Then Begin
        N:=ObjectList.Items.IndexOf(Scene.SelectedList[I]);
        If N>=0 Then ObjectList.Selected[N]:=True; //а не надо ли ещё скидывать выбранность у тех, кто не значится?
        SelectionListEditor.Cells[0,BaseN]:='object';
        SelectionListEditor.Cells[1,BaseN]:=Scene.SelectedList[I];
        //для всех выделенных в списке объектов у которых нет хэндлов - создать их
        If Scene.VHandleList.IndexOf(Scene.SelectedList[I])<0 Then Begin
          Scene.CreateSelHandles(Scene.SelectedList[I]);
        End;
        Inc(BaseN);
      End;
    end;
    For I:=0 To Scene.SelectedList.Count-1 Do Begin
      If GetTypeByName(Scene,Scene.SelectedList[I])='callout' Then Begin
        N:=CalloutList.Items.IndexOf(Scene.SelectedList[I]);
        If N>=0 Then CalloutList.Selected[N]:=True; //а не надо ли ещё скидывать выбранность у тех, кто не значится?
        SelectionListEditor.Cells[0,BaseN]:='callout';
        SelectionListEditor.Cells[1,BaseN]:=Scene.SelectedList[I];
        //для всех выделенных в списке объектов у которых нет хэндлов - создать их
        If Scene.VHandleList.IndexOf(Scene.SelectedList[I])<0 Then Begin
          Scene.CreateSelHandles(Scene.SelectedList[I]);
        End;
        Inc(BaseN);
      End;
    end;
    For I:=0 To Scene.SelectedList.Count-1 Do Begin
      If GetTypeByName(Scene,Scene.SelectedList[I])='connection' Then Begin
        N:=ConnectionList.Items.IndexOf(Scene.SelectedList[I]);
        If N>=0 Then ConnectionList.Selected[N]:=True; //а не надо ли ещё скидывать выбранность у тех, кто не значится?
        SelectionListEditor.Cells[0,BaseN]:='connection';
        SelectionListEditor.Cells[1,BaseN]:=Scene.SelectedList[I];
        //Что вместо хэндлов?
        If Scene.VHandleList.IndexOf(Scene.SelectedList[I])<0 Then Begin
          Scene.CreateSelHandles(Scene.SelectedList[I]);
        End;
        If DrawingPanel.Color=clBlack Then Scene.Drawer.Canvas.Pen.Mode:=pmWhite//pmNotCopy;
        Else Scene.Drawer.Canvas.Pen.Mode:=pmNotCopy;//pmNotCopy;
        Scene.ExecCommand('DrawConnection '+Scene.SelectedList[I],ZeroAcc,0);
        Inc(BaseN);
      End;
    end;

  {  If Scene.VHandleList.Count>0 Then
      I:=Scene.VHandleList.Count-1;
      While I>=0 Do Begin
        SelHandle:=Scene.VHandleList.Objects[I] As TVSelHandle;
        N:=Scene.SelectedList.IndexOf(SelHandle.Name);
        If N<0 Then Begin
          DeleteSelHandles(SelHandle.Name);
          Dec(I);
        End;
        Dec(I);
      End;}
{        N:=CalloutList.Items.IndexOf(SelHandle.Name);
        If N>=0 Then
          If Not CalloutList.Selected[N] Then Begin
            //нет такого - удаляем
            Scene.Drawer.Canvas.Pen.Mode:=pmXor;
             DupHandles:=False;
             If Scene.VHandleList.Count>1 Then
               For J:=0 To Scene.VHandleList.Count-1 Do Begin
                 SelHandle1:=Scene.VHandleList.Objects[J] As TVSelHandle;
                 If I<>J Then
                   If (Abs(SelHandle.Xw-SelHandle1.Xw)/Scene.Drawer.ViewScale<2)And(Abs(SelHandle.Yw-SelHandle1.Yw)/Scene.Drawer.ViewScale<2) Then Begin
                     DupHandles:=True;Break;
                   End;
               End;
            If Not DupHandles Then
            Scene.Drawer.ExecCommand('UnScaled '+FloatToStr(SelHandle.Xw)+','+FloatToStr(SelHandle.Yw)+',box,5',ZeroAcc);
            Scene.VHandleList.Delete(I);
            SelHandle.Free;
          end;
      end;    }
    Scene.Drawer.Canvas.Pen.Mode:=pmCopy;
    {------slow but reliable}
    N:=Form1.SelectionListEditor.RowCount;
    If Scene.SelectedList.Count=1 Then Begin
      Form1.SelectionListEditorDblClick(Nil);
    end Else Begin
      If Scene.SelectedList.Count=0 Then Begin
        Form1.ToolOptionsPanel.Hide;
        Form1.Splitter2.Hide;
      end Else Begin
        Form1.ToolOptionsPanel.Show;
        Form1.Splitter2.Show;
        Form1.InspectorPanel.Hide;
        Form1.SelectionListPanel.Show;
      end;
    end;
  end;
end;

Procedure UnselectAllBut(SelName:String);
Var I:Longint;
Begin
  LockSelectionUpdate:=True;
  If SelName='' Then Begin
    If Scene.VHandleList.Count>0 Then
      For I:=Scene.SelectedList.Count-1 DownTo 0 Do Begin
        Scene.DeleteSelHandles(Scene.SelectedList[I]);
        Scene.SelectedList.Delete(I);
      End;
  End;
  If Form1.CurlList.Count>0 Then
    For I:=0 To Form1.CurlList.Count-1 Do
      If Form1.CurlList.Items[I]<>SelName Then Begin
        Form1.CurlList.Selected[I]:=False;
        Scene.DeleteSelHandles(Form1.CurlList.Items[I]);
      End;
  If Form1.ObjectList.Count>0 Then
    For I:=0 To Form1.ObjectList.Count-1 Do
      If Form1.ObjectList.Items[I]<>SelName Then Begin
        Form1.ObjectList.Selected[I]:=False;
        Scene.DeleteSelHandles(Form1.ObjectList.Items[I]);
      End;
  If Form1.ConnectionList.Count>0 Then
    For I:=0 To Form1.ConnectionList.Count-1 Do
      If Form1.ConnectionList.Items[I]<>SelName Then Begin
        Form1.ConnectionList.Selected[I]:=False;
        Scene.DeleteSelHandles(Form1.ConnectionList.Items[I]);
      End;
  If Form1.CalloutList.Count>0 Then
    For I:=0 To Form1.CalloutList.Count-1 Do
      If Form1.CalloutList.Items[I]<>SelName Then Begin
        Form1.CalloutList.Selected[I]:=False;
        Scene.DeleteSelHandles(Form1.CalloutList.Items[I]);
      End;
  If Scene.SelectedList.Count>0 Then
    For I:=Scene.SelectedList.Count-1 DownTo 0 Do
      If Scene.SelectedList[I]<>SelName Then Begin
        Scene.SelectedList.Delete(I);
      end;


  LockSelectionUpdate:=False;
//  UpdateMultiSelection;
End;

Procedure ObjectGUI2Scene;
Var Obj:TVObject;
    I,N,K:Longint;Buf,ParsedBuf,TemplateName,Ext,Name:String;
    Sm,Rm,Scm,tmpm,TransM:TMatrix2D;
Begin
    N:=Scene.VObjectList.IndexOf(Form1.CurrentEditingNameEdit.Text);
    If N>=0 Then Begin
      Obj:=Scene.VObjectList.Objects[N] As TVObject;
      Case Form1.ObjStyleRadioGroup.ItemIndex Of
      0: Begin
               Ext:=ExtractFileExt(Form1.LibraryShellTreeView.Path);
               Name:=ExtractFileName(Form1.LibraryShellTreeView.Path);
               TemplateName:=Copy(Name,1,Length(Name)-Length(Ext));
               Obj.Template:=TemplateName;
               Obj.X:=Form1.XEdit.Value;
               Obj.Y:=Form1.YEdit.Value;
               Obj.A:=Form1.AEdit.Value;
               Obj.S:=Form1.SEdit.Value;
         End;
      1: Begin
               Obj.Template:='';
               Obj.X:=Form1.XEdit.Value;
               Obj.Y:=Form1.YEdit.Value;
               Obj.A:=Form1.AEdit.Value;
               Obj.S:=Form1.SEdit.Value;
         End;
      2,3,4,5,6: Begin
               Obj.Template:='';
               Obj.X:=Min(Form1.LX1Edit.Value,Form1.LX2Edit.Value);
               Obj.Y:=Min(Form1.LY1Edit.Value,Form1.LY2Edit.Value);
               Obj.W:=Abs(Form1.LX2Edit.Value-Form1.LX1Edit.Value);
               Obj.H:=Abs(Form1.LY2Edit.Value-Form1.LY1Edit.Value);
               If Form1.ObjStyleRadioGroup.ItemIndex=2 Then Obj.A:=720;
               If Form1.ObjStyleRadioGroup.ItemIndex=3 Then Obj.A:=720+360;
               If Form1.ObjStyleRadioGroup.ItemIndex=4 Then Obj.A:=720+2*360;
               If Form1.ObjStyleRadioGroup.ItemIndex=5 Then Obj.A:=720+3*360;
               If Form1.ObjStyleRadioGroup.ItemIndex=6 Then Obj.A:=720+4*360;
               Obj.S:=1;
               Obj.Color:=ColorToString(Form1.BorderColorButton.ButtonColor);
               Obj.BGColor:=ColorToString(Form1.BGColorButton.ButtonColor);
               Obj.Width:=IntToStr(Form1.WidthButton1.Tag);
               If (Form1.ObjStyleRadioGroup.ItemIndex=5)Or(Form1.ObjStyleRadioGroup.ItemIndex=6) Then
                 Obj.Source:=Form1.SourceEdit.Text
               Else Obj.Source:='';

             End;
      End;
      Scene.ObjectAttr2Style(Obj);
      Scene.UpdateObjectDisplayList(Obj);
      Scene.UpdateObjectPorts(Obj);
    End;
end;

Procedure CalloutGUI2Scene;
Var Callout:TVCallout;Obj,OldObj:TVObject;
    I,N,K,K2,Index:Longint;Buf,ParsedBuf,TemplateName:String;
    Sm,Rm,Scm,tmpm,TransM:TMatrix2D;
    BIUS:String;
Begin
    N:=Scene.VCalloutList.IndexOf(Form1.CurrentEditingNameEdit.Text);
    If N>=0 Then Begin
      Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
      Callout.X:=Min(Form1.LX1Edit.Value,Form1.LX2Edit.Value);
      Callout.Y:=Max(Form1.LY1Edit.Value,Form1.LY2Edit.Value);
      Callout.W:=Abs(Form1.LX2Edit.Value-Form1.LX1Edit.Value);
      Callout.H:=Abs(Form1.LY2Edit.Value-Form1.LY1Edit.Value);
      Case Form1.CAStyleRadioGroup.ItemIndex of
      0: Callout.Content:='Text';
      1: Callout.Content:='Pix';
      2: Callout.Content:='Vect';
      End;
      // check if BaseObjectEdit.Text is a valid object
      K:=Scene.VObjectList.IndexOf(Form1.BaseObjectEdit.Text);
      If K>=0 Then Begin
        If Callout.RelatedObj<>Form1.BaseObjectEdit.Text Then //уже был другой объект - надо убирать из него ссылку
          If Callout.RelatedObj<>'' Then Begin
                 K2:=Scene.VObjectList.IndexOf(Callout.RelatedObj);
                 If K2>=0 Then Begin
                   //Remove link to this callout from old object
                   OldObj:=Scene.VObjectList.Objects[K2] As TVObject;
                   Index:=OldObj.RelatedCAList.IndexOf(Callout.Name);
                   If Index>=0 Then OldObj.RelatedCAList.Delete(Index);
                 End;
          end;
        Callout.RelatedObj:=Form1.BaseObjectEdit.Text;
        //add link to this callout to object
        Obj:=Scene.VObjectList.Objects[K] As TVObject;
        If Obj.RelatedCAList.IndexOf(Callout.Name)<0 Then Obj.RelatedCAList.AddObject(Callout.Name,Callout);
      End;
      Callout.Source:=Form1.SourceEdit.Text;
      If Callout.Source='' Then Callout.Text:=Form1.TextMemo.Lines.CommaText;
      BIUS:='';
      If fsBold in Form1.FontDialog.Font.Style Then BIUS:=BIUS+'b';
      If fsItalic in Form1.FontDialog.Font.Style Then BIUS:=BIUS+'i';
      If fsUnderline in Form1.FontDialog.Font.Style Then BIUS:=BIUS+'u';
      If fsStrikeOut in Form1.FontDialog.Font.Style Then BIUS:=BIUS+'s';
      Callout.Color:=ColorToString(Form1.BorderColorButton.ButtonColor);
      Callout.BGColor:=ColorToString(Form1.PeekBGColorButton.ButtonColor);
      Callout.Width:=IntToStr(Form1.WidthButton1.Tag);
      Callout.FontName:=Form1.FontDialog.Font.Name;
      Callout.FontColor:=ColorToString(Form1.FontDialog.Font.Color);
      Callout.FontHeight:=FloatToStr(Form1.FontDialog.Font.Height*Form1.ViewScaleEdit.Value);
      Callout.BIUS:=BIUS;
      If Form1.TransparentBGCheckBox.Checked Then
        Callout.Transparent:='Yes'
      Else
        Callout.Transparent:='No';
      Case Form1.BindModeRadioGroup.ItemIndex Of
      0:  Callout.BindMode:='Shell';
      1:  Callout.BindMode:='Base';
      2:  Callout.BindMode:='LT';
      3:  Callout.BindMode:='RT';
      4:  Callout.BindMode:='LB';
      5:  Callout.BindMode:='RB';
      6:  Callout.BindMode:='None';
      End;
      Scene.CalloutAttr2Style(Callout);
      Scene.UpdateCalloutDisplayList(Callout);
    End;
End;

Procedure ConnectionGUI2Scene;
Var Connection:TVConnection;Obj:TVObject; ConnPort:TVConnectionPort;
    I,N,K:Longint;Buf,ParsedBuf,TemplateName:String;
    Sm,Rm,Scm,tmpm,TransM:TMatrix2D;
    BIUS:String;
Begin
    N:=Scene.VConnectionList.IndexOf(Form1.CurrentEditingNameEdit.Text);
    If N>=0 Then Begin
      Connection:=Scene.VConnectionList.Objects[N] As TVConnection;
      Connection.Color:=ColorToString(Form1.BorderColorButton.ButtonColor);
      Connection.BGColor:=ColorToString(Form1.PeekBGColorButton.ButtonColor);
      Connection.Width:=IntToStr(Form1.WidthButton1.Tag);
      Connection.StartStyle:=Form1.StartStyleComboBox.Text;
      Connection.EndStyle:=Form1.EndStyleComboBox.Text;
{      Connection.FontName:=Form1.FontDialog.Font.Name;
      Connection.FontColor:=ColorToString(Form1.FontDialog.Font.Color);
      Connection.FontHeight:=FloatToStr(Form1.FontDialog.Font.Height*Form1.ScaleEdit.Value);
      Connection.BIUS:=BIUS;
      If Form1.TransparentBGCheckBox.Checked Then
        Connection.Transparent:='Yes'
      Else
        Connection.Transparent:='No';}
      Scene.ConnectionAttr2Style(Connection);
      For I:=1 To Form1.ConnPortStringGrid.RowCount-1 Do Begin
        ConnPort:=Connection.PortList.Objects[I-1] As TVConnectionPort;
        ConnPort.PortType:=Form1.ConnPortStringGrid.Cells[0,I];
        ConnPort.AR:=Form1.ConnPortStringGrid.Cells[1,I];
        If ConnPort.AR='A' Then Begin
          ConnPort.AX:=StrToFloat(Form1.ConnPortStringGrid.Cells[2,I]);
          ConnPort.AY:=StrToFloat(Form1.ConnPortStringGrid.Cells[3,I]);
        end Else Begin
          ConnPort.X:=StrToFloat(Form1.ConnPortStringGrid.Cells[2,I]);
          ConnPort.Y:=StrToFloat(Form1.ConnPortStringGrid.Cells[3,I]);
        End;
        If ConnPort.PortType='Text' Then ConnPort.ConnectedObject:=Form1.ConnPortStringGrid.Cells[4,I];
      end;
      Scene.UpdateConnectionDisplayList(Connection);
      Scene.ExecCommand('DrawConnection '+Connection.Name,ZeroAcc,0);
    End;
End;

procedure PreparePenPropEdit(Curl:TVCurl);
Begin
  If ReadyEditor='pen' Then Exit;
  With Form1 Do begin
    ToolOptionsPanel.Show;
    Form1.Splitter2.Show;

    SimplifyGroupBox.Hide;SimplifyGroupBox.Align:=alNone;SimplifyGroupBox.Parent:=InspectorScrollBox;
    CornerGroupBox.Hide;CornerGroupBox.Align:=alNone;CornerGroupBox.Parent:=InspectorScrollBox;
    LineGroupBox.Hide;LineGroupBox.Align:=alNone;LineGroupBox.Parent:=InspectorScrollBox;
    BackGroundGroupBox.Hide;BackGroundGroupBox.Align:=alNone;BackGroundGroupBox.Parent:=InspectorScrollBox;
    RectGroupBox.Hide;RectGroupBox.Align:=alNone;RectGroupBox.Parent:=InspectorScrollBox;
    LineCutGroupBox.Hide;LineCutGroupBox.Align:=alNone;LineCutGroupBox.Parent:=InspectorScrollBox;
    CAStyleRadioGroup.Hide;CAStyleRadioGroup.Align:=alNone;CAStyleRadioGroup.Parent:=InspectorScrollBox;
    BindingGroupBox.Hide;BindingGroupBox.Align:=alNone;BindingGroupBox.Parent:=InspectorScrollBox;
    FontGroupBox.Hide;FontGroupBox.Align:=alNone;FontGroupBox.Parent:=InspectorScrollBox;
    SourceGroupBox.Hide;SourceGroupBox.Align:=alNone;SourceGroupBox.Parent:=InspectorScrollBox;
    ObjStyleRadioGroup.Hide;ObjStyleRadioGroup.Align:=alNone;ObjStyleRadioGroup.Parent:=InspectorScrollBox;
    InsPointGroupBox.Hide;InsPointGroupBox.Align:=alNone;InsPointGroupBox.Parent:=InspectorScrollBox;
    TemplateGroupBox.Hide;TemplateGroupBox.Align:=alNone;TemplateGroupBox.Parent:=InspectorScrollBox;
    PortPageControl.Hide;PortPageControl.Align:=alNone;PortPageControl.Parent:=InspectorScrollBox;
    ConnNodesGroupBox.Hide;ConnNodesGroupBox.Align:=alNone;ConnNodesGroupBox.Parent:=InspectorScrollBox;
    EndingStyleGroupBox.Hide;EndingStyleGroupBox.Align:=alNone;EndingStyleGroupBox.Parent:=InspectorScrollBox;

    CurrentEditingNameEdit.Text:='';
    CurrentEditingNameEdit.Enabled:=False;

    LineGroupBox.Left:=0;
    LineGroupBox.Top:=0;
    LineGroupBox.Show;
    LineGroupBox.Align:=alTop;

    SimplifyGroupBox.Left:=0;
    SimplifyGroupBox.Top:=LineGroupBox.Top+LineGroupBox.Height+1;
    SimplifyGroupBox.Align:=alTop;
    SimplifyGroupBox.Show;

    CurrentEditingNameEdit.Text:='';
    CurrentEditingNameEdit.Enabled:=False;
    TextTabSheet.TabVisible:=False;
  end;
  ReadyEditor:='pen';
end;

procedure PrepareLinePropEdit(Curl:TVCurl);
Begin
  If ReadyEditor='line' Then Exit;
  With Form1 Do begin
    ToolOptionsPanel.Show;
    Form1.Splitter2.Show;

    SimplifyGroupBox.Hide;SimplifyGroupBox.Align:=alNone;SimplifyGroupBox.Parent:=InspectorScrollBox;
    CornerGroupBox.Hide;CornerGroupBox.Align:=alNone;CornerGroupBox.Parent:=InspectorScrollBox;
    LineGroupBox.Hide;LineGroupBox.Align:=alNone;LineGroupBox.Parent:=InspectorScrollBox;
    BackGroundGroupBox.Hide;BackGroundGroupBox.Align:=alNone;BackGroundGroupBox.Parent:=InspectorScrollBox;
    RectGroupBox.Hide;RectGroupBox.Align:=alNone;RectGroupBox.Parent:=InspectorScrollBox;
    LineCutGroupBox.Hide;LineCutGroupBox.Align:=alNone;LineCutGroupBox.Parent:=InspectorScrollBox;
    CAStyleRadioGroup.Hide;CAStyleRadioGroup.Align:=alNone;CAStyleRadioGroup.Parent:=InspectorScrollBox;
    BindingGroupBox.Hide;BindingGroupBox.Align:=alNone;BindingGroupBox.Parent:=InspectorScrollBox;
    FontGroupBox.Hide;FontGroupBox.Align:=alNone;FontGroupBox.Parent:=InspectorScrollBox;
    SourceGroupBox.Hide;SourceGroupBox.Align:=alNone;SourceGroupBox.Parent:=InspectorScrollBox;
    ObjStyleRadioGroup.Hide;ObjStyleRadioGroup.Align:=alNone;ObjStyleRadioGroup.Parent:=InspectorScrollBox;
    InsPointGroupBox.Hide;InsPointGroupBox.Align:=alNone;InsPointGroupBox.Parent:=InspectorScrollBox;
    TemplateGroupBox.Hide;TemplateGroupBox.Align:=alNone;TemplateGroupBox.Parent:=InspectorScrollBox;
    PortPageControl.Hide;PortPageControl.Align:=alNone;PortPageControl.Parent:=InspectorScrollBox;
    ConnNodesGroupBox.Hide;ConnNodesGroupBox.Align:=alNone;ConnNodesGroupBox.Parent:=InspectorScrollBox;
    EndingStyleGroupBox.Hide;EndingStyleGroupBox.Align:=alNone;EndingStyleGroupBox.Parent:=InspectorScrollBox;

    LineGroupBox.Left:=0;
    LineGroupBox.Top:=0;
    LineGroupBox.Show;
    LineGroupBox.Align:=alTop;

    CornerGroupBox.Left:=0;
    CornerGroupBox.Top:=BackgroundGroupBox.Top+BackgroundGroupBox.Height+1;
    CornerGroupBox.Align:=alTop;
    CornerGroupBox.Show;

    LineCutGroupBox.Top:=CornerGroupBox.Top+CornerGroupBox.Height+1;
    LineCutGroupBox.Align:=alClient;
    LineCutGroupBox.Show;

    CurrentEditingNameEdit.Text:='';
    CurrentEditingNameEdit.Enabled:=False;
    TextTabSheet.TabVisible:=False;
  end;
  ReadyEditor:='line';
end;

procedure PrepareRectPropEdit(Curl:TVCurl);
Begin
  If ReadyEditor='rect' Then Exit;
  With Form1 Do begin
    ToolOptionsPanel.Show;
    Form1.Splitter2.Show;

    SimplifyGroupBox.Hide;SimplifyGroupBox.Align:=alNone;SimplifyGroupBox.Parent:=InspectorScrollBox;
    CornerGroupBox.Hide;CornerGroupBox.Align:=alNone;CornerGroupBox.Parent:=InspectorScrollBox;
    LineGroupBox.Hide;LineGroupBox.Align:=alNone;LineGroupBox.Parent:=InspectorScrollBox;
    BackGroundGroupBox.Hide;BackGroundGroupBox.Align:=alNone;BackGroundGroupBox.Parent:=InspectorScrollBox;
    RectGroupBox.Hide;RectGroupBox.Align:=alNone;RectGroupBox.Parent:=InspectorScrollBox;
    LineCutGroupBox.Hide;LineCutGroupBox.Align:=alNone;LineCutGroupBox.Parent:=InspectorScrollBox;
    CAStyleRadioGroup.Hide;CAStyleRadioGroup.Align:=alNone;CAStyleRadioGroup.Parent:=InspectorScrollBox;
    BindingGroupBox.Hide;BindingGroupBox.Align:=alNone;BindingGroupBox.Parent:=InspectorScrollBox;
    FontGroupBox.Hide;FontGroupBox.Align:=alNone;FontGroupBox.Parent:=InspectorScrollBox;
    SourceGroupBox.Hide;SourceGroupBox.Align:=alNone;SourceGroupBox.Parent:=InspectorScrollBox;
    ObjStyleRadioGroup.Hide;ObjStyleRadioGroup.Align:=alNone;ObjStyleRadioGroup.Parent:=InspectorScrollBox;
    InsPointGroupBox.Hide;InsPointGroupBox.Align:=alNone;InsPointGroupBox.Parent:=InspectorScrollBox;
    TemplateGroupBox.Hide;TemplateGroupBox.Align:=alNone;TemplateGroupBox.Parent:=InspectorScrollBox;
    PortPageControl.Hide;PortPageControl.Align:=alNone;PortPageControl.Parent:=InspectorScrollBox;
    ConnNodesGroupBox.Hide;ConnNodesGroupBox.Align:=alNone;ConnNodesGroupBox.Parent:=InspectorScrollBox;
    EndingStyleGroupBox.Hide;EndingStyleGroupBox.Align:=alNone;EndingStyleGroupBox.Parent:=InspectorScrollBox;

    LineGroupBox.Left:=0;
    LineGroupBox.Top:=0;
    LineGroupBox.Show;
    LineGroupBox.Align:=alTop;

    BackgroundGroupBox.Left:=0;
    BackgroundGroupBox.Top:=LineGroupBox.Top+LineGroupBox.Height+1;
    BackgroundGroupBox.Align:=alTop;
    BackgroundGroupBox.Show;

    CornerGroupBox.Left:=0;
    CornerGroupBox.Top:=BackgroundGroupBox.Top+BackgroundGroupBox.Height+1;
    CornerGroupBox.Align:=alTop;
    CornerGroupBox.Show;

    RectGroupBox.Left:=0;
    RectGroupBox.Top:=CornerGroupBox.Top+CornerGroupBox.Height+1;
    RectGroupBox.Align:=alTop;

    CurrentEditingNameEdit.Text:='';
    CurrentEditingNameEdit.Enabled:=False;
    TextTabSheet.TabVisible:=False;
  end;
  ReadyEditor:='rect';
end;

procedure PrepareLabelPropEdit(Curl:TVCurl);
Begin
  If ReadyEditor='label' Then Exit;
  With Form1 Do begin
    ToolOptionsPanel.Show;
    Form1.Splitter2.Show;

    SimplifyGroupBox.Hide;SimplifyGroupBox.Align:=alNone;SimplifyGroupBox.Parent:=InspectorScrollBox;
    CornerGroupBox.Hide;CornerGroupBox.Align:=alNone;CornerGroupBox.Parent:=InspectorScrollBox;
    LineGroupBox.Hide;LineGroupBox.Align:=alNone;LineGroupBox.Parent:=InspectorScrollBox;
    BackGroundGroupBox.Hide;BackGroundGroupBox.Align:=alNone;BackGroundGroupBox.Parent:=InspectorScrollBox;
    RectGroupBox.Hide;RectGroupBox.Align:=alNone;RectGroupBox.Parent:=InspectorScrollBox;
    LineCutGroupBox.Hide;LineCutGroupBox.Align:=alNone;LineCutGroupBox.Parent:=InspectorScrollBox;
    CAStyleRadioGroup.Hide;CAStyleRadioGroup.Align:=alNone;CAStyleRadioGroup.Parent:=InspectorScrollBox;
    BindingGroupBox.Hide;BindingGroupBox.Align:=alNone;BindingGroupBox.Parent:=InspectorScrollBox;
    FontGroupBox.Hide;FontGroupBox.Align:=alNone;FontGroupBox.Parent:=InspectorScrollBox;
    SourceGroupBox.Hide;SourceGroupBox.Align:=alNone;SourceGroupBox.Parent:=InspectorScrollBox;
    ObjStyleRadioGroup.Hide;ObjStyleRadioGroup.Align:=alNone;ObjStyleRadioGroup.Parent:=InspectorScrollBox;
    InsPointGroupBox.Hide;InsPointGroupBox.Align:=alNone;InsPointGroupBox.Parent:=InspectorScrollBox;
    TemplateGroupBox.Hide;TemplateGroupBox.Align:=alNone;TemplateGroupBox.Parent:=InspectorScrollBox;
    PortPageControl.Hide;PortPageControl.Align:=alNone;PortPageControl.Parent:=InspectorScrollBox;
    ConnNodesGroupBox.Hide;ConnNodesGroupBox.Align:=alNone;ConnNodesGroupBox.Parent:=InspectorScrollBox;
    EndingStyleGroupBox.Hide;EndingStyleGroupBox.Align:=alNone;EndingStyleGroupBox.Parent:=InspectorScrollBox;

    FontGroupBox.Left:=0;
    FontGroupBox.Top:=0;
    FontGroupBox.Align:=alTop;
    FontGroupBox.Show;
    FontDialog.Font.Height:=FontSizeEdit.Value;

// TextGroupBox.Hide;
    CurrentEditingNameEdit.Text:='';
    CurrentEditingNameEdit.Enabled:=False;
    TextTabSheet.TabVisible:=True;
  end;
  ReadyEditor:='label';
end;

procedure PrepareMemoPropEdit(Curl:TVCurl);
Begin
  If ReadyEditor='memo' Then Exit;
  With Form1 Do begin
    ToolOptionsPanel.Show;
    Form1.Splitter2.Show;

    SimplifyGroupBox.Hide;SimplifyGroupBox.Align:=alNone;SimplifyGroupBox.Parent:=InspectorScrollBox;
    CornerGroupBox.Hide;CornerGroupBox.Align:=alNone;CornerGroupBox.Parent:=InspectorScrollBox;
    LineGroupBox.Hide;LineGroupBox.Align:=alNone;LineGroupBox.Parent:=InspectorScrollBox;
    BackGroundGroupBox.Hide;BackGroundGroupBox.Align:=alNone;BackGroundGroupBox.Parent:=InspectorScrollBox;
    RectGroupBox.Hide;RectGroupBox.Align:=alNone;RectGroupBox.Parent:=InspectorScrollBox;
    LineCutGroupBox.Hide;LineCutGroupBox.Align:=alNone;LineCutGroupBox.Parent:=InspectorScrollBox;
    CAStyleRadioGroup.Hide;CAStyleRadioGroup.Align:=alNone;CAStyleRadioGroup.Parent:=InspectorScrollBox;
    BindingGroupBox.Hide;BindingGroupBox.Align:=alNone;BindingGroupBox.Parent:=InspectorScrollBox;
    FontGroupBox.Hide;FontGroupBox.Align:=alNone;FontGroupBox.Parent:=InspectorScrollBox;
    SourceGroupBox.Hide;SourceGroupBox.Align:=alNone;SourceGroupBox.Parent:=InspectorScrollBox;
    ObjStyleRadioGroup.Hide;ObjStyleRadioGroup.Align:=alNone;ObjStyleRadioGroup.Parent:=InspectorScrollBox;
    InsPointGroupBox.Hide;InsPointGroupBox.Align:=alNone;InsPointGroupBox.Parent:=InspectorScrollBox;
    TemplateGroupBox.Hide;TemplateGroupBox.Align:=alNone;TemplateGroupBox.Parent:=InspectorScrollBox;
    PortPageControl.Hide;PortPageControl.Align:=alNone;PortPageControl.Parent:=InspectorScrollBox;
    ConnNodesGroupBox.Hide;ConnNodesGroupBox.Align:=alNone;ConnNodesGroupBox.Parent:=InspectorScrollBox;
    EndingStyleGroupBox.Hide;EndingStyleGroupBox.Align:=alNone;EndingStyleGroupBox.Parent:=InspectorScrollBox;

    FontGroupBox.Left:=0;
    FontGroupBox.Top:=0;//LineGroupBox.Top+LineGroupBox.Height+1;
    FontGroupBox.Align:=alTop;
    FontGroupBox.Show;
    FontDialog.Font.Height:=FontSizeEdit.Value;

    CornerGroupBox.Left:=0;
    CornerGroupBox.Top:=FontGroupBox.Top+FontGroupBox.Height+1;
    CornerGroupBox.Align:=alTop;
    CornerGroupBox.Show;

    CurrentEditingNameEdit.Text:='';
    CurrentEditingNameEdit.Enabled:=False;
    TextTabSheet.TabVisible:=True;
  end;
  ReadyEditor:='memo';
end;

procedure PrepareObjectPropEdit(Obj:TVObject);
Var Port:TVPort;
    ObjName,B,PB,Templ:String;
    I,N:Longint;
    TreeNode:TTreeNode;
Begin
  If Not (Form1.InspectorPanel.Visible And Form1.ToolOptionsPanel.Visible) Then Begin
    Form1.ToolOptionsPanel.Show;
    Form1.Splitter2.Show;
    Form1.InspectorPanel.Show;
    Form1.SelectionListPanel.Hide;
  End;
  If ReadyEditor<>'object' Then Begin
    With Form1 Do Begin
      LockBackUpdate:=True;
      ToolOptionsPanel.Show;
      Form1.Splitter2.Show;

      SimplifyGroupBox.Hide;SimplifyGroupBox.Align:=alNone;SimplifyGroupBox.Parent:=InspectorScrollBox;
      CornerGroupBox.Hide;CornerGroupBox.Align:=alNone;CornerGroupBox.Parent:=InspectorScrollBox;
      LineGroupBox.Hide;LineGroupBox.Align:=alNone;LineGroupBox.Parent:=InspectorScrollBox;
      BackGroundGroupBox.Hide;BackGroundGroupBox.Align:=alNone;BackGroundGroupBox.Parent:=InspectorScrollBox;
      RectGroupBox.Hide;RectGroupBox.Align:=alNone;RectGroupBox.Parent:=InspectorScrollBox;
      LineCutGroupBox.Hide;LineCutGroupBox.Align:=alNone;LineCutGroupBox.Parent:=InspectorScrollBox;
      CAStyleRadioGroup.Hide;CAStyleRadioGroup.Align:=alNone;CAStyleRadioGroup.Parent:=InspectorScrollBox;
      BindingGroupBox.Hide;BindingGroupBox.Align:=alNone;BindingGroupBox.Parent:=InspectorScrollBox;
      FontGroupBox.Hide;FontGroupBox.Align:=alNone;FontGroupBox.Parent:=InspectorScrollBox;
      SourceGroupBox.Hide;SourceGroupBox.Align:=alNone;SourceGroupBox.Parent:=InspectorScrollBox;
      ObjStyleRadioGroup.Hide;ObjStyleRadioGroup.Align:=alNone;ObjStyleRadioGroup.Parent:=InspectorScrollBox;
      InsPointGroupBox.Hide;InsPointGroupBox.Align:=alNone;InsPointGroupBox.Parent:=InspectorScrollBox;
      TemplateGroupBox.Hide;TemplateGroupBox.Align:=alNone;TemplateGroupBox.Parent:=InspectorScrollBox;
      PortPageControl.Hide;PortPageControl.Align:=alNone;PortPageControl.Parent:=InspectorScrollBox;
      ConnNodesGroupBox.Hide;ConnNodesGroupBox.Align:=alNone;ConnNodesGroupBox.Parent:=InspectorScrollBox;
      EndingStyleGroupBox.Hide;EndingStyleGroupBox.Align:=alNone;EndingStyleGroupBox.Parent:=InspectorScrollBox;

      Case ObjStyleRadioGroup.ItemIndex of
      0: Begin
           PortPageControl.Align:=alNone;
           ObjStyleRadioGroup.Top:=0;
           ObjStyleRadioGroup.Align:=alTop;
           ObjStyleRadioGroup.Show;
           InsPointGroupBox.Align:=alTop;
           InsPointGroupBox.Top:=ObjStyleRadioGroup.Top+ObjStyleRadioGroup.Height+1;
           InsPointGroupBox.Show;
           TemplateGroupBox.Align:=alTop;
           TemplateGroupBox.Top:=InsPointGroupBox.Top+InsPointGroupBox.Height+1;
           TemplateGroupBox.Show;
           CornerGroupBox.Hide;
           SourceGroupBox.Hide;
           BackGroundGroupBox.Hide;
           LineGroupBox.Hide;

           TemplateGroupBox.Top:=InsPointGroupBox.Top+InsPointGroupBox.Height+1;
           TemplateGroupBox.Align:=alTop;
           PortPageControl.Top:=TemplateGroupBox.Top+TemplateGroupBox.Height+5;
           PortPageControl.Align:=alClient;
         End;
      2,3,4: Begin
                   InsPointGroupBox.Hide;
                   TemplateGroupBox.Hide;
                   SourceGroupBox.Hide;
                   LineGroupBox.Align:=alNone;
                   LineGroupBox.Show;
                   BackGroundGroupBox.Align:=alNone;
                   BackGroundGroupBox.Show;
                   CornerGroupBox.Align:=alNone;
                   CornerGroupBox.Show;

                   LineGroupBox.Top:=ObjStyleRadioGroup.Top+ObjStyleRadioGroup.Height+1;
                   LineGroupBox.Align:=alTop;

                   BackGroundGroupBox.Top:=LineGroupBox.Top+LineGroupBox.Height+1;
                   BackGroundGroupBox.Align:=alTop;

                   CornerGroupBox.Top:=BackGroundGroupBox.Top+BackGroundGroupBox.Height+1;
                   CornerGroupBox.Align:=alTop;

                   ObjStyleRadioGroup.Top:=0;
                   ObjStyleRadioGroup.Align:=alTop;

                   PortPageControl.Align:=alClient;
             End;
      5,6:  Begin
                   InsPointGroupBox.Hide;
                   TemplateGroupBox.Hide;
                   LineGroupBox.Align:=alNone;
                   LineGroupBox.Hide;
                   SourceGroupBox.Show;
                   SourceGroupBox.Align:=alNone;
                   BackGroundGroupBox.Align:=alNone;
                   BackGroundGroupBox.Hide;
                   CornerGroupBox.Align:=alNone;
                   CornerGroupBox.Show;

                   SourceGroupBox.Top:=ObjStyleRadioGroup.Top+ObjStyleRadioGroup.Height+1;
                   SourceGroupBox.Align:=alTop;

                   LineGroupBox.Top:=ObjStyleRadioGroup.Top+ObjStyleRadioGroup.Height+1;
                   LineGroupBox.Align:=alTop;

                   BackGroundGroupBox.Top:=LineGroupBox.Top+LineGroupBox.Height+1;
                   BackGroundGroupBox.Align:=alTop;

                   CornerGroupBox.Top:=BackGroundGroupBox.Top+BackGroundGroupBox.Height+1;
                   CornerGroupBox.Align:=alTop;

                   ObjStyleRadioGroup.Top:=0;
                   ObjStyleRadioGroup.Align:=alTop;

                   PortPageControl.Align:=alClient;
             End;
      end;
      PortPageControl.Show;PortPageControl.Parent:=InspectorScrollBox;
//      If TemplateGroupBox.Visible Then TemplateGroupBox.Hide;TemplateGroupBox.Parent:=InspectorScrollBox;
//      If PortPageControl.Visible Then PortPageControl.Hide;
      If ConnNodesGroupBox.Visible Then ConnNodesGroupBox.Hide;ConnNodesGroupBox.Parent:=InspectorScrollBox;
      If Not ObjStyleRadioGroup.Visible Then ObjStyleRadioGroup.Show;
      TextTabSheet.TabVisible:=False;
      PortStringGrid.RowCount:=1;
      ReadyEditor:='object';
    End;
  End;
  LockBackUpdate:=True;
  With Form1 Do Begin
    If Obj=Nil Then Begin //new object
      CurrentEditingNameEdit.Text:='';
      CurrentEditingNameEdit.Enabled:=False;
      ObjectList.ItemIndex:=-1;
      ObjStyleRadioGroup.Top:=0;
      ObjStyleRadioGroup.Align:=alTop;
      ObjStyleRadioGroup.Show;
 //   TemplateGroupBox.Show;
 //     InsPointGroupBox.Show;
//      PortPageControl.Show;
//      ObjStyleRadioGroupSelectionChanged(Nil);
      Exit;
    end;
    CurrentEditingNameEdit.Text:=Obj.Name;
    CurrentEditingNameEdit.Enabled:=True;
//    ObjectList.ItemIndex:=1;
    If Obj.A=720 Then Begin //style=rect
      ObjStyleRadioGroup.ItemIndex:=2;
      CornerGroupBox.Show;
      LineGroupBox.Show;
      BackGroundGroupBox.Show;
      PortPageControl.Show;
    end;
    If Obj.A=720+360 Then Begin //style=rrect
      ObjStyleRadioGroup.ItemIndex:=3;
      CornerGroupBox.Show;
      LineGroupBox.Show;
      BackGroundGroupBox.Show;
      PortPageControl.Show;
    end;
    If Obj.A=720+2*360 Then Begin //style=ellipse
      ObjStyleRadioGroup.ItemIndex:=4;
      CornerGroupBox.Show;
      LineGroupBox.Show;
      BackGroundGroupBox.Show;
      PortPageControl.Show;
    end;
    If Obj.A=720+3*360 Then Begin //style=PixCont
      ObjStyleRadioGroup.ItemIndex:=5;
      CornerGroupBox.Show;
      SourceGroupBox.Show;
      PortPageControl.Show;
    end;
    If Obj.A=720+4*360 Then Begin //style=VectCont
      ObjStyleRadioGroup.ItemIndex:=6;
      CornerGroupBox.Show;
      SourceGroupBox.Show;
      PortPageControl.Show;
    end;

    // -360<=Obj.A<=360 style=template
    // -360<=Obj.A<=360 style=custom
    If (Obj.Template<>'') Then Begin
      ObjStyleRadioGroup.ItemIndex:=0;
      InsPointGroupBox.Show;
      TemplateGroupBox.Show;
      PortPageControl.Show;
    End;
  {  If ObjectList.ItemIndex=1 Then Begin
      InsPointGroupBox.Show;
      PortPageControl.Show;
    end;}
    XEdit.Value:=Obj.X;
    YEdit.Value:=Obj.Y;
    AEdit.Value:=Obj.A;
    SEdit.Value:=Obj.S;
    LX1Edit.Value:=Obj.X;
    LY1Edit.Value:=Obj.Y;
    LX2Edit.Value:=Obj.X+Obj.W;//just init, should not be used
    LY2Edit.Value:=Obj.Y+Obj.H;
    Case ObjStyleRadioGroup.ItemIndex of
    0: Begin
         GetNextToken(Obj.DisplayList[0],PB,' ');
         B:=PB;
         Templ:=GetNextToken(B,PB,' ');
         TreeNode:=LibraryShellTreeView.Items.FindNodeWithText(Templ+'.tpg');
         LibraryShellTreeView.Select(TreeNode,[]);
       End;
    2,3,4,5,6: Begin
             BorderColorButton.ButtonColor:=StringToColor(Obj.Color);
             BGColorButton.ButtonColor:=StringToColor(Obj.BGColor);
             LX2Edit.Value:=Obj.X+Obj.W;
             LY2Edit.Value:=Obj.Y+Obj.H;
             WidthButton1.Tag:=StrToInt(Obj.Width);
             SourceEdit.Text:=Obj.Source;
             Case Obj.Width of
             '1': WidthButton1.Down:=True;
             '2': WidthButton2.Down:=True;
             '3': WidthButton3.Down:=True;
             '4': WidthButton4.Down:=True;
             '5': WidthButton5.Down:=True;
             end;
           End;
    End;
    If Obj.PortList.Count=0 Then PortStringGrid.RowCount:=1
    Else Begin
      PortStringGrid.RowCount:=Obj.PortList.Count+1;
      For I:=0 To Obj.PortList.Count-1 Do Begin
        Port:=Obj.PortList.Objects[I] As TVPort;
        PortStringGrid.Cells[0,I+1]:=Port.Name;
        PortStringGrid.Cells[1,I+1]:=Port.AR;
        PortStringGrid.Cells[2,I+1]:=FloatToStrF(Port.X,ffGeneral,4,2);
        PortStringGrid.Cells[3,I+1]:=FloatToStrF(Port.Y,ffGeneral,4,2);
        PortStringGrid.Cells[4,I+1]:=Port.Connection;
        PortStringGrid.Cells[5,I+1]:=Port.ConnectionPort;
      End;
    end;
    NonPortConnListBox.Items.Assign(Obj.NonPortConnectionList);
    RelatedCAListBox.Items.Assign(Obj.RelatedCAList);
    If Obj.ActionList.Count>0 Then Begin
    //  ActionListEditor.RowCount:=Obj.ActionList.Count;
      ActionListEditor.Strings.Assign(Obj.ActionList);
    end Else Begin
      ActionListEditor.Strings.Clear;
    End;
  end;
  LockBackUpdate:=False;
  If Form1.Active Then Form1.DrawingPanel.SetFocus;
end;

procedure PrepareConnectionPropEdit(Conn:TVConnection);
Var Port:TVConnectionPort;
    I,N:Longint;
    SelHandle:TVSelHandle;
Begin
  If Not (Form1.InspectorPanel.Visible And Form1.ToolOptionsPanel.Visible) Then Begin
    Form1.ToolOptionsPanel.Show;
    Form1.Splitter2.Show;
    Form1.InspectorPanel.Show;
    Form1.SelectionListPanel.Hide;
  End;
  If ReadyEditor<>'conn' Then Begin
    With Form1 Do Begin
      LockBackUpdate:=True;

      SimplifyGroupBox.Hide;SimplifyGroupBox.Align:=alNone;SimplifyGroupBox.Parent:=InspectorScrollBox;
      CornerGroupBox.Hide;CornerGroupBox.Align:=alNone;CornerGroupBox.Parent:=InspectorScrollBox;
      LineGroupBox.Hide;LineGroupBox.Align:=alNone;LineGroupBox.Parent:=InspectorScrollBox;
      BackGroundGroupBox.Hide;BackGroundGroupBox.Align:=alNone;BackGroundGroupBox.Parent:=InspectorScrollBox;
      RectGroupBox.Hide;RectGroupBox.Align:=alNone;RectGroupBox.Parent:=InspectorScrollBox;
      LineCutGroupBox.Hide;LineCutGroupBox.Align:=alNone;LineCutGroupBox.Parent:=InspectorScrollBox;
      CAStyleRadioGroup.Hide;CAStyleRadioGroup.Align:=alNone;CAStyleRadioGroup.Parent:=InspectorScrollBox;
      BindingGroupBox.Hide;BindingGroupBox.Align:=alNone;BindingGroupBox.Parent:=InspectorScrollBox;
      FontGroupBox.Hide;FontGroupBox.Align:=alNone;FontGroupBox.Parent:=InspectorScrollBox;
      SourceGroupBox.Hide;SourceGroupBox.Align:=alNone;SourceGroupBox.Parent:=InspectorScrollBox;
      ObjStyleRadioGroup.Hide;ObjStyleRadioGroup.Align:=alNone;ObjStyleRadioGroup.Parent:=InspectorScrollBox;
      InsPointGroupBox.Hide;InsPointGroupBox.Align:=alNone;InsPointGroupBox.Parent:=InspectorScrollBox;
      TemplateGroupBox.Hide;TemplateGroupBox.Align:=alNone;TemplateGroupBox.Parent:=InspectorScrollBox;
      PortPageControl.Hide;PortPageControl.Align:=alNone;PortPageControl.Parent:=InspectorScrollBox;
      ConnNodesGroupBox.Hide;ConnNodesGroupBox.Align:=alNone;ConnNodesGroupBox.Parent:=InspectorScrollBox;
      EndingStyleGroupBox.Hide;EndingStyleGroupBox.Align:=alNone;EndingStyleGroupBox.Parent:=InspectorScrollBox;

      LineGroupBox.Align:=alTop;
      LineGroupBox.Left:=0;
      LineGroupBox.Top:=0;
      LineGroupBox.Show;

      EndingStyleGroupBox.Align:=alTop;
      EndingStyleGroupBox.Left:=0;
      EndingStyleGroupBox.Top:=LineGroupBox.Top+LineGroupBox.Height+1;
      EndingStyleGroupBox.Show;

      ConnNodesGroupBox.Left:=0;
      ConnNodesGroupBox.Top:=EndingStyleGroupBox.Top+EndingStyleGroupBox.Height+1;
      ConnNodesGroupBox.Align:=alClient;
      ConnNodesGroupBox.Show;

      TextTabSheet.TabVisible:=False;
    End;
    ReadyEditor:='conn';
  End;
  LockBackUpdate:=True;
  With Form1 Do Begin
    If Conn=Nil Then Begin //new connection
      CurrentEditingNameEdit.Text:='';
      CurrentEditingNameEdit.Enabled:=False;
      Exit;
    end;
    CurrentEditingNameEdit.Text:=Conn.Name;
    CurrentEditingNameEdit.Enabled:=True;
    //ToDo: добавить выставление атрибутов линии по текущему
    BorderColorButton.ButtonColor:=StringToColor(Conn.Color);
    BGColorButton.ButtonColor:=StringToColor(Conn.BGColor);
    WidthButton1.Tag:=StrToInt(Conn.Width);
    Case Conn.Width of
    '1': WidthButton1.Down:=True;
    '2': WidthButton2.Down:=True;
    '3': WidthButton3.Down:=True;
    '4': WidthButton4.Down:=True;
    '5': WidthButton5.Down:=True;
    end;
    Case Conn.StartStyle of
    '', 'flat': Form1.StartStyleComboBox.Text:='flat'
    else Form1.StartStyleComboBox.Text:=Conn.StartStyle;
    End;
    Case Conn.EndStyle of
    '', 'flat': Form1.EndStyleComboBox.Text:='flat'
    else Form1.EndStyleComboBox.Text:=Conn.EndStyle;
    End;

    If Conn.PortList.Count=0 Then ConnPortStringGrid.RowCount:=1
    Else Begin
      ConnPortStringGrid.RowCount:=Conn.PortList.Count+1;
      For I:=0 To Conn.PortList.Count-1 Do Begin
        Port:=Conn.PortList.Objects[I] As TVConnectionPort;
        ConnPortStringGrid.Cells[0,I+1]:=Port.PortType;
        ConnPortStringGrid.Cells[1,I+1]:=Port.AR;
        If Port.AR='A' Then Begin
          ConnPortStringGrid.Cells[2,I+1]:=FloatToStr(Port.AX);
          ConnPortStringGrid.Cells[3,I+1]:=FloatToStr(Port.AY);
        End Else Begin
          ConnPortStringGrid.Cells[2,I+1]:=FloatToStr(Port.X);
          ConnPortStringGrid.Cells[3,I+1]:=FloatToStr(Port.Y);
        End;
        ConnPortStringGrid.Cells[4,I+1]:=Port.ConnectedObject;
        ConnPortStringGrid.Cells[5,I+1]:=Port.ConnectedPort;
        If Port.PortType='Node' Then Begin
          SelHandle:=TVSelHandle.Create;
          SelHandle.Xw:=Port.AX;
          SelHandle.Yw:=Port.AY;
        End;
      End;
    end;
  End;
  LockBackUpdate:=False;
end;

procedure PrepareCalloutPropEdit(Callout:TVCallout);
Var Port:TVConnectionPort;
    CalloutName:String;
    Col,BGCol,CWidth,LineStyle,BindMode,FontName,FontColor,FontHeight,BIUS,Transparent:String;
    I,N:Longint;F:Extended;
Begin
  If Not Form1.TextTabSheet.TabVisible Then Form1.TextTabSheet.TabVisible:=True;

  Form1.ToolOptionsPanel.Show;
  Form1.Splitter2.Show;
  If ReadyEditor<>'callout' Then Begin
    With Form1 Do Begin
//    ToolOptionsPanel.Show;
//    Form1.Splitter2.Show;

    SimplifyGroupBox.Hide;SimplifyGroupBox.Align:=alNone;SimplifyGroupBox.Parent:=InspectorScrollBox;
    CornerGroupBox.Hide;CornerGroupBox.Align:=alNone;CornerGroupBox.Parent:=InspectorScrollBox;
    LineGroupBox.Hide;LineGroupBox.Align:=alNone;LineGroupBox.Parent:=InspectorScrollBox;
    BackGroundGroupBox.Hide;BackGroundGroupBox.Align:=alNone;BackGroundGroupBox.Parent:=InspectorScrollBox;
    RectGroupBox.Hide;RectGroupBox.Align:=alNone;RectGroupBox.Parent:=InspectorScrollBox;
    LineCutGroupBox.Hide;LineCutGroupBox.Align:=alNone;LineCutGroupBox.Parent:=InspectorScrollBox;
    CAStyleRadioGroup.Hide;CAStyleRadioGroup.Align:=alNone;CAStyleRadioGroup.Parent:=InspectorScrollBox;
    BindingGroupBox.Hide;BindingGroupBox.Align:=alNone;BindingGroupBox.Parent:=InspectorScrollBox;
    FontGroupBox.Hide;FontGroupBox.Align:=alNone;FontGroupBox.Parent:=InspectorScrollBox;
    SourceGroupBox.Hide;SourceGroupBox.Align:=alNone;SourceGroupBox.Parent:=InspectorScrollBox;
    ObjStyleRadioGroup.Hide;ObjStyleRadioGroup.Align:=alNone;ObjStyleRadioGroup.Parent:=InspectorScrollBox;
    InsPointGroupBox.Hide;InsPointGroupBox.Align:=alNone;InsPointGroupBox.Parent:=InspectorScrollBox;
    TemplateGroupBox.Hide;TemplateGroupBox.Align:=alNone;TemplateGroupBox.Parent:=InspectorScrollBox;
    PortPageControl.Hide;PortPageControl.Align:=alNone;PortPageControl.Parent:=InspectorScrollBox;
    ConnNodesGroupBox.Hide;ConnNodesGroupBox.Align:=alNone;ConnNodesGroupBox.Parent:=InspectorScrollBox;
    EndingStyleGroupBox.Hide;EndingStyleGroupBox.Align:=alNone;EndingStyleGroupBox.Parent:=InspectorScrollBox;

     // TextTabSheet.TabVisible:=True;
      CAStyleRadioGroup.Align:=alTop;
      CAStyleRadioGroup.Left:=0;
      CAStyleRadioGroup.Top:=0;
      CAStyleRadioGroup.Show;

      BindingGroupBox.Align:=alTop;
      BindingGroupBox.Left:=0;
      BindingGroupBox.Top:=CAStyleRadioGroup.Top+CAStyleRadioGroup.Height+1;
      BindingGroupBox.Show;

      SourceGroupBox.Align:=alTop;
      SourceGroupBox.Left:=0;
      SourceGroupBox.Top:=BindingGroupBox.Top+BindingGroupBox.Height+1;
      SourceGroupBox.Show;

      LineGroupBox.Align:=alTop;
      LineGroupBox.Left:=0;
      LineGroupBox.Top:=SourceGroupBox.Top+SourceGroupBox.Height+1;
      LineGroupBox.Show;

      FontGroupBox.Align:=alTop;
      FontGroupBox.Left:=0;
      FontGroupBox.Top:=LineGroupBox.Top+LineGroupBox.Height+1;
      FontGroupBox.Show;
      FontDialog.Font.Height:=FontSizeEdit.Value;

      CornerGroupBox.Align:=alTop;
      CornerGroupBox.Left:=0;
      CornerGroupBox.Top:=FontGroupBox.Top+FontGroupBox.Height+1;
      CornerGroupBox.Show;

      Form1.FontDialog.Font.Height:=FontSizeEdit.Value;
      ReadyEditor:='callout';
    End;
  End;

    With Form1 Do Begin
      If Callout=Nil Then Begin //new callout
        CurrentEditingNameEdit.Text:='';
        CurrentEditingNameEdit.Enabled:=False;
        CalloutList.ItemIndex:=-1;
        Exit;
      end;
      CurrentEditingNameEdit.Text:=Callout.Name;
      CurrentEditingNameEdit.Enabled:=True;
      LockBackUpdate:=True;

      SelectionListPanel.Hide;
      InspectorPanel.Show;
    {TextTabSheet.TabVisible:=True;}
      Scene.CalloutAttr2Style(Callout);
      Col:=GetValByName(Callout.Style,'Color');BorderColorButton.ButtonColor:=StringToColor(Col);
      BGCol:=GetValByName(Callout.Style,'BGColor');PeekBGColorButton.ButtonColor:=StringToColor(BGCol);
      CWidth:=GetValByName(Callout.Style,'Width');
      WidthButton1.Tag:=StrToInt(CWidth);
      WidthButton1.Down:=(CWidth='1')Or(CWidth='0');WidthButton2.Down:=CWidth='2';
      WidthButton3.Down:=CWidth='3';WidthButton4.Down:=CWidth='4';WidthButton5.Down:=CWidth='5';
      LineStyle:=GetValByName(Callout.Style,'LineStyle');
      FontName:=GetValByName(Callout.Style,'FontName');FontComboBox.Text:=FontName;
      FontColor:=GetValByName(Callout.Style,'FontColor');PeekFontFaceColorButton.ButtonColor:=StringToColor(FontColor);
      FontHeight:=GetValByName(Callout.Style,'FontHeight');
      If Not TryStrToFloat(FontHeight,F) Then FontSizeEdit.Value:=0
      Else FontSizeEdit.Value:=Round(Abs(StrToFloat(FontHeight)/ViewScaleEdit.Value));
      BIUS:=GetValByName(Callout.Style,'BIUS');
      BoldButton.Down:=Pos('b',BIUS)<>0;ItalicButton.Down:=Pos('i',BIUS)<>0;
      UnderButton.Down:=Pos('u',BIUS)<>0;StrikeButton.Down:=Pos('s',BIUS)<>0;
      Form1.LX1Edit.Value:=Callout.X;
      Form1.LY1Edit.Value:=Callout.Y;
      Form1.LX2Edit.Value:=Callout.X+Callout.W;
      Form1.LY2Edit.Value:=Callout.Y-Callout.H;
//      If Callout<>Nil Then
        Case Callout.Content Of
        'Pix': Begin CAStyleRadioGroup.ItemIndex:=1; TextTabSheet.TabVisible:=False;End;
        'Vect':Begin CAStyleRadioGroup.ItemIndex:=2; TextTabSheet.TabVisible:=False;End;
        Else   Begin CAStyleRadioGroup.ItemIndex:=0; TextTabSheet.TabVisible:=True;End;
        End;
      FontDialog.Font.Color:=StringToColor(FontColor);
      FontDialog.Font.Height:=FontSizeEdit.Value;
      FontDialog.Font.Style:=[];
      If BoldButton.Down Then FontDialog.Font.Style:=FontDialog.Font.Style+[fsBold];
      If ItalicButton.Down Then FontDialog.Font.Style:=FontDialog.Font.Style+[fsItalic];
      If UnderButton.Down Then FontDialog.Font.Style:=FontDialog.Font.Style+[fsUnderline];
      If StrikeButton.Down Then FontDialog.Font.Style:=FontDialog.Font.Style+[fsStrikeOut];
      BindMode:=GetValByName(Callout.Style,'BindMode');
      Transparent:=GetValByName(Callout.Style,'Transparent');TransparentBGCheckBox.Checked:=Pos('yes',LowerCase(Transparent))>0;
      Form1.BaseObjectEdit.Text:=Callout.RelatedObj;
      Form1.SourceEdit.Text:=Callout.Source;
      Case BindMode Of
        'Shell':  Form1.BindModeRadioGroup.ItemIndex:=0;
        'Base':   Form1.BindModeRadioGroup.ItemIndex:=1;
        'LT':     Form1.BindModeRadioGroup.ItemIndex:=2;
        'RT':     Form1.BindModeRadioGroup.ItemIndex:=3;
        'LB':     Form1.BindModeRadioGroup.ItemIndex:=4;
        'RB':     Form1.BindModeRadioGroup.ItemIndex:=5;
        'None':   Form1.BindModeRadioGroup.ItemIndex:=6;
      End;
      TextMemo.Lines.CommaText:=Callout.Text;
      LockBackUpdate:=False;
  {  If Conn.PortList.Count=0 Then ConnPortStringGrid.RowCount:=1
    Else Begin
      ConnPortStringGrid.RowCount:=Conn.PortList.Count+1;
      For I:=0 To Conn.PortList.Count-1 Do Begin
        Port:=Conn.PortList.Objects[I] As TVConnectionPort;
        ConnPortStringGrid.Cells[0,I+1]:=Port.PortType;
        ConnPortStringGrid.Cells[1,I+1]:=Port.AR;
        ConnPortStringGrid.Cells[2,I+1]:=FloatToStr(Port.X);
        ConnPortStringGrid.Cells[3,I+1]:=FloatToStr(Port.Y);
        ConnPortStringGrid.Cells[4,I+1]:=Port.ConnectedObject;
        ConnPortStringGrid.Cells[5,I+1]:=Port.ConnectedPort;
      End;
    end; }
     If Callout.ActionList.Count>0 Then Begin
    //  ActionListEditor.RowCount:=Obj.ActionList.Count;
      ActionListEditor.Strings.Assign(Callout.ActionList);
    end Else Begin
      ActionListEditor.Strings.Clear;
    End;
  End;
  LockBackUpdate:=False;
end;

Procedure DrawRubber;
Var I:Longint;
Begin
  If RubberDisplayList.Count>0 Then Begin
    WCanvas.Pen.Mode:=pmnotXOR;
    WCanvas.Pen.Style:=psDot;
    Scene.Drawer.EnforcedPenStyle:=psDot;
    For I:=0 To RubberDisplayList.Count-1 Do
      Scene.ExecCommand(RubberDisplayList[I],ZeroAcc,0);
    WCanvas.Pen.Mode:=pmCopy;
    WCanvas.Pen.Style:=psSolid;
    Scene.Drawer.EnforcedPenStyle:=psClear;
  End;
End;

Function BuildAllActions:TStringList;
Var I,J:Longint;
    Obj:TVObject;
    Callout:TVCallout;
    List:TStringList;
Begin
  List:=TStringList.Create;
  If Scene.VObjectList.Count>0 Then
    For I:=0 To Scene.VObjectList.Count-1 Do Begin
      Obj:=Scene.VObjectList.Objects[I] As TVObject;
      If Obj.ActionList.Count>0 Then
        For J:=0 To Obj.ActionList.Count-1 Do Begin
          If List.IndexOf(Obj.ActionList.Names[J])<0 Then
            List.Add(Obj.ActionList.Names[J]);
        end;
    end;
  If Scene.VCalloutList.Count>0 Then
    For I:=0 To Scene.VCalloutList.Count-1 Do Begin
      Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
      If Callout.ActionList.Count>0 Then
        For J:=0 To Callout.ActionList.Count-1 Do Begin
          If List.IndexOf(Callout.ActionList.Names[J])<0 Then
            List.Add(Callout.ActionList.Names[J]);
        end;
    end;
  Result:=List;
end;


procedure TForm1.PenButtonClick(Sender: TObject);
Var List:TStringList;
begin
  If RubberDisplayList.Count>0 Then Begin
    DrawRubber;RubberDisplayList.Clear;
  End;
  Drawing:=False;JustDrawing:=False;
  Moving:=False;
  SelectionListPanel.Hide;
  InspectorPanel.Show;
  ToolOptionsPanel.Show;
  Form1.Splitter2.Show;
  CurrentEditingNameEdit.Text:='';
  CurrentEditingNameEdit.Enabled:=True;
  Case (Sender As TSpeedButton).Tag Of
  0: Begin // navigation mode
       EditMode:='navigation';
       NaviPanel.Show;
       PenPanel.Hide;
       FontPanel.Hide;
       FigurePanel.Hide;
//     StaticText.Hide;
       HintLabel.Hide;
       TLabelEdit.Hide;
       TextTabSheet.TabVisible:=False;
       ConnPanel.Hide;
       //unselect everything
       UnselectAllBut('');
       Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
       ToolOptionsPanel.Hide;
       Form1.Splitter2.Hide;
       OpComboBox.Items.Clear;
       OpComboBox.Items.Add('Teleport');
       OpComboBox.Items.Add('TeleZoom');
       OpComboBox.Items.Add('Hover');
       OpComboBox.Items.Add('HoverZoom');
       OpComboBox.Items.Add('Fly');
       OpComboBox.ItemIndex:=0;
     End;
  1: Begin // control mode
        EditMode:='control';
        UnselectAllBut('');
        If SelectionListEditor.RowCount>1 Then Begin
          ToolOptionsPanel.Show;
          Form1.Splitter2.Show;
        End;
         NaviPanel.Show;
  {       PenPanel.Hide;
         FontPanel.Hide;
         FigurePanel.Hide;
         ConnPanel.Hide;       }
         TextTabSheet.TabVisible:=False;
         UpdateMultiSelection;
         Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
         List:=BuildAllActions;
         OpComboBox.Items.Clear;
         OpComboBox.Items.Add('');
         OpComboBox.Items.AddStrings(List);
         List.Free;
         OpComboBox.ItemIndex:=0;
       End;
  2: Begin // edit mode
      EditMode:='edit';
      If SelectionListEditor.RowCount>1 Then Begin
        ToolOptionsPanel.Show;
        Form1.Splitter2.Show;
      End;
       NaviPanel.Show;
{       PenPanel.Hide;
       FontPanel.Hide;
       FigurePanel.Hide;
       ConnPanel.Hide;       }
       TextTabSheet.TabVisible:=False;
       UpdateMultiSelection;
       Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
       OpComboBox.Items.Clear;
       OpComboBox.Items.Add('Select');
       OpComboBox.Items.Add('Delete');
       OpComboBox.Items.Add('Move here');
       OpComboBox.Items.Add('Copy here');
       OpComboBox.Items.Add('Add to group');
       OpComboBox.Items.Add('Remove from group');
       OpComboBox.ItemIndex:=0;
     End;
  3: Begin //Auto
     End;
  4: Begin //objects
       EditMode:='object';
       OpComboBox.Items.Clear;
       OpComboBox.ItemIndex:=-1;
       PrepareObjectPropEdit(Nil);
     End;
  5: Begin //Connector
        EditMode:='connection';
        OpComboBox.Items.Clear;
        OpComboBox.ItemIndex:=-1;
        PrepareConnectionPropEdit(Nil);
     End;
  6: Begin // Callout
        EditMode:='callout';
        OpComboBox.Items.Clear;
        OpComboBox.ItemIndex:=-1;
        PrepareCalloutPropEdit(Nil);
      End;
  7: Begin  //Pen Drawing
       EditMode:='curl pen';
       OpComboBox.Items.Clear;
       OpComboBox.ItemIndex:=-1;
       PreparePenPropEdit(Nil);
     end;
  8: Begin //Line
       EditMode:='curl line';
       OpComboBox.Items.Clear;
       OpComboBox.ItemIndex:=-1;
       PrepareLinePropEdit(Nil);
       JustDrawing:=True;
       Scene.Drawer.EnforcedPenStyle:=psDot;
     end;
  9: Begin   //rect rrect ellipse
       EditMode:='curl rect';
       OpComboBox.Items.Clear;
       OpComboBox.ItemIndex:=-1;
       PrepareRectPropEdit(Nil);
     end;
  10: Begin   //rect rrect ellipse
        EditMode:='curl rrect';
        OpComboBox.Items.Clear;
        OpComboBox.ItemIndex:=-1;
        PrepareRectPropEdit(Nil);
     end;
  11: Begin   //rect rrect ellipse
        EditMode:='curl ellipse';
        OpComboBox.Items.Clear;
        OpComboBox.ItemIndex:=-1;
        PrepareRectPropEdit(Nil);
     end;

  12,13: Begin // text label
       EditMode:='curl label';
       OpComboBox.Items.Clear;
       OpComboBox.ItemIndex:=-1;
       PrepareLabelPropEdit(Nil);
     End;
  15: Begin // multiline text
       EditMode:='curl multiline';
       OpComboBox.Items.Clear;
       OpComboBox.ItemIndex:=-1;
       PrepareMemoPropEdit(Nil);
     End;

  end;
end;

procedure TForm1.PrintButtonClick(Sender: TObject);
Var PrintDrawer:TDrawer;
    I:Longint; G,GX,Gr,GY,x1,x2,x3,x4,y1,y2,y3,y4,lx,ly,rx,ry:Extended;
    R:Extended;
    BGColor:String;
begin
  If Not PrinterSetupDialog.Execute Then Exit;
  If Not PrintDialog.Execute Then Exit;
  PrintDrawer:=TDrawer.Create(Printer.Canvas);
  LogMessage(5,IntToStr(Printer.PageWidth));
  LogMessage(5,IntToStr(Printer.XDPI));
  PrintDrawer.ViewX:=Form1.ViewXEdit.Value;
  PrintDrawer.ViewY:=Form1.ViewYEdit.Value;
  // landscape 2 landscape - short Dst edge/short Src edge
  If (Drawer.Wx/Drawer.Wy>1) And (Printer.PageWidth/Printer.PageHeight>1) Then R:=Printer.PageHeight/Drawer.Wy;
  // landscape 2 portraite - long Dst edge/short Src edge
  If (Drawer.Wx/Drawer.Wy>1) And (Printer.PageWidth/Printer.PageHeight<1) Then R:=Printer.PageHeight/Drawer.Wy;
  // portraite 2 landscape - long Dst edge/short Src edge
  If (Drawer.Wx/Drawer.Wy<1) And (Printer.PageWidth/Printer.PageHeight>1) Then R:=Printer.PageWidth/Drawer.Wx;
  // portraite 2 portraite - short Dst edge/short Src edge
  If (Drawer.Wx/Drawer.Wy<1) And (Printer.PageWidth/Printer.PageHeight<1) Then R:=Printer.PageWidth/Drawer.Wx;
  PrintDrawer.ViewScale:=Form1.ViewScaleEdit.Value/R;
  PrintDrawer.ViewAngle:=Form1.ViewAngleEdit.Value/180*pi;
  PrintDrawer.Wx:=Printer.PageWidth;
  PrintDrawer.Wy:=Printer.PageHeight;
  PrintDrawer.RecalcMatrix;
  Scene.UpdateVisibility;
  Scene.Drawer:=PrintDrawer;
  PrintDrawer.PrintMultiplier:=PrintLineSpinEdit.Value;
  BGColor:=Config.ConfigFile.Values['SceneBGColor'];
  Config.ConfigFile.Values['SceneBGColor']:='clWhite';
  Printer.BeginDoc;
  DrawScene(PrintDrawer,False);
  Printer.EndDoc;
  PrintDrawer.Free;
  Config.ConfigFile.Values['SceneBGColor']:=BGColor;
  Scene.Drawer:=Drawer;
  Scene.UpdateVisibility;
end;

procedure TForm1.RenameObjectButtonClick(Sender: TObject);
Var N:Longint;
    Obj:TVObject;
    OldName:String;
begin
  If ObjectList.ItemIndex>=0 Then Begin
    N:=Scene.VObjectList.IndexOf(ObjectList.Items[ObjectList.ItemIndex]);
    Obj:=Scene.VObjectList.Objects[N] As TVObject;
    OldName:=Obj.Name;
    RenameForm.Caption:='Renaming object from '+Obj.Name;
    RenameForm.Scene:=Scene;
    RenameForm.NewNameEdit.Text:=Obj.Name;
    RenameForm.ShowModal;
    If RenameForm.ModalResult=mrOk Then Begin
      Scene.VObjectList[N]:=RenameForm.NewNameEdit.Text;
      ObjectList.Items[ObjectList.ItemIndex]:=RenameForm.NewNameEdit.Text;
      Obj.Name:=RenameForm.NewNameEdit.Text;
      If Scene.View.Count>0 Then
        For N:=0 To Scene.View.Count-1 Do Begin
          If Scene.View[N]=('DrawObject '+OldName) Then Scene.View[N]:='DrawObject '+Obj.Name;
        end;
      Form1.SceneMemo.Lines.Assign(Scene.View);
    end;
    //Добавить обновление имени в подключенных связях
    //Добавить обновление имени в группах и выносках
  end;
end;

procedure TForm1.RenameTemplateButtonClick(Sender: TObject);
var N:Longint;Template:TVTemplate;
    OldName:String;
begin
  If TemplateList.ItemIndex>=0 Then Begin
    N:=Scene.VTemplateList.IndexOf(TemplateList.Items[TemplateList.ItemIndex]);
    Template:=Scene.VTemplateList.Objects[N] As TVTemplate;
    OldName:=TemplateList.Items[TemplateList.ItemIndex];
    RenameForm.Caption:='Renaming template from '+OldName;
    RenameForm.Scene:=Scene;
    RenameForm.NewNameEdit.Text:=OldName;
    RenameForm.ShowModal;
    If RenameForm.ModalResult=mrOk Then Begin
      Scene.VTemplateList[N]:=RenameForm.NewNameEdit.Text;
      TemplateList.Items[TemplateList.ItemIndex]:=RenameForm.NewNameEdit.Text;
      Template.Name:=RenameForm.NewNameEdit.Text;
    end;
  end;
end;

procedure TForm1.ResetCoordButtonClick(Sender: TObject);
begin
  ResetOriginPopupMenu.Popup;
end;

procedure TForm1.SaveButtonClick(Sender: TObject);
begin
  SavePopupMenu.Popup(Form1.Left+SaveButton.Left,Form1.Top+SaveButton.Top+SaveButton.Height+1);
end;

procedure TForm1.SaveGButtonClick(Sender: TObject);
Var R1,R2:TRect;BM:TBitmap;Image:TImage;
    Picture:TPicture;
begin
  R1.Top:=0;R1.Left:=0;R1.Right:=DrawingPanel.ClientWidth-1;R1.Bottom:=DrawingPanel.ClientHeight-1;
  Picture:=TPicture.Create;
  Picture.Bitmap.Height:=R1.Bottom;
  Picture.Bitmap.Width:=R1.Right;
  Picture.Bitmap.Canvas.CopyRect(R1,DrawingPanel.Canvas,R1);
  If SceneFileName<>'' Then SaveGDialog.FileName:=ExtractFileName(SceneFileName);
    If SaveGDialog.Execute Then Begin
      vFileName:=SaveGDialog.FileName;
    End;
    Try
      Picture.SaveToFile(vFileName,ExtractFileExt(vFileName));
    Except ShowMessage('Can''t Write file:'+vFileName);
    End;
  Picture.Free;
end;

procedure TForm1.SaveTemplateButtonClick(Sender: TObject);
var N:Longint;Template:TVTemplate;
begin
  If TemplateList.ItemIndex>-1 Then Begin
    N:=Scene.VTemplateList.IndexOf(TemplateList.Items[TemplateList.ItemIndex]);
    Template:=Scene.VTemplateList.Objects[N] As TVTemplate;
    // надо исправить на реальное расположение
    Template.DisplayList.SaveToFile(ConfigFile.Values['TemplateDir']+'/'+TemplateList.Items[TemplateList.ItemIndex]+'.tpg');
  end;
end;

procedure TForm1.ViewScaleEditChange(Sender: TObject);
begin
  If LockCoordUpdate Then Exit;
  If BasisChanging Then Exit;
  If ViewScaleEdit.Value>0.000001 Then
     Dispatcher.ExecCommand('self::CAD_UpdateScale');
end;

procedure TForm1.Scene2GUIBtnClick(Sender: TObject);
begin
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
end;

procedure TForm1.SelectFontButtonClick(Sender: TObject);
begin
  If FontDialog.Execute Then Begin
    FontComboBox.Text:=FontDialog.Font.Name;
    FontSizeEdit.Value:=FontDialog.Font.Size;
    PeekFontFaceColorButton.ButtonColor:=FontDialog.Font.Color;
    BoldButton.Down:=(fsBold in FontDialog.Font.Style);
    ItalicButton.Down:=(fsItalic in FontDialog.Font.Style);
    UnderButton.Down:=(fsUnderline in FontDialog.Font.Style);
    StrikeButton.Down:=(fsStrikeOut in FontDialog.Font.Style);
    Form1.FontSizeEditChange(Sender);
  end;
end;

procedure TForm1.ShowPaletteButtonClick(Sender: TObject);
begin
//  PalettePanel.Visible:=ShowPaletteButton.Down;
end;

procedure TForm1.ShowSceneDetailsButtonClick(Sender: TObject);
begin
  SceneDetailsPanel.Visible:=ShowSceneDetailsButton.Down;
  Splitter1.Visible:=ShowSceneDetailsButton.Down;
  If SceneDetailsPanel.Visible Then Splitter1.Left:=SceneDetailsPanel.Left-2;
  If Not ShowSceneDetailsButton.Down Then Begin
    DetailForm.Hide;
    DetachDetailsSpeedButton.Down:=False;
    DetachDetailsSpeedButtonClick(Sender);
  end;
end;

procedure TForm1.ShowTPGEditButtonClick(Sender: TObject);
Var Curl:TVCurl;Template:TVTemplate;
    I,N:Longint;
    CurlName,TemplName:String;
begin
  TPGEditGroupBox.Visible:=ShowTPGEditButton.Down;
  If Not ShowTPGEditButton.Down Then Begin
    TPGEditForm.Hide;
    DetachTPGSpeedButton.Down:=False;
    DetachTPGSpeedButtonClick(Sender);
  end;
  TPGEditGroupBox.Visible:=ShowTPGEditButton.Down;
  //If Form1.WindowState=wsMaximized
  If Form1.Left+Form1.Width>=Screen.Width-5 Then
    TPGEditForm.Left:=Screen.Width-TpgEditForm.Width-1
  Else TPGEditForm.Left:=Form1.Left+Form1.Width+1;
  TPGEditForm.Top:=Form1.Top;
  TPGEditForm.Height:=Form1.Height;
  If PrimitivesPageControl.ActivePage=TemplatesTabSheet Then Begin
    TPGEditMemo.Clear;
    If TemplateList.Count>0 Then
      For I:=0 To TemplateList.Count-1 Do Begin
        If TemplateList.Selected[I] Then Begin
          TemplateList.Items[I];
          N:=Scene.VTemplateList.IndexOf(TemplName);
          Template:=Scene.VTemplateList.Objects[N] As TVTemplate;
          TPGEditMemo.Lines.AddStrings(Template.DisplayList);
        End;
      end;
  end;
  If PrimitivesPageControl.ActivePage=CurlsTabSheet Then Begin
    TPGEditMemo.Clear;
    If CurlList.Count>0 Then
      For I:=0 To CurlList.Count-1 Do Begin
        If CurlList.Selected[I] Then Begin
          CurlName:=CurlList.Items[I];
          N:=Scene.VCurlList.IndexOf(CurlName);
          Curl:=Scene.VCurlList.Objects[N] As TVCurl;
          TPGEditMemo.Lines.AddStrings(Curl.DisplayList);
        End;
      end;
  end;
end;

Function CreateObjectPort(ObjectName,Style:String):String;
Var Obj:TVObject;Port:TVPort;
    PrimitiveName,PortName,X,Y:String;
    N:Longint;AccObject:TAccObject;
    NonAccCommand:String;
Begin
  N:=Scene.VObjectList.IndexOf(ObjectName);
  If N<0 Then Begin Result:='Error, no object:'+ObjectName;Exit;End;
  Obj:=Scene.VObjectList.Objects[N] As TVObject;
  PortName:=GetValByName(Style,'Name');
  If PortName='' Then Begin
    //если имя не указано создать автоименованный порт
    PortName:='Port'+IntToStr(Obj.PortList.Count+1);
  End;
  X:=GetValByName(Style,'X');
  Y:=GetValByName(Style,'Y');
  If X='' Then X:='0.5';
  If Y='' Then Y:='0.5';
  If Obj.PortList.IndexOf(PortName)>=0 Then Begin Result:='Error, port already exists:'+PortName;Exit;End;
  Port:=TVPort.Create;
  Port.Name:=PortName;
  Port.AR:='R';
  Port.X:=StrToFloat(X);
  Port.Y:=StrToFloat(Y);
  Port.AX:=Obj.Shell.X1+Port.X*(Obj.Shell.X2-Obj.Shell.X1);
  Port.AY:=Obj.Shell.Y1+Port.Y*(Obj.Shell.Y2-Obj.Shell.Y1);
  Port.Connection:='';
  Port.ConnectionPort:='';
  Obj.PortList.AddObject(PortName,Port);
  NonAccCommand:='UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone);
  AccObject:=TAccObject.Create;
  AccObject.AcceleratedCommand:=AccelerateCommand(NonAccCommand);
  Obj.DisplayList.AddObject(NonAccCommand,AccObject);
  Scene.ExecCommand('DrawObject '+Obj.Name,ZeroAcc,0);
  Result:=PortName;
End;

Function CreateObject(Options:String):String;
Var Obj:TVObject;
    PrimitiveName:String;
    AccObject:TAccObject;
    Xw1,Yw1,Xw2,Yw2,W,H:Extended;
    NonAccCommand:String;
    N:Longint;
    Name:String;
    Xs,Ys,X2s,Y2s,Ast,Ss,Ws,Hs,Color,BGColor,Width:String;
Begin
  Name:=GetValByName(Options,'Name');
  If Scene.VObjectList.IndexOf(Name)>=0 Then Begin
    Result:=Name;Exit;
    //duplicate
  End;
  Obj:=TVObject.Create;
  If Name='' Then Begin
    PrimitiveName:=GetNewName(Scene,Scene.VObjectList,'');
  End Else PrimitiveName:=Name;
  Scene.VObjectList.AddObject(PrimitiveName,Obj);
  Obj.Saveable:=(LowerCase(ConfigFile.Values['InterpreterCreatesSaveable'])='yes')Or
     (LowerCase(ConfigFile.Values['InterpreterCreatesSaveable'])='on') Or
     (LowerCase(ConfigFile.Values['InterpreterCreatesSaveable'])='y') Or
     (LowerCase(ConfigFile.Values['InterpreterCreatesSaveable'])='1');
  Form1.CurrentEditingNameEdit.Text:=PrimitiveName;
  Form1.CurrentEditingNameEdit.Enabled:=True;
  Obj.Name:=PrimitiveName;            //switch back
  Obj.Style:=Options;
  Scene.ObjectStyle2Attr(Obj);
  Scene.UpdateObjectDisplayList(Obj);
  Scene.View.Add('DrawObject '+PrimitiveName);
  Result:=Obj.Name;
 // Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  ExecCommand('DrawObject '+Name);
End;

Function CreateCallout(Options:String):String;
Var Callout:TVCallout;Obj:TVObject;
    PrimitiveName:String;
    AccObject:TAccObject;
    Xw1,Yw1,Xw2,Yw2,W,H:Extended;
    NonAccCommand:String;
    N:Longint;
    Name:String;
    Xs,Ys,X2s,Y2s,Ast,Ss,Ws,Hs,Color,BGColor,Width:String;
Begin
  Name:=GetValByName(Options,'Name');
  If Scene.VCalloutList.IndexOf(Name)>=0 Then Begin
     Result:=Name;Exit;
     //duplicate
   End;
  Callout:=TVCallout.Create;
  If Name='' Then Begin
    PrimitiveName:=GetNewName(Scene,Scene.VCalloutList,'');
  End Else PrimitiveName:=Name;
  Scene.VCalloutList.AddObject(PrimitiveName,Callout);
  Callout.Saveable:=(LowerCase(ConfigFile.Values['InterpreterCreatesSaveable'])='yes')Or
     (LowerCase(ConfigFile.Values['InterpreterCreatesSaveable'])='on') Or
     (LowerCase(ConfigFile.Values['InterpreterCreatesSaveable'])='y') Or
     (LowerCase(ConfigFile.Values['InterpreterCreatesSaveable'])='1');

  Form1.CurrentEditingNameEdit.Text:=PrimitiveName;
  Form1.CurrentEditingNameEdit.Enabled:=True;
  Callout.Name:=PrimitiveName;            //switch back
  Callout.Style:=Options;
  Scene.CalloutStyle2Attr(Callout);
  Scene.UpdateCalloutDisplayList(Callout);
 // Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  ExecCommand('DrawCallout '+Name);
  Result:=Callout.Name;
End;

Function CreateConnection(Options:String):String;
Var Conn:TVConnection;StartObj,EndObj:TVObject;
    PrimitiveName:String;
    AccObject:TAccObject;
    Xw1,Yw1,Xw2,Yw2,W,H:Extended;
    NonAccCommand:String;
    N:Longint;
    Name:String;
    Xs,Ys,X2s,Y2s,Ast,Ss,Ws,Hs,Color,BGColor,Width:String;
    ConnPort:TVConnectionPort;
    StartPort,EndPort:TVPort;
Begin
  Name:=GetValByName(Options,'Name');
  If Scene.VConnectionList.IndexOf(Name)>=0 Then Begin
     Result:=Name;Exit;
     //duplicate
   End;
  Conn:=TVConnection.Create;
  If Name='' Then Begin
    PrimitiveName:=GetNewName(Scene,Scene.VConnectionList,'');
  End Else PrimitiveName:=Name;
  Conn.Name:=PrimitiveName;
  Scene.VConnectionList.AddObject(PrimitiveName,Conn);
  Conn.Saveable:=(LowerCase(ConfigFile.Values['InterpreterCreatesSaveable'])='yes')Or
     (LowerCase(ConfigFile.Values['InterpreterCreatesSaveable'])='on') Or
     (LowerCase(ConfigFile.Values['InterpreterCreatesSaveable'])='y') Or
     (LowerCase(ConfigFile.Values['InterpreterCreatesSaveable'])='1');

  Form1.CurrentEditingNameEdit.Text:=PrimitiveName;
  Form1.CurrentEditingNameEdit.Enabled:=True;
     //switch back

  Conn.Style:=Options;
  Scene.ConnectionStyle2Attr(Conn);
  Scene.UpdateConnectionDisplayList(Conn);
//  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  Result:=Conn.Name;
  If Scene.VObjectList.IndexOf(Conn.StartObj)<0 Then Exit;//как правильно создавать связь к несуществующему объекту?
  If Scene.VObjectList.IndexOf(Conn.EndObj)<0 Then Exit;
  StartObj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(Conn.StartObj)] As TVObject;
  EndObj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(Conn.EndObj)] As TVObject;
      ConnPort:=TVConnectionPort.Create;
      ConnPort.PortType:='Start';
      ConnPort.X:=0;
      ConnPort.Y:=0;
      ConnPort.AR:='R';
      ConnPort.ConnectedObject:=StartObj.Name;
      If Conn.StartPort='' Then Begin
        //Сщздать порт автоматически
        Conn.StartPort:=CreateObjectPort(StartObj.Name,'');
      End; //Else Begin
        N:=StartObj.PortList.IndexOf(Conn.StartPort);
        StartPort:=StartObj.PortList.Objects[N] As TVPort;
        ConnPort.ConnectedPort:=Conn.StartPort;
        StartPort.Connection:=Conn.Name;
        StartPort.ConnectionPort:='Start';
//      end;
      Conn.PortList.AddObject('Start',ConnPort);
      ConnPort:=TVConnectionPort.Create;
      ConnPort.PortType:='End';
      ConnPort.X:=100;
      ConnPort.Y:=100;
      ConnPort.AR:='R';
      ConnPort.ConnectedObject:=EndObj.Name;
      Conn.PortList.AddObject('End',ConnPort);
      If Conn.EndPort='' Then Begin
        //создать порт автоматически
        Conn.EndPort:=CreateObjectPort(EndObj.Name,'');
      End;// Else Begin
        N:=EndObj.PortList.IndexOf(Conn.EndPort);
        EndPort:=EndObj.PortList.Objects[N] As TVPort;
        ConnPort.ConnectedPort:=Conn.EndPort;
        EndPort.Connection:=Conn.Name;
        EndPort.ConnectionPort:='End';
//      End;
      Scene.UpdateConnectionDisplayList(Conn);
 /////     Scene.ExecCommand('DrawConnection '+Conn.Name,ZeroAcc,0); - это типа CreateConnectionBatch
//      Dispatcher.ExecCommand('self::CAD_Scene2GUI');
End;

Function CreateNPConnection(Options:String):String;
Var Conn:TVConnection;StartObj,EndObj:TVObject;
    PrimitiveName:String;
    AccObject:TAccObject;
    Xw1,Yw1,Xw2,Yw2,W,H:Extended;
    NonAccCommand:String;
    N:Longint;
    Name:String;
    Xs,Ys,X2s,Y2s,Ast,Ss,Ws,Hs,Color,BGColor,Width:String;
    ConnPort:TVConnectionPort;
Begin
  Name:=GetValByName(Options,'Name');
  If Scene.VConnectionList.IndexOf(Name)>=0 Then Begin
     Result:=Name;Exit;
     //duplicate
  End;
  Conn:=TVConnection.Create;
  If Name='' Then Begin
    PrimitiveName:=GetNewName(Scene,Scene.VConnectionList,'');
  End Else PrimitiveName:=Name;
  Conn.Name:=PrimitiveName;
  Scene.VConnectionList.AddObject(PrimitiveName,Conn);
  Form1.CurrentEditingNameEdit.Text:=PrimitiveName;
  Form1.CurrentEditingNameEdit.Enabled:=True;
     //switch back

  Conn.Style:=Options;
  Scene.ConnectionStyle2Attr(Conn);
  Scene.UpdateConnectionDisplayList(Conn);
//  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  Result:=Conn.Name;
  If Scene.VObjectList.IndexOf(Conn.StartObj)<0 Then Exit;//соединение в никуда
  If Scene.VObjectList.IndexOf(Conn.EndObj)<0 Then Exit;//соединение в никуда
  StartObj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(Conn.StartObj)] As TVObject;
  EndObj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(Conn.EndObj)] As TVObject;
      ConnPort:=TVConnectionPort.Create;
      ConnPort.PortType:='Start';
      ConnPort.X:=0;
      ConnPort.Y:=0;
      ConnPort.AR:='R';
      ConnPort.ConnectedObject:=StartObj.Name;
      ConnPort.ConnectedPort:='';
      StartObj.NonPortConnectionList.Add(Conn.Name);
      Conn.PortList.AddObject('Start',ConnPort);
      ConnPort:=TVConnectionPort.Create;
      ConnPort.PortType:='End';
      ConnPort.X:=100;
      ConnPort.Y:=100;
      ConnPort.AR:='R';
      ConnPort.ConnectedObject:=EndObj.Name;
      Conn.PortList.AddObject('End',ConnPort);
      ConnPort.ConnectedPort:='';
      EndObj.NonPortConnectionList.Add(Conn.Name);
      Scene.UpdateConnectionDisplayList(Conn);
      Scene.ExecCommand('DrawConnection '+Conn.Name,ZeroAcc,0);
  //    Dispatcher.ExecCommand('self::CAD_Scene2GUI');
End;

Function SetSource(Name,Src:String):String;
Var Callout:TVCallout;Obj:TVObject;
    PrimitiveName:String;
    AccObject:TAccObject;
    Xw1,Yw1,Xw2,Yw2,W,H:Extended;
    NonAccCommand:String;
    N:Longint;
    Xs,Ys,X2s,Y2s,Ast,Ss,Ws,Hs,Color,BGColor,Width:String;
Begin
  Case GetTypeByName(Scene,Name) of
  'object': Begin
      Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(Name)] as TVObject;
      Obj.Source:=Src;
      Scene.UpdateObjectDisplayList(Obj);
      ExecCommand('DrawObject '+Name);
    End;
  'callout': Begin
      Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(Name)] as TVCallout;
      Callout.Source:=Src;
      Scene.UpdateCalloutDisplayList(Callout);
      ExecCommand('DrawCallout '+Name);
    End;
  End;
End;

Function SetText(Name,Text:String):String;
Var Callout:TVCallout;
    PrimitiveName:String;
    AccObject:TAccObject;
    Xw1,Yw1,Xw2,Yw2,W,H:Extended;
    NonAccCommand:String;
    N:Longint;
    Xs,Ys,X2s,Y2s,Ast,Ss,Ws,Hs,Color,BGColor,Width:String;
Begin
  Case GetTypeByName(Scene,Name) of
  'callout': Begin
      Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(Name)] as TVCallout;
      Callout.Text:=Text;
      Scene.UpdateCalloutDisplayList(Callout);
      ExecCommand('DrawCallout '+Name);
    End;
  End;
End;

Function GetAttr(ItemName,AttrName:String):String;
Var Obj:TVObject;
    Callout:TVCallout;
    Conn:TVConnection;
    Style:String;
Begin
  Case GetTypeByName(Scene,ItemName) of
  'object': Begin
      Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(ItemName)] as TVObject;
      Style:=Obj.Style;
            End;
  'callout': Begin
      Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(ItemName)] as TVCallout;
      Style:=Callout.Style;
            End;
  'connection': Begin
      Conn:=Scene.VConnectionList.Objects[Scene.VConnectionList.IndexOf(ItemName)] as TVConnection;
      Style:=Conn.Style;
                End;
  'none':Style:='';
  End;
  Result:=GetValByName(Style,AttrName);
End;

Function SetAttr(ItemName,AttrName,Value:String):String;
Var Obj:TVObject;
    Callout:TVCallout;
    Conn:TVConnection;
    Style:String;
    I,I1,I2:Longint;
    Found:Boolean;
Begin
  Case GetTypeByName(Scene,ItemName) of
  'object': Begin
      Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(ItemName)] as TVObject;
      Style:=Obj.Style;
            End;
  'callout': Begin
      Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(ItemName)] as TVCallout;
      Style:=Callout.Style;
            End;
  'connection': Begin
      Conn:=Scene.VConnectionList.Objects[Scene.VConnectionList.IndexOf(ItemName)] as TVConnection;
      Style:=Conn.Style;
                End;
  'none':Exit;
  End;
//  Result:=GetValByName(Style,AttrName);
  I1:=Pos(AttrName,Style);
  Found:=False;
  For I:=I1 To Length(Style) Do
    If Style[I]=' ' Then Begin
      I2:=I;Found:=True;Break;
    End;
  If Not(Found) Then I2:=Length(Style);
  Delete(Style,I1,I2-I1+1);
  Insert(AttrName+'='+Value+' ',Style,I1);
  Case GetTypeByName(Scene,ItemName) of
  'object': Begin
      Obj.Style:=Style;
      Scene.ObjectStyle2Attr(Obj);
      Scene.UpdateObjectDisplayList(Obj);
            End;
  'callout': Begin
      Callout.Style:=Style;
      Scene.CalloutStyle2Attr(Callout);
      Scene.UpdateCalloutDisplayList(Callout);
            End;
  'connection': Begin
      Conn.Style:=Style;
      Scene.ConnectionStyle2Attr(Conn);
      Scene.UpdateConnectionDisplayList(Conn);
                End;
  'none':
  End;
End;

Function FixItem(ItemName:String):String;
Var Obj:TVObject;
    Callout:TVCallout;
    Conn:TVConnection;
    Style:String;
    X,Y:Extended;
Begin
  Case GetTypeByName(Scene,ItemName) of
  'object': Begin
      Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(ItemName)] as TVObject;
      Style:=Obj.Style;
      Scene.MoveObjectTo(Obj,Obj.X,Obj.Y,'');
            End;
  'callout': Begin
      Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(ItemName)] as TVCallout;
      Style:=Callout.Style;
            End;
  'connection': Begin
      Conn:=Scene.VConnectionList.Objects[Scene.VConnectionList.IndexOf(ItemName)] as TVConnection;
      Style:=Conn.Style;
                End;
  End;

End;

Function ModAttr(ItemName,AttrName,Delta:String):String;
Var Obj:TVObject;
    Callout:TVCallout;
    Conn:TVConnection;
    Style:String;
    I,I1,I2:Longint;
    Found:Boolean;
    Value:String;
    iVal,iDelta:Longint;fVal:Extended;
    iMod,fMod:Boolean;
Begin
  Case GetTypeByName(Scene,ItemName) of
  'object': Begin
      Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(ItemName)] as TVObject;
      Style:=Obj.Style;
            End;
  'callout': Begin
      Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(ItemName)] as TVCallout;
      Style:=Callout.Style;
            End;
  'connection': Begin
      Conn:=Scene.VConnectionList.Objects[Scene.VConnectionList.IndexOf(ItemName)] as TVConnection;
      Style:=Conn.Style;
                End;
  End;
  Value:=GetValByName(Style,AttrName);
  I1:=Pos(AttrName,Style);
  Found:=False;
  For I:=I1 To Length(Style) Do
    If Style[I]=' ' Then Begin
      I2:=I;Found:=True;Break;
    End;
  If Not(Found) Then I2:=Length(Style);
  Delete(Style,I1,I2-I1+1);
  iMod:=False;fMod:=False;
  If TryStrToInt(Value,iVal) And (TryStrToInt(Delta,iDelta)) Then Begin
    iVal:=iVal+iDelta;iMod:=True;
  End Else
   If TryStrToFloat(Value,fVal) Then Begin
     fVal:=fVal+StrToFloat(Delta);
     fMod:=True;
   end;
  If iMod Then Value:=IntToStr(iVal);
  If fMod Then Value:=FloatToStr(fVal);
  Insert(AttrName+'='+Value+' ',Style,I1);
  Case GetTypeByName(Scene,ItemName) of
  'object': Begin
      Obj.Style:=Style;
      Scene.ObjectStyle2Attr(Obj);
      Scene.UpdateObjectDisplayList(Obj);
//      Scene.MoveObjectTo(Obj,Obj.X,Obj.Y,''); //Grouplist='' а почему?
            End;
  'callout': Begin
      Callout.Style:=Style;
      Scene.CalloutStyle2Attr(Callout);
      Scene.UpdateCalloutDisplayList(Callout);
            End;
  'connection': Begin
      Conn.Style:=Style;
      Scene.ConnectionStyle2Attr(Conn);
      Scene.UpdateConnectionDisplayList(Conn);
                End;
  End;
End;

Procedure Curl2Object(Curl:TVCurl;Obj:TVObject;BaseX,BaseY:Extended);
Var I,J,K:Longint;
    Command,Buf,ParsedBuf,Cmd:String;
    Xs,Ys:Longint;xws,yws:String;
    X2s,Y2s:Longint;x2ws,y2ws:String;
    Xw,Yw:Extended;
    X2w,Y2w:Extended;
    Delta:Extended;
    P,p1,p2:TCPoint;
    AccObject:TAccObject;
Begin
  LogMessage(5,'converting curl'+Curl.Name);
  For I:=0 To Curl.DisplayList.Count-1 Do Begin
    Command:=Curl.DisplayList[I];
    Buf:=Command;
    Cmd:=GetNextToken(Buf,ParsedBuf,' ');
    Buf:=ParsedBuf;
    If (Cmd='LineTo') Or (Cmd='MoveTo') Then Begin
      Xws:=GetNextToken(Buf,ParsedBuf,',');
      Yws:=ParsedBuf;
      If TryStrToFloat(Xws,Xw) Then Xw:=StrToFloat(Xws)-BaseX
      Else Xw:=0;
      If TryStrToFloat(Yws,Yw) Then Yw:=StrToFloat(Yws)-BaseY
      Else Yw:=0;
      AccObject:=TAccObject.Create;
      AccObject.AcceleratedCommand:=AccelerateCommand(Command);
      AccObject.AcceleratedCommand[2]:=Xw;
      AccObject.AcceleratedCommand[3]:=Yw;
      Obj.DisplayList.AddObject(Cmd+' '+FloatToStr(Xw)+','+FloatToStr(Yw),AccObject);
    End Else Begin
      AccObject:=TAccObject.Create;
      AccObject.AcceleratedCommand:=AccelerateCommand(Command);
      Obj.DisplayList.AddObject(Command,AccObject);
    End;
  end;
  Obj.X:=BaseX;Obj.Y:=BaseY;Obj.A:=0;Obj.S:=1;
end;

Procedure Curl2Template(Curl:TVCurl;Templ:TVTemplate;BaseX,BaseY:Extended);
Var I,J,K:Longint;
    Command,Buf,ParsedBuf,Cmd:String;
    Xs,Ys:Longint;xws,yws:String;
    X2s,Y2s:Longint;x2ws,y2ws:String;
    Xw,Yw:Extended;
    X2w,Y2w:Extended;
    Delta:Extended;
    P,p1,p2:TCPoint;
    AccObject:TAccObject;
Begin
  LogMessage(5,'converting curl'+Curl.Name);
  For I:=0 To Curl.DisplayList.Count-1 Do Begin
    Command:=Curl.DisplayList[I];
    Buf:=Command;
    Cmd:=GetNextToken(Buf,ParsedBuf,' ');
    Buf:=ParsedBuf;
    Case Cmd Of
    'LineTo','MoveTo': Begin
        Xws:=GetNextToken(Buf,ParsedBuf,',');
        Yws:=ParsedBuf;
        Xw:=StrToFloat(Xws)-BaseX;Yw:=StrToFloat(Yws)-BaseY;
        AccObject:=TAccObject.Create;
        AccObject.AcceleratedCommand:=AccelerateCommand(Command);
        AccObject.AcceleratedCommand[2]:=Xw;
        AccObject.AcceleratedCommand[3]:=Yw;
        Templ.DisplayList.AddObject(Cmd+' '+FloatToStr(Xw)+','+FloatToStr(Yw),AccObject);
      End;
    'Rect','Ellipse': Begin
        Xws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        Yws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        X2ws:=GetNextToken(Buf,ParsedBuf,',');
        Y2ws:=ParsedBuf;
        Xw:=StrToFloat(Xws)-BaseX;Yw:=StrToFloat(Yws)-BaseY;
        X2w:=StrToFloat(X2ws)-BaseX;Y2w:=StrToFloat(Y2ws)-BaseY;
        AccObject:=TAccObject.Create;
        AccObject.AcceleratedCommand:=AccelerateCommand(Command);
        AccObject.AcceleratedCommand[2]:=Xw;
        AccObject.AcceleratedCommand[3]:=Yw;
        AccObject.AcceleratedCommand[4]:=X2w;
        AccObject.AcceleratedCommand[5]:=Y2w;
        Templ.DisplayList.AddObject(Cmd+' '+FloatToStr(Xw)+','+FloatToStr(Yw)+','+FloatToStr(X2w)+','+FloatToStr(Y2w),AccObject);
        End;
    'Circle': Begin
        Xws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        Yws:=GetNextToken(Buf,ParsedBuf,',');
        Xw:=StrToFloat(Xws)-BaseX;Yw:=StrToFloat(Yws)-BaseY;
        AccObject:=TAccObject.Create;
        AccObject.AcceleratedCommand:=AccelerateCommand(Command);
        AccObject.AcceleratedCommand[2]:=Xw;
        AccObject.AcceleratedCommand[3]:=Yw;
        Templ.DisplayList.AddObject(Cmd+' '+FloatToStr(Xw)+','+FloatToStr(Yw)+','+ParsedBuf,AccObject);
      end;
    'TextOut': Begin
        Xws:=GetNextToken(Buf,ParsedBuf,',');
        Buf:=ParsedBuf;
        Yws:=GetNextToken(Buf,ParsedBuf,',');
        Xw:=StrToFloat(Xws)-BaseX;Yw:=StrToFloat(Yws)-BaseY;
        AccObject:=TAccObject.Create;
        AccObject.AcceleratedCommand:=AccelerateCommand(Command);
        AccObject.AcceleratedCommand[2]:=Xw;
        AccObject.AcceleratedCommand[3]:=Yw;
        Templ.DisplayList.AddObject(Cmd+' '+FloatToStr(Xw)+','+FloatToStr(Yw)+','+ParsedBuf,AccObject)
      End Else Begin
        AccObject:=TAccObject.Create;
        AccObject.AcceleratedCommand:=AccelerateCommand(Command);
        Templ.DisplayList.AddObject(Command,AccObject);
      End;
    End;
  end;
end;

Function SimplifyCurl(Curl:TVCurl):TVCurl;
Var I,J,K:Longint;
    Command,Buf,ParsedBuf,Cmd:String;
    Xs,Ys:Longint;xws,yws:String;
    X2s,Y2s:Longint;x2ws,y2ws:String;
    Xw,Yw:Extended;
    X2w,Y2w:Extended;
    Delta:Extended;
    PointList:TStringList;
    P,p1,p2,p3:TCPoint;
    ResultCurl:TVCurl;
Begin
  LogMessage(5,'simplifyling curl'+Curl.Name);
  PointList:=TStringList.Create;
  For I:=0 To Curl.DisplayList.Count-1 Do Begin
    Command:=Curl.DisplayList[I];
    Buf:=Command;
    Cmd:=GetNextToken(Buf,ParsedBuf,' ');
    Buf:=ParsedBuf;
    P:=TCPoint.Create;
    If (Cmd='LineTo') Or (Cmd='MoveTo') Then Begin
      Xws:=GetNextToken(Buf,ParsedBuf,',');
      Yws:=ParsedBuf;
      Xw:=StrToFloat(Xws);Yw:=StrToFloat(Yws);
      Drawer.WtoS(Xw,Yw,Xs,Ys);
      P.xw:=Xw;P.yw:=Yw;P.xs:=Xs;P.ys:=Ys;
    End Else Begin
      P.xw:=0;P.yw:=0;P.xs:=0;P.ys:=0;
    End;
    PointList.AddObject(Cmd,P);
  end;
 { // Simple DXDY
   For I:=0 To PointList.Count-1 Do Begin
    p1:=PointList.Objects[I] As TCPoint;
    If I<PointList.Count-1 Then Begin
      p2:=PointList.Objects[I+1] As TCPoint;
      P1.dx:=P2.xs-P1.xs;
      P1.dy:=P2.ys-P1.ys;
      If P1.dy=0 Then P1.dxdy:=9999999999999*sign(P1.dx)
      Else P1.dxdy:=P1.dx/P1.dy;
    End Else Begin
      p2:=PointList.Objects[I-1] As TCPoint;
      P1.dx:=-(P2.xs-P1.xs);
      P1.dy:=-(P2.ys-P1.ys);
      If P1.dy=0 Then P1.dxdy:=-9999999999999*sign(P1.dx)
      Else P1.dxdy:=P1.dx/P1.dy;
    end;
//    TPGEditForm.Memo1.Lines[I]:=TPGEditForm.Memo1.Lines[I]+' '+PointList[I]+' '+FloatToStr(P1.xs)+' '+FloatToStr(P1.ys)+' '+FloatToStr(P1.dx)+' '+FloatToStr(P1.dy)+' '+FloatToStr(P1.dxdy);
  end;}

{  // DDX version
   For I:=0 To PointList.Count-1 Do Begin
    p1:=PointList.Objects[I] As TCPoint;
    If I<PointList.Count-1 Then Begin
      p2:=PointList.Objects[I+1] As TCPoint;
      P1.ddx:=P2.dx-P1.dx;
      P1.ddy:=P2.dy-P1.dy;
    End Else Begin
      p2:=PointList.Objects[I-1] As TCPoint;
      P1.ddx:=-(P2.dx-P1.dx);
      P1.ddy:=-(P2.dy-P1.dy);
    end;
    TPGEditForm.Memo1.Lines[I]:=TPGEditForm.Memo1.Lines[I]+' '+PointList[I]+' '+FloatToStr(P1.xs)+' '+FloatToStr(P1.ys)+' '+FloatToStr(P1.dx)+' '+FloatToStr(P1.dy)+' '+FloatToStr(P1.ddx)+' '+FloatToStr(P1.ddy)+' '+FloatToStr(P1.dxdy);
  end;}
  I:=0;
  Repeat
    If (PointList[I]<>'LineTo')And(PointList[I]<>'MoveTo') Then Begin Inc(I);Continue;End;
    P1:=PointList.Objects[I] As TCPoint;
    P1.dx:=0;    P1.dy:=0;
    J:=I+1;
    While (J<PointList.Count-1)And((PointList[J]='LineTo')Or(PointList[J]<>'MoveTo')) Do Begin
      P2:=PointList.Objects[J] As TCPoint;
      P2.dx:=P2.xs-P1.xs;
      P2.dy:=P2.ys-P1.ys;
      If (P2.dx<>0)And(P2.dy<>0) Then Begin P2.dxdy:=P2.dx/P2.dy;P2.dydx:=P2.dy/P2.dx;End;
      If P2.dy=0 Then Begin P2.dxdy:=9999999999999*sign(P1.dx);P2.dydx:=0;End;
      If P2.dx=0 Then Begin P2.dxdy:=0;P2.dydx:=9999999999999*sign(P1.dy);End;
      Form1.TPGEditMemo.Lines[J]:=Form1.TPGEditMemo.Lines[J]+' '+PointList[J]+' '+FloatToStr(P2.xs)+' '+FloatToStr(P2.ys)+' '+FloatToStr(P2.dx)+' '+FloatToStr(P2.dy)+' '+FloatToStr(P2.ddx)+' '+FloatToStr(P2.ddy)+' '+FloatToStr(P2.dxdy);
      P3:=PointList.Objects[J-1] As TCPoint;
      If (Abs(P2.dxdy-P3.dxdy)<0.1)And(Abs(P2.dydx-P3.dydx)<0.1) Then Begin
        PointList[J]:='nop';
    //    TPGEditForm.Memo1.Lines[J]:=TPGEditForm.Memo1.Lines[J]+'nop';
        Inc(J);
      End Else Begin
        Inc(J);
      end;
    End;
    I:=J+1;
  Until I>=PointList.Count-1;

{  Repeat
    If (PointList[I]<>'LineTo')And(PointList[I]<>'MoveTo') Then Begin Inc(I);Continue;End;
    P1:=PointList.Objects[I] As TCPoint;
    J:=I+1;
    While (J<PointList.Count-1)And((PointList[J]='LineTo')Or(PointList[J]<>'MoveTo')) Do Begin
      P2:=PointList.Objects[J] As TCPoint;
{      If ((Abs(P2.dxdy-P1.dxdy)<1.1)Or((Abs(P2.dx)+Abs(P2.dy))<5))And(Abs(P2.xs-P1.xs)+Abs(P2.ys-P1.ys)<30) Then Begin
        PointList[J]:='nop';
//        TPGEditForm.Memo1.Lines[J]:=TPGEditForm.Memo1.Lines[J]+'nop';
        Inc(J);
      End Else Begin
//        Inc(J);
        Break;
      end;}
{      If (Abs(P2.ddx)+Abs(P2.ddy))<5 Then Begin
           PointList[J]:='nop';
              TPGEditForm.Memo1.Lines[J]:=TPGEditForm.Memo1.Lines[J]+'nop';
              Inc(J);
      End Else Begin
      //        Inc(J);
              Break;
      end;
    End;}
    I:=J+1;
  Until I>=PointList.Count-1;}
  ResultCurl:=TVCurl.Create;
  ResultCurl.Name:=Curl.Name;
  For I:=0 To Curl.DisplayList.Count-1 Do
    If PointList[I]<>'nop' Then
      ResultCurl.DisplayList.Add(Curl.DisplayList[I]);
  PointList.Free;
  Result:=ResultCurl;
end;

procedure TForm1.SimplifyCurlButtonClick(Sender: TObject);
Var CurlName:String;
    Curl,NewCurl:TVCurl;I,J,N:Longint;
begin
  If CurlList.Count>0 Then
    For I:=0 To CurlList.Count-1 Do Begin
      If CurlList.Selected[I] Then Begin
        CurlName:=CurlList.Items[I];
        N:=Scene.VCurlList.IndexOf(CurlName);
        Curl:=Scene.VCurlList.Objects[N] As TVCurl;
        NewCurl:=SimplifyCurl(Curl);
        Curl.Free;
        Scene.VCurlList.Objects[N]:=NewCurl;
        NumCurlsLabel.Caption:=IntToStr(CurlList.Items.Count);
      end;
    end;
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
end;

procedure TForm1.GotoFoundModeDropSpeedButtonClick(Sender: TObject);
begin
  GoToStyleComboBox.DroppedDown:=True;
end;

procedure CopySelection;
Var Obj:TVObject;
    FileBuf,ClipBuf:TStringList;
    I:Longint;
    ItemName:String;
begin
  ClipBuf:=TStringList.Create;
//  If Sender=Nil Then Begin
    CopyOriginX:=CurrentXGw;
    CopyOriginY:=CurrentYGw;
 // End Else Scene.Drawer.StoW(DrawingPanel.ClientWidth div 2,DrawingPanel.ClientHeight div 2,CopyOriginX,CopyOriginY);
  If Form1.SelectionListEditor.RowCount>2 Then Begin
    For I:=1 To Form1.SelectionListEditor.RowCount-1 Do Begin
      ItemName:=Form1.SelectionListEditor.Cells[1,I];
      FileBuf:=Scene.SaveItem(ItemName);
      ClipBuf.AddStrings(FileBuf);
      FileBuf.Free;
    end;
  end Else
    If Form1.CurrentEditingNameEdit.Text<>'' Then Begin
      FileBuf:=Scene.SaveItem(Form1.CurrentEditingNameEdit.Text);
      ClipBuf.AddStrings(FileBuf);
      FileBuf.Free;
    end;
  Clipboard.Clear;
  Clipboard.AsText:=ClipBuf.Text;
  ClipBuf.Free;
end;

procedure PasteSelection;
Var Curl:TVCurl;
    Obj,OldObj:TVObject;
    Callout:TVCallout;
    Connection:TVConnection;
    Port:TVPort;
    FileBuf,ClipBuf,Limiter,Renlist:TStringList;
    I,J,K,K2,N,Index:Longint;
    ItemName,Buf:String;
begin
//  If Sender=Nil Then Begin
    CopyDX:=CurrentXGw;CopyDY:=CurrentYGw;
//  end Else Scene.Drawer.StoW(DrawingPanel.ClientWidth div 2,DrawingPanel.ClientHeight div 2,CopyDX,CopyDY);
  CopyDX:=CopyDX-CopyOriginX;
  CopyDY:=CopyDY-CopyOriginY;
  Limiter:=TStringList.Create;
  ClipBuf:=TStringList.Create;
  ClipBuf.Text:=Clipboard.AsText;
  For I:=0 To ClipBuf.Count-1 Do Begin
    If (Pos('curl name:',LowerCase(ClipBuf[I]))=1) or
       (Pos('object name:',LowerCase(ClipBuf[I]))=1) or
       (Pos('callout name:',LowerCase(ClipBuf[I]))=1) or
       (Pos('connection name:',LowerCase(ClipBuf[I]))=1) or
       (Pos('group name:',LowerCase(ClipBuf[I]))=1) or
       (Pos('view:',LowerCase(ClipBuf[I]))=1)
    Then Limiter.Add(IntToStr(I));
  end;
  Limiter.Add(IntToStr(ClipBuf.Count));
  RenList:=TStringList.Create;
  For I:=0 To Limiter.Count-2 Do Begin
{    If (Pos('curl name:',LowerCase(ClipBuf[StrToInt(Limiter[I])]) )=1) Then Begin
      FileBuf:=TStringList.Create;
      For J:=StrToInt(Limiter[I]) To StrToInt(Limiter[I+1])-1 Do
        FileBuf.Add(ClipBuf[J]);
      Curl:=Scene.LoadCurl(0,True,FileBuf);
      FileBuf.Free;
    End;}
    If (Pos('object name:',LowerCase(ClipBuf[StrToInt(Limiter[I])]) )=1) Then Begin
      FileBuf:=TStringList.Create;
      For J:=StrToInt(Limiter[I]) To StrToInt(Limiter[I+1])-1 Do
        FileBuf.Add(ClipBuf[J]);
      Obj:=Scene.LoadObject(0,True,CopyDX,CopyDY,FileBuf,RenList);
      Scene.UpdateObjectDisplayList(Obj);
      //RenderShell included. Ports?
      Scene.UpdateObjectPorts(Obj);
      FileBuf.Free;
    End;
    If (Pos('callout name:',LowerCase(ClipBuf[StrToInt(Limiter[I])]) )=1) Then Begin
      FileBuf:=TStringList.Create;
      For J:=StrToInt(Limiter[I]) To StrToInt(Limiter[I+1])-1 Do
        FileBuf.Add(ClipBuf[J]);
      Callout:=Scene.LoadCallout(0,True,CopyDX,CopyDY,FileBuf,RenList);
      FileBuf.Free;
    End;
    If (Pos('connection name:',LowerCase(ClipBuf[StrToInt(Limiter[I])]) )=1) Then Begin
         FileBuf:=TStringList.Create;
         For J:=StrToInt(Limiter[I]) To StrToInt(Limiter[I+1])-1 Do
           FileBuf.Add(ClipBuf[J]);
         Connection:=Scene.LoadConnection(0,True,CopyDX,CopyDY,FileBuf,RenList);
         FileBuf.Free;
    End;
  end;

  For I:=0 To RenList.Count-1 Do Begin
    N:=Scene.VObjectList.IndexOf(RenList.ValueFromIndex[I]);//по всем новым объектам
    If N>=0 Then Begin
      Obj:=Scene.VObjectList.Objects[N] As TVObject;
      If Obj.PortList.Count>0 Then //переименование скопированных связей в новых объектах
        For J:=0 To Obj.PortList.Count-1 Do Begin
          Port:=Obj.PortList.Objects[J] As TVPort;
          Buf:=RenList.Values[Port.Connection];
          Port.Connection:=Buf;
        end;
      If Obj.NonPortConnectionList.Count>0 Then //переименование скопированных связей в новых объектах
        For J:=0 To Obj.NonPortConnectionList.Count-1 Do Begin
          Index:=RenList.IndexOfName(Obj.NonPortConnectionList[J]);
          If Index>=0 Then Obj.NonPortConnectionList[J]:=RenList.ValueFromIndex[Index];
{          Index:=RenList.IndexOfName(Connection.StartObj);
          If Index>=0 Then Connection.StartObj:=RenList.ValueFromIndex[Index];
          Index:=RenList.IndexOfName(Connection.EndObj);
          If Index>=0 Then Connection.EndObj:=RenList.ValueFromIndex[Index];}
        end;
      If Obj.RelatedCAList.Count>0 Then //переименование скопированных выносок в новых объектах
        For J:=0 To Obj.RelatedCAList.Count-1 Do Begin
          Buf:=RenList.Values[Obj.RelatedCAList[J]];
          Obj.RelatedCAList[J]:=Buf;
        end;
    End;
  end;
  For I:=0 To RenList.Count-1 Do Begin
    N:=Scene.VConnectionList.IndexOf(RenList.ValueFromIndex[I]);
    If N>=0 Then Begin
      Connection:=Scene.VConnectionList.Objects[N] As TVConnection;
      //если объект-начало числится в оригиналах замены, то исправить
      Index:=RenList.IndexOfName(Connection.StartObj);
      If Index>=0 Then Connection.StartObj:=RenList.ValueFromIndex[Index];
      //если объект-конец числится в оригиналах замены, то исправить
      Index:=RenList.IndexOfName(Connection.EndObj);
      If Index>=0 Then Connection.EndObj:=RenList.ValueFromIndex[Index];
      Scene.ConnectionAttr2Style(Connection);
      Scene.UpdateConnectionDisplayList(Connection);
    end;
  end;
  For I:=0 To RenList.Count-1 Do Begin
    N:=Scene.VCalloutList.IndexOf(RenList.ValueFromIndex[I]);
    If N>=0 Then Begin
      Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
      If Callout.RelatedObj<>'' Then Begin
        Buf:=RenList.Values[Callout.RelatedObj];
        K2:=Scene.VObjectList.IndexOf(Callout.RelatedObj);
        K:=Scene.VObjectList.IndexOf(Buf);
        If K2>=0 Then Begin
          //Remove link to this callout from old object
          OldObj:=Scene.VObjectList.Objects[K2] As TVObject;
          Index:=OldObj.RelatedCAList.IndexOf(Callout.Name);
          If Index>=0 Then OldObj.RelatedCAList.Delete(Index);
        End;
        If K>=0 Then Begin
          //Add link to this callout from new object
          Obj:=Scene.VObjectList.Objects[K] As TVObject;
          Index:=Obj.RelatedCAList.IndexOf(Callout.Name);
          If Index<0 Then Obj.RelatedCAList.AddObject(Callout.Name,Callout);
        End;
        Callout.RelatedObj:=Buf;
      end;
      Scene.CalloutAttr2Style(Callout);
      Scene.UpdateCalloutDisplayList(Callout);
    end;
  end;

{  Obj:=Scene.LoadObject(0,True,ClipBuf);}
  ClipBuf.Free;
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  For I:=0 To RenList.Count-1 Do Begin
    N:=Form1.ObjectList.Items.IndexOf(RenList.ValueFromIndex[I]);
    If N>=0 Then Form1.ObjectList.Selected[N]:=True;
    N:=Form1.CalloutList.Items.IndexOf(RenList.ValueFromIndex[I]);
    If N>=0 Then Form1.CalloutList.Selected[N]:=True;
  end;
  RenList.Free;
  UpdateMultiSelection;
//  Scene.UpdateVisibility;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  //Repaint;
end;

Procedure DeleteItem(ItemName:String);
Var Obj:TVObject;
    Callout:TVCallout;
    Connection:TVConnection;
    Curl:TVCurl;
Begin
  If Scene.VObjectList.IndexOf(ItemName)>=0 Then Begin
    Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(ItemName)] As TVObject;
    Scene.DeleteObject(Obj);
    Exit;
  End;
  If Scene.VCalloutList.IndexOf(ItemName)>=0 Then Begin
    Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(ItemName)] As TVCallout;
    Scene.DeleteCallout(Callout);
    Exit;
  End;
  If Scene.VConnectionList.IndexOf(ItemName)>=0 Then Begin
    Connection:=Scene.VConnectionList.Objects[Scene.VConnectionList.IndexOf(ItemName)] As TVConnection;
    Scene.DeleteConnection(Connection);
    Exit;
  End;
  If Scene.VCurlList.IndexOf(ItemName)>=0 Then Begin
    Curl:=Scene.VCurlList.Objects[Scene.VCurlList.IndexOf(ItemName)] As TVCurl;
//    Scene.DeleteCurl(Curl);
    Exit;
  End;

End;

Procedure DeleteSelection;
Var Obj:TVObject;
    Callout:TVCallout;
    Connection:TVConnection;
    I,J,N:Longint;
begin
  Form1.TPGEditMemo.Clear;
 { If SelectionListEditor.RowCount>2 Then Begin
    For I:=1 To SelectionListEditor.RowCount-1 Do Begin
      ItemName:=SelectionListEditor.Cells[1,I];
    end;
  end Else
    If CurrentEditingNameEdit.Text<>'' Then Begin

    end;}
  If Scene.SelectedList.Count>0 Then
     For I:=Scene.SelectedList.Count-1 DownTo 0 Do Begin
       If Scene.SelectedList.Objects[I] is TVConnection Then Begin
         Connection:=Scene.SelectedList.Objects[I] As TVConnection;
         RemoveItemFromSelection(Connection.Name);
         Scene.DeleteConnection(Connection);
       end;
     end;
  If Scene.SelectedList.Count>0 Then
    For I:=Scene.SelectedList.Count-1 DownTo 0 Do Begin
      If Scene.SelectedList.Objects[I] is TVCallout Then Begin
        Callout:=Scene.SelectedList.Objects[I] As TVCallout;
        RemoveItemFromSelection(Callout.Name);
        Scene.DeleteCallout(Callout);
      end;
    end;
  If Scene.SelectedList.Count>0 Then
    For I:=Scene.SelectedList.Count-1 DownTo 0 Do Begin
      If Scene.SelectedList.Objects[I] is TVObject Then Begin
        Obj:=Scene.SelectedList.Objects[I] As TVObject;
        RemoveItemFromSelection(Obj.Name);
       Scene.DeleteObject(Obj);
      end;
   End;
  UpdateMultiSelection;
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  RepaintView;
end;



procedure TForm1.Splitter2ChangeBounds(Sender: TObject);
begin
  Form1.RefreshSpeedLabel.Left:=Form1.Splitter2.Left+20;
end;

procedure TForm1.Splitter2Moved(Sender: TObject);
begin
  Form1.RefreshSpeedLabel.Left:=Form1.Splitter2.Left+20;
end;

procedure TForm1.TemplateListFilterEditChange(Sender: TObject);
Var I:Longint;
begin
  TemplateList.Items.Clear;
  If TemplateListFilterEdit.Text='' Then TemplateList.Items.Assign(Scene.VTemplateList)
  Else
  If Scene.VTemplateList.Count>0 Then
    For I:=0 To Scene.VTemplateList.Count-1 Do
      If Pos(TemplateListFilterEdit.Text,Scene.VTemplateList[I])<>0 Then
        TemplateList.Items.Add(Scene.VTemplateList[I]);
end;


procedure TForm1.TemplateListSelectionChange(Sender: TObject; User: boolean);
Var TemplName:String;
    Template:TVTemplate;I,J,N:Longint;
begin
  TPGEditMemo.Clear;
  If TemplateList.Count>0 Then
    For I:=0 To TemplateList.Count-1 Do Begin
      If TemplateList.Selected[I] Then Begin
        TemplName:=TemplateList.Items[I];
        N:=Scene.VTemplateList.IndexOf(TemplName);
        Template:=Scene.VTemplateList.Objects[N] As TVTemplate;
//        If TPGEditForm.Visible Then Begin
          TPGEditForm.Caption:='TPG edit: template '+TemplName;
          TPGEditMemo.Lines.AddStrings(Template.DisplayList);
//        End;
      end;
    end;
end;

procedure TForm1.WidthButton1Click(Sender: TObject);
Begin
  If (Sender As TSpeedButton).Down Then WidthButton1.Tag:=StrToInt((Sender As TSpeedButton).Caption);
  Case GetTypeByName(Scene,CurrentEditingNameEdit.Text) of
  'object':  Begin
               ObjectGUI2Scene;
               Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
               RepaintView;
             End;
  'callout': Begin
               CalloutGUI2Scene;
               Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
               RepaintView;
             End;
  'connection': Begin
               ConnectionGUI2Scene;
               Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
  //             Scene.ExecCommand('DrawConnection '+Connection.Nanme);
               RepaintView;
             End;

  end;
End;

procedure TForm1.TextMemoChange(Sender: TObject);
Var Callout:TVCallout;
    I,N:Longint;Buf,ParsedBuf,TemplateName:String;
    Sm,Rm,Scm,tmpm,TransM:TMatrix2D;
begin
  If LockBackUpdate Then Exit;
  If GetTypeByName(Scene,CurrentEditingNameEdit.Text)='callout' Then Begin
    CalloutGUI2Scene;
    RepaintView;
  End;
end;

procedure TForm1.TLabelEditChange(Sender: TObject);
Var W,H:Longint;
    F:TFont;S:String;
begin
  DrawingPanel.Canvas.Font.Assign(TLabelEdit.Font);
  DrawingPanel.Canvas.GetTextSize(TLabelEdit.Text+'  ',w,h);
  TLabelEdit.Width:=W+15;
  TLabelEdit.Height:=H+5;
end;

procedure TForm1.TLabelEditKeyPress(Sender: TObject; var Key: char);
Var Xw,Yw,Xw0,Yw0:Extended;Xg,Yg,N:Longint;BIUS:String;
    Curl:TVCurl;PrimitiveName:String;
    AccObject:TAccObject;
    NonAccCommand:String;
begin
  If Key=#13 Then Begin
    //hide label edit handle
      TLabelEdit.Hide;
      Drawing:=False;
      SelectX1s:=TLabelEdit.Left;
      SelectY1s:=TLabelEdit.Top;
      Drawer.StoW(SelectX1s,SelectY1s,SelectX1w,SelectY1w);
      If SnapToGridButton.Down Then Begin
        SelectX1w:=GridGapEdit.Value*Round(SelectX1w/GridGapEdit.Value);
        SelectY1w:=GridGapEdit.Value*Round(SelectY1w/GridGapEdit.Value);
        Drawer.WtoS(SelectX1w,SelectY1w,SelectX1s,SelectY1s);
      End;
      BIUS:='';
      If fsBold in FontDialog.Font.Style Then BIUS:=BIUS+'b';
      If fsItalic in FontDialog.Font.Style Then BIUS:=BIUS+'i';
      If fsUnderline in FontDialog.Font.Style Then BIUS:=BIUS+'u';
      If fsStrikeOut in FontDialog.Font.Style Then BIUS:=BIUS+'s';
      Curl:=TVCurl.Create;
      PrimitiveName:=GetNewName(Scene,Scene.VCurlList,'text');
      Curl.Saveable:=True;
      Scene.VCurlList.AddObject(PrimitiveName,Curl);
      Curl.Name:=PrimitiveName;
      AccObject:=TAccObject.Create;
      If TextButton.Down Then
        NonAccCommand:='SetFont '+FontDialog.Font.Name+','+IntToStr(FontDialog.Font.Size)+','+ColorToString(FontDialog.Font.Color)+','+bius;
      If ScaledTextButton.Down Then
        NonAccCommand:='SetScaledFont '+FontDialog.Font.Name+','+FloatToStr(FontDialog.Font.Height*ViewScaleEdit.Value)+','+ColorToString(FontDialog.Font.Color)+','+bius;
      AccObject.AcceleratedCommand:=AccelerateCommand(NonAccCommand);
      Curl.DisplayList.AddObject(NonAccCommand,AccObject);
      AccObject:=TAccObject.Create;
      AccObject.AcceleratedCommand:=AccelerateCommand('SetBGColor '+ColorToString(PeekBGColorButton.ButtonColor));
      Curl.DisplayList.AddObject('SetBGColor '+ColorToString(PeekBGColorButton.ButtonColor),AccObject);
      AccObject:=TAccObject.Create;
      If TransparentBGCheckBox.Checked Then Begin
        AccObject.AcceleratedCommand:=AccelerateCommand('SetTextStyle Transparent');
        Curl.DisplayList.AddObject('SetTextStyle Transparent',AccObject);
      End Else Begin
        AccObject.AcceleratedCommand:=AccelerateCommand('SetTextStyle Opaque');
        Curl.DisplayList.AddObject('SetTextStyle Opaque',AccObject);
      End;
      AccObject:=TAccObject.Create;
      AccObject.AcceleratedCommand:=AccelerateCommand('TextOut '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w)+','+TLabelEdit.Caption);
      Curl.DisplayList.AddObject('TextOut '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w)+','+TLabelEdit.Caption,AccObject);
      Curl.Shell:=Scene.RenderShell(Curl.DisplayList,Scene.Drawer.TransM);
      Scene.View.Add('DrawCurl '+PrimitiveName);
      Dispatcher.ExecCommand('self::CAD_Scene2GUI');
      Key:=#0;
  end;
  If Key=#27 Then Begin
    //hide label edit handle
      TLabelEdit.Hide;
      Drawing:=False;
      Key:=#0;
  end;
end;

procedure TForm1.TNameEditEditingDone(Sender: TObject);
begin
   Renaming:=False;
end;

procedure TForm1.TNameEditKeyDown(Sender: TObject; var Key: Word;  Shift: TShiftState);
begin
  If Key=27 then Begin
    Key:=0;
    Renaming:=False;
  end;
end;

procedure TForm1.ToObjectButtonClick(Sender: TObject);
Var CurlName,OName,TI:String;
    Curl:TVCurl;I,J,N:Longint;
    Obj:TVObject;BaseX,BaseY,Xw,Yw:Extended;
    S:Boolean;
    Sm,Rm,Scm,tmpm,TransM:TMatrix2D;
begin
  If CurlList.Count=0 Then Exit;
  S:=False;
  For I:=CurlList.Count-1 DownTo 0 Do Begin
      If CurlList.Selected[I] Then Begin
        S:=True;
        Break;
      End;
  End;
  If Not(S) Then Exit; // nothing selected to convert     NavigateButton.Down:=True;
  CurlActionPanel.Caption:='Click on base point';
  CurlActionPanel.Color:=clYellow;
  DelCurlsButton.Hide;
  SimplifyCurlButton.Hide;
  ToObjectButton.Hide;
  ToTemplateButton.Hide;
  GettingPoint:=True;
  Repeat Application.ProcessMessages Until Not GettingPoint;
  CurlActionPanel.Caption:='';
  CurlActionPanel.Color:=clBtnFace;
  DelCurlsButton.Show;
  SimplifyCurlButton.Show;
  ToObjectButton.Show;
  ToTemplateButton.Show;
{  If SnapToGridButton.Down Then Begin
    Drawer.StoW(SelectX1s,SelectY1s,SelectX1w,SelectY1w);
    SelectX1w:=GridGapEdit.Value*Round(SelectX1w/GridGapEdit.Value);
    SelectY1w:=GridGapEdit.Value*Round(SelectY1w/GridGapEdit.Value);
  end Else Drawer.StoW(SelectX1s,SelectY1s,SelectX1w,SelectY1w);}
  BaseX:=SelectX1w;
  BaseY:=SelectY1w;
  TPGEditMemo.Clear;
  Obj:=TVObject.Create;
  Obj.Saveable:=True;
  If Scene.VObjectList.Count=0 Then OName:='object0'
  Else OName:=((Scene.VObjectList.Objects[Scene.VObjectList.Count-1]) As TVObject).Name;
//    TI:=IntToStr(Scene.VCurlList.Count+1);
  TI:=IntToStr(StrToInt(Copy(OName,7,Length(OName)-6))+1);
  Scene.VObjectList.AddObject('object'+TI,Obj);
  Obj.Name:='object'+TI;
  Obj.X:=BaseX;  Obj.Y:=BaseY;
  Obj.A:=0; Obj.S:=1;
  Scene.View.Add('DrawObject object'+TI);
  If CurlList.Count>0 Then
    For I:=CurlList.Count-1 Downto 0 Do Begin
      If CurlList.Selected[I] Then Begin
        CurlName:=CurlList.Items[I];
        N:=Scene.VCurlList.IndexOf(CurlName);
        Curl:=Scene.VCurlList.Objects[N] As TVCurl;
        Curl2Object(Curl,Obj,BaseX,BaseY);
        {remove original curl after conversion}
        If Scene.View.IndexOf('DrawCurl '+CurlName)>-1 Then Scene.View.Delete(Scene.View.IndexOf('DrawCurl '+CurlName));
        Scene.VCurlList.Delete(N);
        CurlList.Items.Delete(I);
        NumCurlsLabel.Caption:=IntToStr(CurlList.Items.Count);
        Curl.Free;
      end;
    end;
  Sm:=GenShift(Obj.X,Obj.Y);
  Rm:=GenRotate(Obj.X,Obj.Y,Obj.A/180*pi);
  Scm:=GenScale(Obj.X,Obj.Y,Obj.S,Obj.S);
  tmpm:=MulMat2D(Sm,Rm);
  TransM:=MulMat2D(Tmpm,Scm);
  Obj.Shell:=Scene.RenderShell(Obj.DisplayList,TransM);
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
end;

procedure TForm1.ToolOptionsPanelClick(Sender: TObject);
begin

end;

procedure TForm1.ToolsPanelClick(Sender: TObject);
begin

end;

procedure TForm1.ToTemplateButtonClick(Sender: TObject);
  Var CurlName,TName,TI:String;
      Curl:TVCurl;I,J,N,CTI,MaxTI:Longint;
      Obj:TVObject;BaseX,BaseY,Xw,Yw:Extended;
      Templ:TVTemplate;
      S:Boolean;
  begin
    If CurlList.Count=0 Then Exit;
    S:=False;
    For I:=CurlList.Count-1 DownTo 0 Do Begin
        If CurlList.Selected[I] Then Begin
          S:=True;
          Break;
        End;
    End;
    If Not(S) Then Exit; // nothing selected to convert
    NavigateButton.Down:=True;
    PenButtonClick(NavigateButton);
    CurlActionPanel.Caption:='Click on base point';
    CurlActionPanel.Color:=clYellow;
    DelCurlsButton.Hide;
    SimplifyCurlButton.Hide;
    ToObjectButton.Hide;
    ToTemplateButton.Hide;
    GettingPoint:=True;
    Repeat Application.ProcessMessages Until Not GettingPoint;
    CurlActionPanel.Caption:='';
    CurlActionPanel.Color:=clBtnFace;
    DelCurlsButton.Show;
    SimplifyCurlButton.Show;
    ToObjectButton.Show;
    ToTemplateButton.Show;
{    If SnapToGridButton.Down Then Begin
      Drawer.StoW(SelectX1,SelectY1,Xw,Yw);
      Xw:=GridGapEdit.Value*Round(Xw/GridGapEdit.Value);
      Yw:=GridGapEdit.Value*Round(Yw/GridGapEdit.Value);
    end Else Drawer.StoW(SelectX1,SelectY1,Xw,Yw);}
    BaseX:=SelectX1w;
    BaseY:=SelectY1w;
    TPGEditMemo.Clear;
    Templ:=TVTemplate.Create;
    MaxTI:=0;
    If Scene.VTemplateList.Count=0 Then TName:='template0'
    Else Begin
      For I:=0 To Scene.VTemplateList.Count-1 Do Begin
        If Pos('template',Scene.VTemplateList[I])=1 Then Begin
          TName:=Scene.VTemplateList[I];
          CTI:=StrToInt(Copy(TName,9,Length(TName)-8));
          If CTI>MaxTI Then MaxTI:=CTI;
        End;
      End;
      TName:=((Scene.VTemplateList.Objects[Scene.VTemplateList.Count-1]) As TVTemplate).Name;
    end;
    TI:=IntToStr(MaxTI+1);
    Scene.VTemplateList.AddObject('template'+TI,Templ);
    Templ.Name:='template'+TI;
    Templ.OType:=0;
 //   Scene.View.Add('DrawObject object'+TI);
    If CurlList.Count>0 Then
      For I:=CurlList.Count-1 DownTo 0 Do Begin
        If CurlList.Selected[I] Then Begin
          CurlName:=CurlList.Items[I];
          N:=Scene.VCurlList.IndexOf(CurlName);
          Curl:=Scene.VCurlList.Objects[N] As TVCurl;
          Curl2Template(Curl,Templ,BaseX,BaseY);
          {remove original curl after conversion}
          If Scene.View.IndexOf('DrawCurl '+CurlName)>-1 Then Scene.View.Delete(Scene.View.IndexOf('DrawCurl '+CurlName));
          Scene.VCurlList.Delete(N);
          CurlList.Items.Delete(I);
          NumCurlsLabel.Caption:=IntToStr(CurlList.Items.Count);
          Curl.Free;
        end;
      end;
    Dispatcher.ExecCommand('self::CAD_Scene2GUI');
    Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');

end;

procedure TForm1.DetachTPGSpeedButtonClick(Sender: TObject);
begin
  If DetachTPGSpeedButton.Down Then Begin
    ShowTPGEditButton.Down:=True;
    TPGEditForm.Show;
    TPGEditGroupBox.Hide;
    TPGEditPanel.Parent:=TPGEditForm;
  end Else Begin
    If ShowTPGEditButton.Down Then Begin
      TPGEditForm.Hide;
      TPGEditGroupBox.Show;
      TPGEditPanel.Parent:=TPGEditGroupBox;
    end Else Begin
      TPGEditForm.Hide;
      TPGEditGroupBox.Hide;
      TPGEditPanel.Parent:=TPGEditGroupBox;
    end;
  end;
end;

Procedure TForm1.TransparentBGCheckBoxChange(Sender: TObject);
Begin
  If LockBackUpdate Then Exit;
  If GetTypeByName(Scene,CurrentEditingNameEdit.Text)='callout' Then Begin
    CalloutGUI2Scene;
    RepaintView;
  End;
end;

procedure TForm1.WheelTimerTimer(Sender: TObject);
Var Xw,Yw,S1,S2,Xc1,Xc2,Yc1,Yc2:Extended;
      TName:String; Templ:TVTemplate;
      N:Longint;
begin
  WheelTimer.Enabled:=False;

  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  BasisChanging:=False;
  DrawRubber;
  If EditMode='object' Then Begin
   { If Pos('.tpg',LibraryShellTreeView.Path)>0 Then Begin
      TName:=Copy(ExtractFileName(LibraryShellTreeView.Path),1,Length(ExtractFileName(LibraryShellTreeView.Path))-4);
      N:=Scene.VTemplateList.IndexOf(TName);
      Templ:=Scene.VTemplateList.Objects[N] As TVTemplate;
      WCanvas.Pen.Mode:=pmnotXOR;
      WCanvas.Pen.Style:=psDot;
      Scene.Drawer.EnforcedPenStyle:=psDot;
      Scene.ExecCommand('DrawTemplate '+TName+' '+FloatToStr(LastXw)+','+FloatToStr(LastYw)+','+AEdit.Text+','+SEdit.Text,ZeroAcc,0);
//      JustDrawing:=True;
    end;}
  //  DrawRubber;
  end;
  If EditMode='curl line' Then Begin
      Drawer.WtoS(SelectX1w,SelectY1w,SelectX1s,SelectY1s);
      Drawer.WtoS(LastXw,LastYw,LastXs,LastYs);
      WCanvas.MoveTo(SelectX1s,SelectY1s); //рисуем новую резину
      WCanvas.Pen.Mode:=pmnotXOR;
      WCanvas.Pen.Style:=psDot;
      WCanvas.Pen.Color:=BorderColorButton.ButtonColor;
      WCanvas.Pen.Width:=WidthButton1.Tag;
      WCanvas.LineTo(LastXs,LastYs);
  end;
end;

procedure TForm1.ViewXEditChange(Sender: TObject);
begin
  If LockCoordUpdate Then Exit;
  If BasisChanging Then Exit;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
end;

procedure TForm1.XEditChange(Sender: TObject);
Var Obj:TVObject;
    I,N:Longint;Buf,ParsedBuf,TemplateName:String;
    Sm,Rm,Scm,tmpm,TransM:TMatrix2D;
begin
    If LockBackUpdate Then Exit;
    N:=Scene.VObjectList.IndexOf(CurrentEditingNameEdit.Text);
    If N>=0 Then Begin
//    If ObjectList.SelCount=1 Then Begin
//      Obj:=Scene.VObjectList.Objects[ObjectList.ItemIndex] As TVObject;
      Obj:=Scene.VObjectList.Objects[N] As TVObject;
{      If Obj.DisplayList.Count>0 Then
        For I:=0 To Obj.DisplayList.Count-1 Do Begin
          Buf:=Obj.DisplayList[I];
          If Pos('DrawTemplate',Buf)=1 Then
          GetNextToken(Buf,ParsedBuf,' ');
          Buf:=ParsedBuf;
          TemplateName:=GetNextToken(Buf,ParsedBuf,' ');
          Obj.X:=XEdit.Value; Obj.Y:=YEdit.Value;
          Obj.S:=SEdit.Value;
          If Obj.A<=360 Then Obj.A:=AEdit.Value;
        //  Obj.DisplayList[I]:='DrawTemplate '+TemplateName+' 0,0,0,1';
          Break;
        end;
      Obj.X:=XEdit.Value; Obj.Y:=YEdit.Value;
      Obj.S:=SEdit.Value;
      If Obj.A<=360 Then Obj.A:=AEdit.Value;
      Sm:=GenShift(Obj.X,Obj.Y);
      Rm:=GenRotate(Obj.X,Obj.Y,Obj.A/180*pi);
      Scm:=GenScale(Obj.X,Obj.Y,Obj.S,Obj.S);
      tmpm:=MulMat2D(Sm,Rm);
      TransM:=MulMat2D(Tmpm,Scm);}
      ObjectGUI2Scene;
      Scene.ObjectAttr2Style(Obj);
      Scene.DeleteSelHandles(Obj.Name);
      Scene.CreateSelHandles(Obj.Name);
      RepaintView;
    end;
end;

procedure TForm1.ZoomToSceneMenuItemClick(Sender: TObject);
begin
  ZoomToScene;
end;

procedure TForm1.ZoomToSelectionMenuItemClick(Sender: TObject);
begin
  ZoomToSelection;
end;

procedure TForm1.ZoomToSelMenuItemClick(Sender: TObject);
begin
  ZoomToSelection;
end;

procedure TForm1.AxisModeCheckBoxChange(Sender: TObject);
begin
  If AxisModeCheckBox.Checked Then
  Drawer.AxisMode:=1 Else Drawer.AxisMode:=0;
end;

procedure TForm1.BaseObjectEditEditingDone(Sender: TObject);
begin
   If LockBackUpdate Then Exit;
   If GetTypeByName(Scene,CurrentEditingNameEdit.Text)='callout' Then Begin
     BindModeRadioGroupSelectionChanged(Sender);
     CalloutGUI2Scene;
     RepaintView;
   end;
end;

procedure TForm1.BindModeRadioGroupSelectionChanged(Sender: TObject);
begin
  If LockBackUpdate Then Exit;
  Case BindModeRadioGroup.ItemIndex Of
      0:  Begin LX1Edit.Value:=0;LY1Edit.Value:=0;End;//Shell;
      1:  Begin LX1Edit.Value:=0;LY1Edit.Value:=0;End;//Base;
      2:  Begin LX1Edit.Value:=0;LY1Edit.Value:=0;End;//LT;
      3:  Begin LX1Edit.Value:=0;LY1Edit.Value:=0;End;//RT;
      4:  Begin LX1Edit.Value:=0;LY1Edit.Value:=0;End;//LB;
      5:  Begin LX1Edit.Value:=0;LY1Edit.Value:=0;End;//RB;
      6:  //None;
  End;
  Scene.DeleteSelHandles(CurrentEditingNameEdit.Text);
  CalloutGUI2Scene;
  Scene.CreateSelHandles(CurrentEditingNameEdit.Text);
  RepaintView;
end;

procedure TForm1.BoldButtonClick(Sender: TObject);
begin
    If LockBackUpdate Then Exit;
    FontDialog.Font.Style:=[];
    If BoldButton.Down Then FontDialog.Font.Style:=FontDialog.Font.Style+[fsBold];
    If ItalicButton.Down Then FontDialog.Font.Style:=FontDialog.Font.Style+[fsItalic];
    If UnderButton.Down Then FontDialog.Font.Style:=FontDialog.Font.Style+[fsUnderline];
    If StrikeButton.Down Then FontDialog.Font.Style:=FontDialog.Font.Style+[fsStrikeOut];
    TLabelEdit.Font:=FontDialog.Font;

    If GetTypeByName(Scene,CurrentEditingNameEdit.Text)='callout' Then Begin
      CalloutGUI2Scene;
      RepaintView;
    End;
end;

procedure TForm1.ConnectionListSelectionChange(Sender: TObject; User: boolean);
Var ConnectionName:String;
    Conn:TVConnection;I,J,N:Longint;
    Sm,Rm,Scm,tmpm,OldTransM:TMatrix2D;
    Buf,ParsedBuf:String;
begin
  If LockSelectionUpdate Then Exit;
   If Not ConnectorButton.Down Then Begin
     For I:=0 To ConnectionList.Items.Count-1 Do Begin
       If (Scene.SelectedList.IndexOf(ConnectionList.Items[I])<0)And(ConnectionList.Selected[I]) Then Begin
         //свежевыбранный
         AddItemToSelection(ConnectionList.Items[I]);
         Continue;
       End;
       If (Scene.SelectedList.IndexOf(ConnectionList.Items[I])>=0)And(Not ConnectionList.Selected[I]) Then Begin
         //свежеудаленный
         RemoveItemFromSelection(ConnectionList.Items[I]);
         Continue;
       End;
     End;
   End;

  TPGEditMemo.Clear;
//  If TPGEditForm.Visible Then
  TPGEditForm.Caption:='TPG edit: ';
  If ConnectionList.Count>0 Then
    For I:=0 To ConnectionList.Count-1 Do Begin
      ConnectionName:=ConnectionList.Items[I];
      N:=Scene.VConnectionList.IndexOf(ConnectionName);
      Conn:=Scene.VConnectionList.Objects[N] As TVConnection;
      If ConnectionList.Selected[I] Then Begin
//        If TPGEditForm.Visible Then Begin
          TPGEditForm.Caption:=TPGEditForm.Caption+ConnectionName+' ';
          TPGEditMemo.Lines.AddStrings(Conn.DisplayList);
//        End;
        If DrawingPanel.Color=clBlack Then Scene.Drawer.Canvas.Pen.Mode:=pmWhite//pmNotCopy;
        Else Scene.Drawer.Canvas.Pen.Mode:=pmNotCopy;//pmNotCopy;
        Scene.ExecCommand('DrawConnection '+ConnectionName,ZeroAcc,0);
      end Else Begin
        Scene.Drawer.Canvas.Pen.Mode:=pmCopy;
        Scene.ExecCommand('DrawConnection '+ConnectionName,ZeroAcc,0);
      end;
    end;
  Scene.Drawer.Canvas.Pen.Mode:=pmCopy;
  UpdateMultiSelection;
end;

procedure TForm1.CoordStyleComboBoxChange(Sender: TObject);
begin
  BasisChanging:=True;
  Case CoordStyleComboBox.Text Of
  'Meters': Begin
              ViewScaleEdit.Value:=0.1;
              GridGapEdit.Value:=10;
            End;
  'Kilometers': Begin
              ViewScaleEdit.Value:=1000;
              GridGapEdit.Value:=10000;
            End;
  'Rack Units':Begin
              ViewScaleEdit.Value:=0.005;//5 mm per pixel
              GridGapEdit.Value:=0.044450;
            End;
  end;
  LX1Edit.Increment:=GridGapEdit.Value;
  LY1Edit.Increment:=GridGapEdit.Value;
  LX2Edit.Increment:=GridGapEdit.Value;
  LY2Edit.Increment:=GridGapEdit.Value;
  LdXEdit.Increment:=GridGapEdit.Value;
  LdYEdit.Increment:=GridGapEdit.Value;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  BasisChanging:=False;
  Dispatcher.ExecCommand('self::CAD_UpdateDraw');
end;

procedure TForm1.CreateBookMarkSpeedButtonClick(Sender: TObject);
Var A,N:String;
begin
   A:='file://'+DocumentName+'?X='+ViewXEdit.Text+'&Y='+ViewYEdit.Text+'&A='+ViewAngleEdit.Text+'&S='+ViewScaleEdit.Text;
   If BookmarkNameEdit.Text<>'' Then N:=BookmarkNameEdit.Text
   Else N:=A;
   BookMarks.Add(N+'='+A);
   BookMarkListBox.Items.Add(N);
//   BookMarkList.Text:=N;
   BookMarknameEdit.Text:='';
end;



Procedure TForm1.DelConnButtonClick(Sender: TObject);
Var ConnName,ObjName:String;
    Conn:TVConnection;
    Port:TVPort;
    ObjS,ObjE:TVObject;Index,I,J,N:Longint;
begin
  TPGEditMemo.Clear;
  If ConnectionList.Count>0 Then
    For I:=ConnectionList.Count-1 Downto 0 Do Begin
      If ConnectionList.Selected[I] Then Begin
        ConnName:=ConnectionList.Items[I];
        Index:=Scene.VConnectionList.IndexOf(ConnName);
        Conn:=Scene.VConnectionList.Objects[Index] As TVConnection;
        Scene.DeleteConnection(Conn);
//        ConnectionList.Items.Delete(I);
//        NumConnectionsLabel.Caption:=IntToStr(ConnectionList.Items.Count);
      end;
    end;
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
end;

Procedure TForm1.DelGroupButtonClick(Sender: TObject);
Var Group:TVGroup;
    Obj:TVObject;
    I,N,GN:Longint;
Begin
{    showmessage('gridrc='+inttoStr(GroupStringGrid.RowCount)
    +' row='+IntToStr(GroupStringGrid.Row)
    +' grc='+IntToStr(Scene.VGroupList.Count)
    );}
  If (GroupStringGrid.RowCount<=1)Or(Scene.VGroupList.Count=0)Or(GroupStringGrid.Row<=0) Then Exit;
  Group:=Scene.VGroupList.Objects[GroupStringGrid.Row-1] As TVGroup;
  If Group.DisplayList.Count>0 Then
    For I:=Group.DisplayList.Count-1 Downto 0 Do Begin
      N:=Scene.VObjectList.IndexOf(Group.DisplayList[I]);
      If N>=0 Then Begin
        Obj:=Scene.VObjectList.Objects[N] As TVObject;
        GN:=Obj.GroupList.IndexOf(Group.Name);
        If GN>=0 Then Obj.GroupList.Delete(GN);
      end;
    End;
  Group.Free;
  Scene.VGroupList.Delete(GroupStringGrid.Row-1);
  GroupStringGrid.DeleteRow(GroupStringGrid.Row);
  GroupItemsList.Clear;
  NumGroupsLabel.Caption:=IntToStr(Scene.VGroupList.Count);
  Form1.GroupStringGridSelection(GroupStringGrid,GroupStringGrid.Col,GroupStringGrid.Row);
end;

procedure TForm1.DelPortSpeedButtonClick(Sender: TObject);
Var I,J,N:Longint;
    ObjName,PortName:String;
    Obj:TVObject;Port:TVPort;
    AccObject:TAccObject;
begin
//  If ObjectList.SelCount<>1 Then Exit;
//  ObjName:=ObjectList.Items[ObjectList.ItemIndex];
//  N:=Scene.VObjectList.IndexOf(ObjName);
  N:=Scene.VObjectList.IndexOf(CurrentEditingNameEdit.Text);
  If N<0 Then Exit;
  Obj:=Scene.VObjectList.Objects[N] As TVObject;
  If PortStringGrid.Row<=0 Then Exit;
  PortName:=PortStringGrid.Cells[0,PortStringGrid.Row];
  Port:=Obj.PortList.Objects[Obj.PortList.IndexOf(PortName)] As TVPort;
  Port.Free;Obj.PortList.Delete(Obj.PortList.IndexOf(PortName));
  If PortStringGrid.Row<PortStringGrid.RowCount-1 Then
    For I:=PortStringGrid.Row To PortStringGrid.RowCount-2 Do Begin
      For J:=0 To 5 Do
        PortStringGrid.Cells[J,I]:=PortStringGrid.Cells[J,I+1];
    end;
  PortStringGrid.RowCount:=PortStringGrid.RowCount-1;
  //перестроение DisplayLista
  If Obj.DisplayList.Count>0 Then
    For I:=Obj.DisplayList.Count-1 DownTo 0 Do
      If Pos('UnScaled ',Obj.DisplayList[I])=1 Then Begin
        AccObject:=Obj.DisplayList.Objects[I] As TAccObject;
        AccObject.Free;
        Obj.DisplayList.Delete(I);
      End;
  If Obj.PortList.Count>0 Then
    For J:=0 To Obj.PortList.Count-1 Do Begin
      Port:=Obj.PortList.Objects[J] As TVPort;
      If Port.AR='A' Then Begin
        Port.X:=(Port.AX-Obj.Shell.X1)/(Obj.Shell.X2-Obj.Shell.X1);
        Port.Y:=(Port.AY-Obj.Shell.Y1)/(Obj.Shell.Y2-Obj.Shell.Y1);
      End Else Begin
        Port.AX:=Obj.Shell.X1+Port.X*(Obj.Shell.X2-Obj.Shell.X1);
        Port.AY:=Obj.Shell.Y1+Port.Y*(Obj.Shell.Y2-Obj.Shell.Y1);
      End;
      //Добавление портов в DisplayList
      AccObject:=TAccObject.Create;
      AccObject.AcceleratedCommand:=AccelerateCommand('UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone));
      Obj.DisplayList.AddObject('UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone),AccObject);
    end;
end;

procedure TForm1.Div2ButtonClick(Sender: TObject);
begin
  GridGapEdit.Value:=GridGapEdit.Value/2;
end;

procedure TForm1.Edit2Change(Sender: TObject);
begin

end;

procedure TForm1.EditConnButtonClick(Sender: TObject);
Var Conn:TVConnection;Port:TVConnectionPort;
    ConnName:String;
    I,N:Longint;
begin
  If ConnectionList.SelCount<>1 Then Exit;
  ConnName:=ConnectionList.Items[ConnectionList.ItemIndex];
  N:=Scene.VConnectionList.IndexOf(ConnName);
  Conn:=Scene.VConnectionList.Objects[N] As TVConnection;
  Scene.ConnectionAttr2Style(Conn);
  PrepareConnectionPropEdit(Conn);
end;

procedure TForm1.EditObjButtonClick(Sender: TObject);
Var Obj:TVObject;Port:TVPort;
    ObjName:String;
    I,N:Longint;
begin
  If ObjectList.SelCount<>1 Then Exit;
  ObjName:=ObjectList.Items[ObjectList.ItemIndex];
  N:=Scene.VObjectList.IndexOf(ObjName);
  Obj:=Scene.VObjectList.Objects[N] As TVObject;
  Scene.ObjectAttr2Style(Obj);
  PrepareObjectPropEdit(Obj);
end;

procedure TForm1.GotoConnButtonClick(Sender: TObject);
Var ConnName:String;
    Conn:TVConnection;
    I,J,N:Longint;
    X1,Y1,X2,Y2:Extended;
begin
  X1:=+MaxExtended;X2:=-MaxExtended;
  Y1:=+MaxExtended;Y2:=-MaxExtended;
  If ConnectionList.Count=0 Then Exit;
  For I:=0 To ConnectionList.Count-1 Do Begin
    If ConnectionList.Selected[I] Then Begin
      ConnName:=ConnectionList.Items[I];
      N:=Scene.VConnectionList.IndexOf(ConnName);
      Conn:=Scene.VConnectionList.Objects[N] As TVConnection;
      X1:=Min(X1,Conn.Shell.X1);Y1:=Min(Y1,Conn.Shell.Y1);
      X2:=Max(X2,Conn.Shell.X2);Y2:=Max(Y2,Conn.Shell.Y2);
    End;
  End;
  N:=Scene.VConnectionList.IndexOf(ConnName);
  If N>=0 Then Begin
    Conn:=Scene.VConnectionList.Objects[N] As TVConnection;
    X1:=Min(X1,Conn.Shell.X1);Y1:=Min(Y1,Conn.Shell.Y1);
    X2:=Max(X2,Conn.Shell.X2);Y2:=Max(Y2,Conn.Shell.Y2);
  End;
  BasisChanging:=True;
  ViewXEdit.Value:=(X1+X2)/2;
  ViewYEdit.Value:=(Y1+Y2)/2;
  If (X2-X1)/Scene.Drawer.Wx > (Y2-Y1)/Scene.Drawer.Wy
  Then ViewScaleEdit.Value:=(X2-X1)*1.01001/Scene.Drawer.Wx
  Else ViewScaleEdit.Value:=(Y2-Y1)*1.01001/Scene.Drawer.Wy;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  BasisChanging:=False;
end;

procedure TForm1.GotoObjButtonClick(Sender: TObject);
Var ObjName:String;
    Obj:TVObject;I,J,N:Longint;
    X1,X2,Y1,Y2:Extended;
begin
  X1:=+MaxExtended;X2:=-MaxExtended;
  Y1:=+MaxExtended;Y2:=-MaxExtended;
  If ObjectList.Count=0 Then Exit;
  For I:=0 To ObjectList.Count-1 Do Begin
    If ObjectList.Selected[I] Then Begin
      ObjName:=ObjectList.Items[I];
      N:=Scene.VObjectList.IndexOf(ObjName);
      Obj:=Scene.VObjectList.Objects[N] As TVObject;
      X1:=Min(X1,Obj.Shell.X1);Y1:=Min(Y1,Obj.Shell.Y1);
      X2:=Max(X2,Obj.Shell.X2);Y2:=Max(Y2,Obj.Shell.Y2);
    End;
  End;
  BasisChanging:=True;
  ViewXEdit.Value:=(X1+X2)/2;
  ViewYEdit.Value:=(Y1+Y2)/2;
  If (X2-X1)/Scene.Drawer.Wx > (Y2-Y1)/Scene.Drawer.Wy
  Then ViewScaleEdit.Value:=(X2-X1)*1.01001/Scene.Drawer.Wx
  Else ViewScaleEdit.Value:=(Y2-Y1)*1.01001/Scene.Drawer.Wy;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  BasisChanging:=False;
end;

procedure TForm1.GroupStringGridCheckboxToggled(sender: TObject; aCol,
  aRow: Integer; aState: TCheckboxState);
begin
  GroupStringGridEditingDone(Sender);
end;

procedure TForm1.GroupStringGridEditingDone(Sender: TObject);
Var Group:TVGroup;
    OldName,GName:String; I,N:Longint;
    Obj:TVObject;Conn:TVConnection;
begin
  If GroupStringGrid.Row<=0 Then Exit;
  GName:=GroupStringGrid.Cells[0,GroupStringGrid.Row];
//  N:=Scene.VGroupList.IndexOf(GName);
//  If N<0 Then Exit;
  Group:=Scene.VGroupList.Objects[GroupStringGrid.Row-1] As TVGroup;
  OldName:=Group.Name;
  Group.Name:=GName;
  If Group.DisplayList.Count>0 Then Begin
    For I:=0 To Group.DisplayList.Count-1 Do Begin
      N:=Scene.VObjectList.IndexOf(Group.DisplayList[I]);
      If N<0 Then Continue;
      Obj:=Scene.VObjectList.Objects[N] As TVObject;
      N:=Obj.GroupList.IndexOf(OldName);
      If N<0 Then Continue;
      Obj.GroupList[N]:=GName;
    end;
    For I:=0 To Group.DisplayList.Count-1 Do Begin
      N:=Scene.VConnectionList.IndexOf(Group.DisplayList[I]);
      If N<0 Then Continue;
      Conn:=Scene.VConnectionList.Objects[N] As TVConnection;
      N:=Conn.GroupList.IndexOf(OldName);
      If N<0 Then Continue;
      Obj.GroupList[N]:=GName;
    end;
  end;
  Group.Glue:=GroupStringGrid.Cells[1,GroupStringGrid.Row]='1';
  Group.Active:=GroupStringGrid.Cells[2,GroupStringGrid.Row]='1';
  Group.Visible:=GroupStringGrid.Cells[3,GroupStringGrid.Row]='1';
  RepaintView;
end;

procedure TForm1.GroupStringGridSelection(Sender: TObject; aCol, aRow: Integer);
Var Group:TVGroup;
    N:Longint;
begin
  If ARow<1 Then Exit;
  N:=Scene.VGroupList.IndexOf(GroupStringGrid.Cells[0,aRow]);
  If N<0 Then Exit; //Error
  Group:=Scene.VGroupList.Objects[N] As TVGroup;
  GroupItemsList.Items.Assign(Group.DisplayList);
end;


procedure TForm1.Image1MouseLeave(Sender: TObject);
Var TName:String; Templ:TVTemplate;
    N:Longint;
begin
  If EditMode='object' Then Begin
    // erase rubber objects
    DrawRubber;
  End;


{
  //  If LibraryTemplateListBox.ItemIndex<0 Then Exit
    If Pos('.tpg',LibraryShellTreeView.Path)=0 Then Exit
    Else Begin
//      TName:=LibraryTemplateListBox.Items[LibraryTemplateListBox.ItemIndex];
      TName:=Copy(ExtractFileName(LibraryShellTreeView.Path),1,Length(ExtractFileName(LibraryShellTreeView.Path))-4);
      N:=Scene.VTemplateList.IndexOf(TName);
      Templ:=Scene.VTemplateList.Objects[N] As TVTemplate;
    End;
    WCanvas.Pen.Mode:=pmnotXOR;
    WCanvas.Pen.Style:=psDot;
    Scene.Drawer.EnforcedPenStyle:=psDot;
//    Scene.Drawer.EnforcedPenColor:=clRed;
    Scene.ExecCommand('DrawTemplate '+TName+' '+FloatToStr(LastXw)+','+FloatToStr(LastYw)+','+AEdit.Text+','+SEdit.Text,ZeroAcc,0);
    JustDrawing:=True;
  end;}

end;

procedure TForm1.NewGroupSpeedButtonClick(Sender: TObject);
Var Group:TVGroup;
    PrimitiveName:String;
begin
  Group:=TVGroup.Create;
  PrimitiveName:=GetNewName(Scene,Scene.VGroupList,'');
  Scene.VGroupList.AddObject(PrimitiveName,Group);
  Group.Name:=PrimitiveName;
  Group.Visible:=True;
  Group.Active:=True;
  Group.Glue:=True;
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  NumGroupsLabel.Caption:=IntToStr(Scene.VGroupList.Count);
end;

procedure TForm1.ObjectFilterEditChange(Sender: TObject);
Var I,N:Longint;
begin
  ObjectList.Items.Clear;
  If ObjectFilterEdit.Text='' Then ObjectList.Items.Assign(Scene.VObjectList)
  Else
  If Scene.VObjectList.Count>0 Then
    For I:=0 To Scene.VObjectList.Count-1 Do
      If Pos(ObjectFilterEdit.Text,Scene.VObjectList[I])<>0 Then
        ObjectList.Items.Add(Scene.VObjectList[I]);
  //restore selection highlight after rebuild of the list
  LockSelectionUpdate:=True;
  If Scene.SelectedList.Count>0 Then
    For I:=0 To Scene.SelectedList.Count-1 Do Begin
      If Scene.SelectedList.Objects[I] Is TVObject Then Begin
        N:=ObjectList.Items.IndexOf(Scene.SelectedList[I]);
        If N>=0 Then ObjectList.Selected[N]:=True;
      end;
    end;
  LockSelectionUpdate:=False;
end;

procedure TForm1.ObjectListDblClick(Sender: TObject);
begin
  If ObjectList.ItemIndex<0 Then Exit;
  NavigationDst:=ObjectList.Items[ObjectList.ItemIndex];
  NavigatePopupMenu.Popup;
end;

Procedure TForm1.ObjectListMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
Begin
  If Not NavigateButton.Down Then
    If ObjectList.SelCount=1 Then Begin
      CurrentEditingNameEdit.Text:=ObjectList.Items[ObjectList.ItemIndex];
      EditButton.Down:=True;
      EditObjButtonClick(Sender);
    end Else Begin
      EditButton.Down:=True;
    End;
end;

procedure TForm1.ObjStyleRadioGroupSelectionChanged(Sender: TObject);
Var K:Longint;Astr:String;Aval:Extended;
    Obj:TVObject;
begin
  // в режиме создания нового и изменения старого
  RubberDisplayList.Clear;
  ObjStyleRadioGroup.Top:=0;
  ObjStyleRadioGroup.Align:=alTop;
  ObjStyleRadioGroup.Show;
  Case ObjStyleRadioGroup.ItemIndex Of
  0: Begin
           PortPageControl.Align:=alNone;
           InsPointGroupBox.Align:=alTop;
           InsPointGroupBox.Top:=ObjStyleRadioGroup.Top+ObjStyleRadioGroup.Height+1;
           InsPointGroupBox.Show;
           TemplateGroupBox.Show;
           CornerGroupBox.Hide;
           SourceGroupBox.Hide;
           BackGroundGroupBox.Hide;
           LineGroupBox.Hide;
           TemplateGroupBox.Top:=InsPointGroupBox.Top+InsPointGroupBox.Height+1;
           TemplateGroupBox.Align:=alTop;
           PortPageControl.Top:=TemplateGroupBox.Top+TemplateGroupBox.Height+5;
           PortPageControl.Align:=alClient;
     End;
  1: Begin End;
  2,3,4: Begin
           InsPointGroupBox.Hide;
           TemplateGroupBox.Hide;
           SourceGroupBox.Hide;
           LineGroupBox.Align:=alNone;
           LineGroupBox.Show;
           BackGroundGroupBox.Align:=alNone;
           BackGroundGroupBox.Show;
           CornerGroupBox.Align:=alNone;
           CornerGroupBox.Show;

           LineGroupBox.Top:=ObjStyleRadioGroup.Top+ObjStyleRadioGroup.Height+1;
           LineGroupBox.Align:=alTop;

           BackGroundGroupBox.Top:=LineGroupBox.Top+LineGroupBox.Height+1;
           BackGroundGroupBox.Align:=alTop;

           CornerGroupBox.Top:=BackGroundGroupBox.Top+BackGroundGroupBox.Height+1;
           CornerGroupBox.Align:=alTop;

           ObjStyleRadioGroup.Top:=0;
           ObjStyleRadioGroup.Align:=alTop;

           PortPageControl.Align:=alClient;
     End;
  5,6: Begin InsPointGroupBox.Hide;
           TemplateGroupBox.Hide;
           LineGroupBox.Align:=alNone;
           LineGroupBox.Hide;
           SourceGroupBox.Show;
           SourceGroupBox.Align:=alNone;
           BackGroundGroupBox.Align:=alNone;
           BackGroundGroupBox.Hide;
           CornerGroupBox.Align:=alNone;
           CornerGroupBox.Show;

           SourceGroupBox.Top:=ObjStyleRadioGroup.Top+ObjStyleRadioGroup.Height+1;
           SourceGroupBox.Align:=alTop;

           LineGroupBox.Top:=ObjStyleRadioGroup.Top+ObjStyleRadioGroup.Height+1;
           LineGroupBox.Align:=alTop;

           BackGroundGroupBox.Top:=LineGroupBox.Top+LineGroupBox.Height+1;
           BackGroundGroupBox.Align:=alTop;

           CornerGroupBox.Top:=BackGroundGroupBox.Top+BackGroundGroupBox.Height+1;
           CornerGroupBox.Align:=alTop;

           ObjStyleRadioGroup.Top:=0;
           ObjStyleRadioGroup.Align:=alTop;

           PortPageControl.Align:=alClient;
           SourceEdit.Text:='';
         End;
  end;
  If EditMode='edit' Then Begin
    If GetTypeByName(Scene,CurrentEditingNameEdit.Text)='object' Then Begin
      K:=Scene.VObjectList.IndexOf(CurrentEditingNameEdit.Text);
      If K>=0 Then Begin
        Obj:=Scene.VObjectList.Objects[K] As TVObject;
        If (Obj.A=720) Or (Obj.A=720+360) Or (Obj.A=720+2*360) Or (Obj.A=720+3*360) Or (Obj.A=720+4*360) Then Begin
          //switching special object type
          Case ObjStyleRadioGroup.ItemIndex Of
          2: Obj.A:=720;
          3: Obj.A:=720+360;
          4: Obj.A:=720+2*360;
          5: Obj.A:=720+3*360;
          6: Obj.A:=720+4*360;
          End;
          Scene.ObjectAttr2Style(Obj);
          Scene.UpdateObjectDisplayList(Obj);
          Scene.UpdateObjectPorts(Obj);
        End;
      End;
    End;
  End;
end;

procedure TForm1.OriginToZeroMenuItemClick(Sender: TObject);
begin
  CoordStyleComboBoxChange(Sender);
  ViewXEdit.Value:=0;
  ViewYEdit.Value:=0;
  ViewScaleEdit.Value:=1;
  ViewAngleEdit.Value:=0;
  ExecCommand('self::CAD_UpdateCoordBase');
end;

procedure TForm1.PageControl2Change(Sender: TObject);
begin

end;

Procedure TForm1.PickFileSpeedButtonClick(Sender: TObject);
Begin
  If OpenPictureDialog.Execute Then Begin
    SourceEdit.Text:='file://'+OpenPictureDialog.FileName;
  End;
  SourceEdit.OnEditingDone(Sender);
end;

procedure TForm1.PortArrangeButtonClick(Sender: TObject);
begin
  If Sender is TSpeedButton Then
    Case (Sender As TSpeedButton).Name of
    'PortArrangeITOLButton':  Dispatcher.ExecCommand('self::CAD_ArrangePortsByLines:'+CurrentEditingNameEdit.Text+':-:1:0:-');
    'PortArrangeITOBButton':  Dispatcher.ExecCommand('self::CAD_ArrangePortsByLines:'+CurrentEditingNameEdit.Text+':-:1:-:0');
    'PortArrangeITORButton':  Dispatcher.ExecCommand('self::CAD_ArrangePortsByLines:'+CurrentEditingNameEdit.Text+':-:1:1:-');
    'PortArrangeIROLButton':  Dispatcher.ExecCommand('self::CAD_ArrangePortsByLines:'+CurrentEditingNameEdit.Text+':1:-:0:-');
    'PortArrangeButton':    Dispatcher.ExecCommand('self::CAD_ArrangePortsByRect:'+CurrentEditingNameEdit.Text+':0:0');
    'PortArrangeILORButton':  Dispatcher.ExecCommand('self::CAD_ArrangePortsByLines:'+CurrentEditingNameEdit.Text+':0:-:1:-');
    'PortArrangeIBOLButton':  Dispatcher.ExecCommand('self::CAD_ArrangePortsByLines:'+CurrentEditingNameEdit.Text+':-:0:0:-');
    'PortArrangeIBOTButton':  Dispatcher.ExecCommand('self::CAD_ArrangePortsByLines:'+CurrentEditingNameEdit.Text+':-:0:-:1');
    'PortArrangeIBORButton':  Dispatcher.ExecCommand('self::CAD_ArrangePortsByLines:'+CurrentEditingNameEdit.Text+':-:0:1:-');
    End;

  Dispatcher.ExecCommand('self::CAD_UpdateDraw');
end;

procedure TForm1.PortFileOpenButtonClick(Sender: TObject);
Var Obj:TVObject;Port:TVPort;AccObject:TAccObject;
    PortFile:TStringList;
    I,N:Longint;
    CurrentLine,ObjName:String;
begin
//  If ObjectList.SelCount<>1 Then Exit;
//  ObjName:=ObjectList.Items[ObjectList.ItemIndex];
//  N:=Scene.VObjectList.IndexOf(ObjName);
  N:=Scene.VObjectList.IndexOf(CurrentEditingNameEdit.Text);
  If N<0 Then Exit;
  Obj:=Scene.VObjectList.Objects[N] As TVObject;
  If Not PortOpenDialog.Execute Then Exit;
  PortFile:=TStringList.Create;
  Try PortFile.LoadFromFile(PortOpenDialog.FileName);
  Except PortFile.Free;Exit; End;
  For I:=0 To PortFile.Count-1 Do Begin
    CurrentLine:=PortFile[I];
    Port:=TVPort.Create;
    Port.Name:=GetValByName(CurrentLine,'PortName');
    Port.AR:=GetValByName(CurrentLine,'A/R');
    PortStringGrid.RowCount:=PortStringGrid.RowCount+1;
    PortStringGrid.Cells[0,PortStringGrid.RowCount-1]:=Port.Name;
    PortStringGrid.Cells[1,PortStringGrid.RowCount-1]:=Port.AR;
    PortStringGrid.Cells[2,PortStringGrid.RowCount-1]:=GetValByName(CurrentLine,'X');
    PortStringGrid.Cells[3,PortStringGrid.RowCount-1]:=GetValByName(CurrentLine,'Y');
    PortStringGrid.Cells[4,PortStringGrid.RowCount-1]:='';
    PortStringGrid.Cells[5,PortStringGrid.RowCount-1]:='';
    If Port.AR='A' Then Begin
      Port.AX:=StrToFloat(GetValByName(CurrentLine,'X'));
      Port.AY:=StrToFloat(GetValByName(CurrentLine,'Y'));
     //пересчитать относительные?
    End Else Begin
      Port.X:=StrToFloat(GetValByName(CurrentLine,'X'));
      Port.Y:=StrToFloat(GetValByName(CurrentLine,'Y'));
      Port.AX:=Obj.Shell.X1+Port.X*(Obj.Shell.X2-Obj.Shell.X1);
      Port.AY:=Obj.Shell.Y1+Port.Y*(Obj.Shell.Y2-Obj.Shell.Y1);
    End;
    Port.Connection:=GetValByName(CurrentLine,'Conn');
    Port.ConnectionPort:=GetValByName(CurrentLine,'Port');
    Obj.PortList.AddObject(Port.Name,Port);
    AccObject:=TAccObject.Create;
    AccObject.AcceleratedCommand:=AccelerateCommand('UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone));
    Obj.DisplayList.AddObject('UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone),AccObject);
  end;
  PortFile.Free;
  Scene.ExecCommand('DrawObject '+Obj.Name,ZeroAcc,0);
end;

procedure TForm1.PortPageControlChange(Sender: TObject);
begin

end;

procedure TForm1.PortPageControlMouseEnter(Sender: TObject);
begin
  PortPageControl.Height:=(TemplateGroupBox.Height+PortPageControl.Height)*3 div 4;
end;

procedure TForm1.PortSaveButtonClick(Sender: TObject);
Var I:Longint;
    PortFile:TStringList;
begin
  If Not PortSaveDialog.Execute Then Exit;
  PortFile:=TStringList.Create;
  For I:=1 To PortStringGrid.RowCount-1 Do Begin
    PortFile.Add('PortName='+PortStringGrid.Cells[0,I]+' A/R='+PortStringGrid.Cells[1,I]+
                       ' X='+PortStringGrid.Cells[2,I]+' Y='+PortStringGrid.Cells[3,I]);
  end;
  PortFile.SaveToFile(PortSaveDialog.FileName);
  PortFile.Free;
end;

Procedure TForm1.PortStringGridEditingDone(Sender: TObject);
Var I,N:Longint;
    ObjName:String;
    Obj:TVObject;
    Port:TVPort;
Begin
//  If ObjectList.SelCount<>1 Then Exit;
//  ObjName:=ObjectList.Items[ObjectList.ItemIndex];
  N:=Scene.VObjectList.IndexOf(CurrentEditingNameEdit.Text);
  If N<0 Then Exit;
  Obj:=Scene.VObjectList.Objects[N] As TVObject;//d
  Case PortStringGrid.Col of
  0: Begin
       Port:=Obj.PortList.Objects[PortStringGrid.Row-1] As TVPort; //небезопасно
       Port.Name:=PortStringGrid.Cells[0,PortStringGrid.Row];
     End;
  2,3: Begin
        Port:=Obj.PortList.Objects[PortStringGrid.Row-1] As TVPort; //небезопасно
        Port.X:=StrToFloat(PortStringGrid.Cells[2,PortStringGrid.Row]);
        Port.Y:=StrToFloat(PortStringGrid.Cells[3,PortStringGrid.Row]);
        Scene.MoveObjectTo(Obj,Obj.X,Obj.Y,'');
      End;
  4,5: Begin
        Port:=Obj.PortList.Objects[PortStringGrid.Row-1] As TVPort; //небезопасно
        Port.Connection:=(PortStringGrid.Cells[4,PortStringGrid.Row]);
        Port.ConnectionPort:=(PortStringGrid.Cells[5,PortStringGrid.Row]);
      End;
  End;
end;

procedure TForm1.PortStringGridMouseMove(Sender: TObject; Shift: TShiftState;
  X, Y: Integer);
begin
//  TemplateGroupBox.Height:=(TemplateGroupBox.Height+PortPageControl.Height-ObjStyleRadioGroup.Height-InsPointGroupBox.Height)*2 div 5;
  TemplateGroupBox.Height:=(InspectorScrollBox.Height-ObjStyleRadioGroup.Height-InsPointGroupBox.Height)*2 div 5;
end;

Procedure TForm1.PrimitivesPageControlChange(Sender: TObject);
Begin

end;


procedure TForm1.RectSpeedButtonClick(Sender: TObject);
Var L,Fi,x1,y1,x2,y2,dx,dy,Xw1,Xw2,Yw1,Yw2:Extended;
    X,Y:Longint;
    Curl:TVCurl;
    AccObject:TAccObject;
    CName,TI,Op:String;
begin
  Drawing:=False;
  JustDrawing:=False;
  Curl:=TVCurl.Create;
  Curl.Saveable:=True;
  If Scene.VCurlList.Count=0 Then CName:='curl0'
  Else CName:=((Scene.VCurlList.Objects[Scene.VCurlList.Count-1]) As TVCurl).Name;
  TI:=IntToStr(StrToInt(Copy(CName,5,Length(CName)-4))+1);
  Scene.VCurlList.AddObject('curl'+TI,Curl);
  Curl.Name:='curl'+TI;
  AccObject:=TAccObject.Create;
  AccObject.AcceleratedCommand:=AccelerateCommand('SetColor '+ColorToString(BorderColorButton.ButtonColor));
  Curl.DisplayList.AddObject('SetColor '+ColorToString(BorderColorButton.ButtonColor),AccObject);
  AccObject:=TAccObject.Create;
  AccObject.AcceleratedCommand:=AccelerateCommand('SetBGColor '+ColorToString(BGColorButton.ButtonColor));
  Curl.DisplayList.AddObject('SetBGColor '+ColorToString(BGColorButton.ButtonColor),AccObject);
  AccObject:=TAccObject.Create;
  AccObject.AcceleratedCommand:=AccelerateCommand('SetWidth '+IntToStr(WidthButton1.Tag));
  Curl.DisplayList.AddObject('SetWidth '+IntToStr(WidthButton1.Tag),AccObject);
  If SnapToGridButton.Down Then Begin
    Xw1:=GridGapEdit.Value*Round(LX1Edit.Value/GridGapEdit.Value);
    Yw1:=GridGapEdit.Value*Round(LY1Edit.Value/GridGapEdit.Value);
    Xw2:=GridGapEdit.Value*Round(LX2Edit.Value/GridGapEdit.Value);
    Yw2:=GridGapEdit.Value*Round(LY2Edit.Value/GridGapEdit.Value);
  End Else Begin
    Xw1:=LX1Edit.Value;
    Yw1:=LY1Edit.Value;
    Xw2:=LX2Edit.Value;
    Yw2:=LY2Edit.Value;
  end;
  AccObject:=TAccObject.Create;
  Case (Sender As TSpeedButton).Caption Of
  'Create Rect': Op:='Rect';
  'Create RRect': Op:='RoundRect';
  'Create Ellipse': Op:='Ellipse';
  End;
  AccObject.AcceleratedCommand:=AccelerateCommand(Op+' '+FloatToStr(Xw1)+','+FloatToStr(Yw1)+','+FloatToStr(Xw2)+','+FloatToStr(Yw2));
  Curl.DisplayList.AddObject(Op+' '+FloatToStr(Xw1)+','+FloatToStr(Yw1)+','+FloatToStr(Xw2)+','+FloatToStr(Yw2),AccObject);
  Scene.View.Add('DrawCurl curl'+TI);
  Scene.ExecCommand('DrawCurl '+Curl.Name,ZeroAcc,0);
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
end;

procedure TForm1.RelatedCAListBoxDblClick(Sender: TObject);
Var CA:TVCallout;
    CAName:String;
    N:Longint;
begin
  If RelatedCAListBox.Items.Count>0 Then Begin
    CAName:=RelatedCAListBox.Items[RelatedCAListBox.ItemIndex];
    N:=Scene.VCalloutList.IndexOf(CAName);
    CA:=Scene.VCalloutList.Objects[N] As TVCallout;
    PrepareCalloutPropEdit(CA);
  end;
end;

procedure TForm1.ReloadSourceSpeedButtonClick(Sender: TObject);
begin
  Dispatcher.QueueCommand('self::CAD_ReloadSource:'+CurrentEditingNameEdit.Text);
  Dispatcher.QueueCommand('self::CAD_UpdateDraw');
end;

procedure TForm1.RenameConnButtonClick(Sender: TObject);
Var N:Longint;
    Conn:TVConnection;Obj1,Obj2:TVObject;
    OldName:String;
begin
  If ConnectionList.ItemIndex>=0 Then Begin
    N:=Scene.VConnectionList.IndexOf(ConnectionList.Items[ConnectionList.ItemIndex]);
    Conn:=Scene.VConnectionList.Objects[N] As TVConnection;
    OldName:=Conn.Name;
    RenameForm.Caption:='Renaming connection from '+Conn.Name;
    RenameForm.Scene:=Scene;
    RenameForm.NewNameEdit.Text:=Conn.Name;
    RenameForm.ShowModal;
    If RenameForm.ModalResult=mrOk Then Begin
      ConnectionList.Items[ConnectionList.ItemIndex]:=RenameForm.NewNameEdit.Text;
      Conn.Name:=RenameForm.NewNameEdit.Text;
      Scene.VConnectionList[N]:=RenameForm.NewNameEdit.Text;
    //обновить имя у связанных объектов
      Form1.SceneMemo.Lines.Assign(Scene.View);
    end;
  end;
end;

procedure TForm1.SaveAsDirMenuItemClick(Sender: TObject);
Var I:Longint;
    FileBuf:TStringList;
begin
  If SaveSceneDialog.Execute Then SceneFileName:=SaveSceneDialog.FileName Else Exit;
//  Dispatcher.ExecCommand('self::CAD_SaveSceneFile:'+SceneFileName);
  If Scene.VGroupList.Count>0 Then
      For I:=0 To Scene.VGroupList.Count-1 Do Begin
        FileBuf:=Scene.SaveItem(Scene.VGroupList[I]);
        FileBuf.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/'+Scene.VGroupList[I]));
        FileBuf.Free;
      end;
  If Scene.VCurlList.Count>0 Then
    For I:=0 To Scene.VCurlList.Count-1 Do Begin
      FileBuf:=Scene.SaveItem(Scene.VCurlList[I]);
      FileBuf.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/'+Scene.VCurlList[I]));
      FileBuf.Free;
    end;
  If Scene.VObjectList.Count>0 Then
    For I:=0 To Scene.VObjectList.Count-1 Do Begin
      FileBuf:=Scene.SaveItem(Scene.VObjectList[I]);
      FileBuf.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/'+Scene.VObjectList[I]));
      FileBuf.Free;
    end;
  If Scene.VCalloutList.Count>0 Then
     For I:=0 To Scene.VCalloutList.Count-1 Do Begin
       FileBuf:=Scene.SaveItem(Scene.VCalloutList[I]);
       FileBuf.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/'+Scene.VCalloutList[I]));
       FileBuf.Free;
     end;
  If Scene.VConnectionList.Count>0 Then
     For I:=0 To Scene.VConnectionList.Count-1 Do Begin
       FileBuf:=Scene.SaveItem(Scene.VConnectionList[I]);
       FileBuf.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/'+Scene.VConnectionList[I]));
       FileBuf.Free;
     end;
  Scene.VCurlList.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_curllist_'));
  Scene.VObjectList.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_objectlist_'));
  Scene.VCalloutList.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_calloutlist_'));
  Scene.VConnectionList.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_connectionlist_'));
  Scene.VGroupList.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_grouplist_'));
  Scene.View.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_displaylist_'));
  Form1.Caption:=TitleString+' '+SceneFileName;
end;

procedure TForm1.SaveToFileAsMenuItemClick(Sender: TObject);
begin
  If SaveSceneDialog.Execute Then SceneFileName:=SaveSceneDialog.FileName Else Exit;
  Dispatcher.ExecCommand('self::CAD_SaveSceneFile:'+SceneFileName);
  Form1.Caption:=TitleString+' '+SceneFileName;
end;

procedure TForm1.SaveToFileMenuItemClick(Sender: TObject);
begin
  If SceneFileName='' Then
    If SaveSceneDialog.Execute Then SceneFileName:=SaveSceneDialog.FileName Else Exit;
  Dispatcher.ExecCommand('self::CAD_SaveSceneFile:'+SceneFileName);
end;

Procedure TForm1.SearchSpeedButtonClick(Sender: TObject);
Begin
  SearchForm.Show;
  SearchForm.SearchFilterCheckGroup.Checked[0]:=SearchFilterObjectSpeedButton.Down;
  SearchForm.SearchFilterCheckGroup.Checked[2]:=SearchFilterConnSpeedButton.Down;
  SearchForm.SearchFilterCheckGroup.Checked[1]:=SearchFilterCalloutSpeedButton.Down;
  SearchForm.SearchFilterCheckGroup.Checked[3]:=SearchFilterCurlSpeedButton.Down;
end;

Procedure TForm1.StartStyleComboBoxChange(Sender: TObject);
Begin
  ConnectionGUI2Scene;
  RepaintView;
end;

Procedure TForm1.UpdateAllSpeedButtonClick(Sender: TObject);
Begin
  UpdateAll;
  AutoUpdateTimer.Enabled:=UpdateAllSpeedButton.Down;
end;

Procedure TForm1.UpdateAllSpeedButtonDblClick(Sender: TObject);
Begin
// UpdateAllSpeedButton.AllowAllUp:=Not UpdateAllSpeedButton.AllowAllUp;
  UpdateAllSpeedButton.Down:=Not UpdateAllSpeedButton.Down;
end;

Procedure TForm1.ViewScaleEditEditingDone(Sender: TObject);
Begin
  If LockCoordUpdate Then Exit;
  If BasisChanging Then Exit;
  If ViewScaleEdit.Value>0.00001 Then
     Dispatcher.ExecCommand('self::CAD_UpdateScale');
end;

Procedure TForm1.ViewScaleEditKeyUp(Sender: TObject; Var Key: Word;
  Shift: TShiftState);
Begin
  If ssCtrl in Shift Then Exit;
  RepaintView;
end;

procedure TForm1.SearchEditKeyUp(Sender: TObject; var Key: Word;
  Shift: TShiftState);
Var I:Longint;Tmp:String;
    Callout:TVCallout;
begin
    If (Key=VK_return) Then SearchListBox.Hide;
    If (Key=VK_return) Or (Key=VK_Left) Or (Key=VK_Right) Or (Key=VK_Tab) Then Exit;
    If (Key=VK_Up) Then Begin
      If SearchListBox.Items.Count>0 Then Begin
        If SearchListBox.ItemIndex<0 Then SearchListBox.ItemIndex:=0;
        If SearchListBox.ItemIndex=0 Then SearchListBox.ItemIndex:=SearchListBox.Items.Count-1
        Else SearchListBox.ItemIndex:=SearchListBox.ItemIndex-1;
      end;
      SearchEdit.Text:=SearchListBox.Items[SearchListBox.ItemIndex];
      Exit;
    End;
    If (Key=VK_Down) Then Begin
      If SearchListBox.Items.Count>0 Then Begin
        If SearchListBox.ItemIndex<0 Then SearchListBox.ItemIndex:=0 Else
        If SearchListBox.ItemIndex=SearchListBox.Items.Count-1 Then SearchListBox.ItemIndex:=0
        Else SearchListBox.ItemIndex:=SearchListBox.ItemIndex+1;
      end;
      SearchEdit.Text:=SearchListBox.Items[SearchListBox.ItemIndex];
      Exit;
    End;
      Tmp:=SearchEdit.Text;
      SearchListBox.Items.Clear;
      SearchListBox.Left:=SearchEdit.Left;
      SearchListBox.Top:=SearchEdit.Top+SearchEdit.Height;
      If SearchFilterObjectSpeedButton.Down then
        If Scene.VObjectList.Count>0 Then
          For I:=0 To Scene.VObjectList.Count-1 Do
            If Pos(Tmp,Scene.VObjectList[I])>0 Then
              SearchListBox.Items.Add(Scene.VObjectList[I]);
      If SearchFilterCurlSpeedButton.Down then
        If Scene.VCurlList.Count>0 Then
          For I:=0 To Scene.VCurlList.Count-1 Do
            If Pos(Tmp,Scene.VCurlList[I])>0 Then
              SearchListBox.Items.Add(Scene.VCurlList[I]);
      If SearchFilterConnSpeedButton.Down then
        If Scene.VConnectionList.Count>0 Then
            For I:=0 To Scene.VConnectionList.Count-1 Do
              If Pos(Tmp,Scene.VConnectionList[I])>0 Then
                SearchListBox.Items.Add(Scene.VConnectionList[I]);
      If SearchFilterCalloutSpeedButton.Down then
        If Scene.VCalloutList.Count>0 Then
          For I:=0 To Scene.VCalloutList.Count-1 Do
            If Pos(Tmp,Scene.VCalloutList[I])>0 Then
              SearchListBox.Items.Add(Scene.VCalloutList[I])
            Else Begin
              // if fulltext search
              Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
              If Pos(Tmp,Callout.Text)>0 Then SearchListBox.Items.Add(Scene.VCalloutList[I]);
            end;
     If SearchListBox.Items.Count=0 Then SearchListBox.Hide Else SearchListBox.Show;
     SearchEdit.SelStart:=Length(SearchEdit.Text);
  end;

procedure TForm1.SearchFilterCurlSpeedButtonClick(Sender: TObject);
Var I:Longint;
begin
  If SearchFilterCurlSpeedButton.Down Then Begin
    CurlsTabSheet.TabVisible:=True;
  end Else Begin
    CurlsTabSheet.TabVisible:=False;
    If CurlList.Count>0 Then
      For I:=0 To CurlList.Count-1 Do
        CurlList.Selected[I]:=False;
  end;
  If SearchFilterObjectSpeedButton.Down Then Begin
    ObjectsTabSheet.TabVisible:=True;
  end Else Begin
    ObjectsTabSheet.TabVisible:=False;
    If ObjectList.Count>0 Then
      For I:=0 To ObjectList.Count-1 Do
        ObjectList.Selected[I]:=False;
  end;
  If SearchFilterConnSpeedButton.Down Then Begin
    ConnectionsTabSheet.TabVisible:=True;
  end Else Begin
    ConnectionsTabSheet.TabVisible:=False;
    If ConnectionList.Count>0 Then
      For I:=0 To ConnectionList.Count-1 Do
        ConnectionList.Selected[I]:=False;
  end;
  If SearchFilterCalloutSpeedButton.Down Then Begin
    CalloutsTabSheet.TabVisible:=True;
  end Else Begin
    CalloutsTabSheet.TabVisible:=False;
    If CalloutList.Count>0 Then
      For I:=0 To CalloutList.Count-1 Do
        CalloutList.Selected[I]:=False;
  end;


end;

procedure TForm1.SearchListBoxClick(Sender: TObject);
begin
  If SearchListBox.ItemIndex<0 Then Exit;
 // If Lock Then Exit;
  SearchEdit.Text:=SearchListBox.Items[SearchListBox.ItemIndex];
  SearchListBox.Clear;
  SearchListBox.Hide;
  Form1.SearchEdit.SelStart:=Length(Form1.SearchEdit.Text);
end;


Procedure TForm1.SelAllConnSpeedButtonClick(Sender: TObject);
Var I:Longint;
begin
  If ConnectionList.Count>0 Then Begin
    If ConnectionList.SelCount=ConnectionList.Count Then
      For I:=0 To ConnectionList.Count-1 Do
        ConnectionList.Selected[I]:=False
    Else
      For I:=0 To ConnectionList.Count-1 Do
        ConnectionList.Selected[I]:=True;
  end;
end;

procedure TForm1.SelAllCurlSpeedButtonClick(Sender: TObject);
Var I:Longint;
begin
  If CurlList.Count>0 Then Begin
    If CurlList.SelCount=CurlList.Count Then
      For I:=0 To CurlList.Count-1 Do
        CurlList.Selected[I]:=False
    Else
      For I:=0 To CurlList.Count-1 Do
        CurlList.Selected[I]:=True;
  end;
end;

procedure TForm1.SelAllObjSpeedButtonClick(Sender: TObject);
Var I:Longint;
begin
  If ObjectList.Count>0 Then Begin
    If ObjectList.SelCount=ObjectList.Count Then
      For I:=0 To ObjectList.Count-1 Do
        ObjectList.Selected[I]:=False
    Else
      For I:=0 To ObjectList.Count-1 Do
        ObjectList.Selected[I]:=True;
  end;
  UpdateMultiSelection;
end;

procedure TForm1.DetachToolsButtonClick(Sender: TObject);
begin
  If DetachToolsButton.Down Then Begin
      ToolOptionsPanel.Parent:=InspectorForm;
      ToolOptionsPanel.Align:=alClient;
      InspectorForm.Show;
  end Else Begin
      InspectorForm.Hide;
      ToolOptionsPanel.Parent:=DrawingPanel;
      ToolOptionsPanel.Align:=alLeft;
      ToolOptionsPanel.Width:=190;
  end;
  Form1.RefreshSpeedLabel.Left:=Form1.Splitter2.Left+20;
end;


procedure TForm1.SelectionListEditorDblClick(Sender: TObject);
Var ItemName,ItemType:String;
    Obj:TVObject;
    Callout:TVCallout;
    Connection:TVConnection;
    I,N:Longint;
begin
  ItemName:=SelectionListEditor.Cells[1,SelectionListEditor.Row];
  ItemType:=SelectionListEditor.Cells[0,SelectionListEditor.Row];
  Case ItemType Of
  'curl': Begin
      {      N:=Scene.VCurlList.IndexOf(ItemName);
            If N<0 Then Exit;
            Curl:=Scene.VCurlList.Objects[N] As TVCurl;}
          end;
   'object': Begin
               N:=Scene.VObjectList.IndexOf(ItemName);
               If N<0 Then Exit;
               Obj:=Scene.VObjectList.Objects[N] As TVObject;
               CurrentEditingNameEdit.Text:=ItemName;
               UnselectAllBut(Obj.Name);
               PrepareObjectPropEdit(Obj);
             End;
   'callout': Begin
               N:=Scene.VCalloutList.IndexOf(ItemName);
               If N<0 Then Exit;
               Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
               CurrentEditingNameEdit.Text:=ItemName;
               UnselectAllBut(Callout.Name);
               PrepareCalloutPropEdit(Callout);
             End;
   'connection': Begin
                  N:=Scene.VConnectionList.IndexOf(ItemName);
                  If N<0 Then Exit;
                  Connection:=Scene.VConnectionList.Objects[N] As TVConnection;
                  CurrentEditingNameEdit.Text:=ItemName;
                  UnselectAllBut(Connection.Name);
                  PrepareConnectionPropEdit(Connection);
                End;
   end;
  //убрать выделение с остальных
   InspectorPanel.Show;
   SelectionListPanel.Hide;
end;

procedure TForm1.SelectionListEditorKeyUp(Sender: TObject; var Key: Word;  Shift: TShiftState);
Var I,T,B,N,Count:Longint;
    ItemName:String;
begin
  T:=SelectionListEditor.Selection.Top;
  B:=SelectionListEditor.Selection.Bottom;
  Count:=SelectionListEditor.RowCount;
  If Key=VK_Return Then Begin   // Select only one?
    ShowMessage('!!!');
 {   For I:=SelectionListEditor.Count-1 DownTo 0 Do Begin
      If SelectionListEditor.S .Items.
    end;}
    Key:=0;
  end;
  If Key=VK_SUBTRACT Then Begin  // Unselect selected
    For I:=Count-1 DownTo 1 Do Begin
      If (I>=T)And(I<=B) Then Begin
        ItemName:=SelectionListEditor.Cells[1,I];
        RemoveItemFromSelection(ItemName);
      end;
    end;
    Key:=0;
  end;
  If Key=VK_ADD Then Begin // Unselect everything but selected
    For I:=Count-1 DownTo 1 Do Begin
      If (I<T)Or(I>B) Then Begin
        ItemName:=SelectionListEditor.Cells[1,I];
        RemoveItemFromSelection(ItemName);
      End;
    end;
    Key:=0;
  end;
end;

procedure TForm1.SettingsSpeedButtonClick(Sender: TObject);
begin
  SettingsForm.Show;
  SettingsForm.WindowState:=wsNormal;
 { If LowerCase(ConfigFile.Values['SelectionMode'])='pen' Then SettingsForm.SelectionModeRadioGroup.ItemIndex:=0
  Else SettingsForm.SelectionModeRadioGroup.ItemIndex:=1;}
end;

procedure TForm1.SnapToGridButtonClick(Sender: TObject);
begin
  LX1GEdit.Visible:=SnapToGridButton.Down;
  LX2GEdit.Visible:=SnapToGridButton.Down;
  LY1GEdit.Visible:=SnapToGridButton.Down;
  LY2GEdit.Visible:=SnapToGridButton.Down;
  LdXGEdit.Visible:=SnapToGridButton.Down;
  LdYGEdit.Visible:=SnapToGridButton.Down;
end;

Procedure DisplayDebug;
Begin
  If SettingsForm=Nil Then Exit;
    If Unit1.Resizing Then SettingsForm.Resizing_Label.Caption:='Resizing:T' else SettingsForm.Resizing_Label.Caption:='Resizing:F';
    If Moving Then SettingsForm.Moving_Label.Caption:='Moving:T' else SettingsForm.Moving_Label.Caption:='Moving:F';
    If Drawing Then SettingsForm.Drawing_Label.Caption:='Drawing:T' else SettingsForm.Drawing_Label.Caption:='Drawing:F';
    If JustDrawing Then SettingsForm.JustDrawing_Label.Caption:='JustDrawing:T' else SettingsForm.JustDrawing_Label.Caption:='JustDrawing:F';
    If ClickNotDrag Then SettingsForm.ClickNotDrag_Label.Caption:='ClickNotDrag:T' else SettingsForm.ClickNotDrag_Label.Caption:='ClickNotDrag:F';
    If Renaming Then SettingsForm.Renaming_Label.Caption:='Renaming:T' else SettingsForm.Renaming_Label.Caption:='Renaming:F';
    If AllowMove Then SettingsForm.AllowMove_Label.Caption:='AllowMove:T' else SettingsForm.AllowMove_Label.Caption:='AllowMove:F';
    SettingsForm.CurrentModeEdit.Text:=EditMode;
End;

procedure TForm1.AddPortSpeedButtonClick(Sender: TObject);
Var Obj:TVObject;Port:TVPort;AccObject:TAccObject;
    ObjName:String;
    I,N:Longint;
begin
//  If ObjectList.SelCount<>1 Then Exit;
  N:=Scene.VObjectList.IndexOf(CurrentEditingNameEdit.Text);
  If N<0 Then Exit;
//  ObjName:=ObjectList.Items[ObjectList.ItemIndex];
//  N:=Scene.VObjectList.IndexOf(ObjName);
  Obj:=Scene.VObjectList.Objects[N] As TVObject;
  PortStringGrid.RowCount:=PortStringGrid.RowCount+1;
  GettingPoint:=True;
  Repeat Application.ProcessMessages Until Not GettingPoint;
  Drawing:=False;JustDrawing:=False;
  PortStringGrid.Cells[0,PortStringGrid.RowCount-1]:='port'+IntToStr(PortStringGrid.RowCount-1);
  PortStringGrid.Cells[1,PortStringGrid.RowCount-1]:='R';
  PortStringGrid.Cells[2,PortStringGrid.RowCount-1]:=FloatToStr(
           (SelectX1w-Obj.Shell.X1)/(Obj.Shell.X2-Obj.Shell.X1));
  PortStringGrid.Cells[3,PortStringGrid.RowCount-1]:=FloatToStr(
        (SelectY1w-Obj.Shell.Y1)/(Obj.Shell.Y2-Obj.Shell.Y1));
  If Obj.PortList.Count<PortStringGrid.RowCount-1 Then Begin
    Port:=TVPort.Create;
    Port.Name:=PortStringGrid.Cells[0,PortStringGrid.RowCount-1];
    Port.AR:=PortStringGrid.Cells[1,PortStringGrid.RowCount-1];
    Port.X:=StrToFloat(PortStringGrid.Cells[2,PortStringGrid.RowCount-1]);
    Port.Y:=StrToFloat(PortStringGrid.Cells[3,PortStringGrid.RowCount-1]);
    Port.AX:=SelectX1w;
    Port.AY:=SelectY1w;
    Port.Connection:='';
    Port.ConnectionPort:='';
    Obj.PortList.AddObject(Port.Name,Port);
    AccObject:=TAccObject.Create;
    AccObject.AcceleratedCommand:=AccelerateCommand('UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone));
    Obj.DisplayList.AddObject('UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone),AccObject);
    Scene.ExecCommand('DrawObject '+Obj.Name,ZeroAcc,0);
  End;
end;

Procedure ArrangePortsByRect(ObjName,Ms,Ns:String);
Var W,H,dx,dy,X,Y:Extended;
    I,J,K,M,N:Longint;
    Obj:TVObject;
    Port:TVPort;
    SmallShell:TShell;
Begin
  If GetTypeByName(Scene,ObjName)<>'object' Then Exit;
  Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(ObjName)] as TVObject;
  M:=StrToInt(Ms);  N:=StrToInt(Ns);
  If (M=0) And (N=0) Then Begin
    M:=Round(Sqrt(Obj.PortList.Count));
    N:=(Obj.PortList.Count Div M);
    If (Obj.PortList.Count Mod M)>0 Then N:=N+1;
  End;
  SmallShell.X1:=(Obj.Shell.X1+Obj.Shell.X2)/2-(Obj.Shell.X2-Obj.Shell.X1)*0.8/2;
  SmallShell.X2:=(Obj.Shell.X1+Obj.Shell.X2)/2+(Obj.Shell.X2-Obj.Shell.X1)*0.8/2;
  SmallShell.Y1:=(Obj.Shell.Y1+Obj.Shell.Y2)/2-(Obj.Shell.Y2-Obj.Shell.Y1)*0.8/2;
  SmallShell.Y2:=(Obj.Shell.Y1+Obj.Shell.Y2)/2+(Obj.Shell.Y2-Obj.Shell.Y1)*0.8/2;
  W:=SmallShell.X2-SmallShell.X1;
  H:=SmallShell.Y2-SmallShell.Y1;
  If N>1 Then dx:=W/(N-1) Else dx:=0;
  If M>1 Then dy:=H/(M-1) Else dy:=0;
  Y:=SmallShell.Y1;
  K:=0;
  For I:=1 To M Do Begin
    X:=SmallShell.X1;
    For J:=1 To N Do Begin
      If K=Obj.PortList.Count Then Break;
      Port:=Obj.PortList.Objects[K] As TVPort;
      Port.AX:=X;
      Port.AY:=Y;
      If Port.AR='R' Then Begin
        Port.X:=(X-Obj.Shell.X1)/(Obj.Shell.X2-Obj.Shell.X1);
        Port.Y:=(Y-Obj.Shell.Y1)/(Obj.Shell.Y2-Obj.Shell.Y1);
      End;
      Inc(K);
      X:=X+dx;
    End;
    Y:=Y+dy;
  End;
//  Scene.UpdateObjectPorts(Obj);
  Scene.MoveObjectTo(Obj,Obj.X,Obj.Y,'');
End;

Procedure ArrangePortsByRectAll(Ms,Ns:String);
Var W,H,dx,dy,X,Y:Extended;
    I,J,K,M,N:Longint;
    Obj:TVObject;
Begin
  If Scene.VObjectList.Count>0 Then
    For I:=0 To Scene.VObjectList.Count-1 Do Begin
      Obj:=Scene.VObjectList.Objects[I] As TVObject;
      ArrangePortsByRect(Obj.Name,Ms,Ns);
    End;
End;

Procedure ArrangePortsByLines(ObjName,IXPos,IYPos,OXPos,OYPos:String);
Var W,H,Idx,Idy,Odx,Ody,IX,IY,OX,OY:Extended;
    I,J,K,M,N,NumInput,NumOutput:Longint;
    Obj:TVObject;
    Port:TVPort;
    SmallShell:TShell;
Begin
  If GetTypeByName(Scene,ObjName)<>'object' Then Exit;
  Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(ObjName)] as TVObject;
  NumInput:=0;
  NumOutput:=0;
  For I:=0 To Obj.PortList.Count-1 Do Begin
    Port:=Obj.PortList.Objects[I] As TVPort;
    If (Port.Connection<>'') And (Port.ConnectionPort='End') Then
      Inc(NumInput);
    If (Port.Connection<>'') And (Port.ConnectionPort='Start') Then
      Inc(NumOutput);
  End;
  SmallShell.X1:=(Obj.Shell.X1+Obj.Shell.X2)/2-(Obj.Shell.X2-Obj.Shell.X1)*0.9/2;
  SmallShell.X2:=(Obj.Shell.X1+Obj.Shell.X2)/2+(Obj.Shell.X2-Obj.Shell.X1)*0.9/2;
  SmallShell.Y1:=(Obj.Shell.Y1+Obj.Shell.Y2)/2-(Obj.Shell.Y2-Obj.Shell.Y1)*0.9/2;
  SmallShell.Y2:=(Obj.Shell.Y1+Obj.Shell.Y2)/2+(Obj.Shell.Y2-Obj.Shell.Y1)*0.9/2;
  W:=SmallShell.X2-SmallShell.X1;
  H:=SmallShell.Y2-SmallShell.Y1;
  //   Object1,-,0.1,-,0.9
  If IXPos='-' Then Begin
    IX:=SmallShell.X1;
    Idx:=W/(NumInput+1);
  End Else Begin
    IX:=SmallShell.X1+StrToFloat(IXPos)*W;
    Idx:=0;
  End;
  If IYPos='-' Then Begin
    IY:=SmallShell.Y1;
    Idy:=H/(NumInput+1);
  End Else Begin
    IY:=SmallShell.Y1+StrToFloat(IYPos)*H;
    Idy:=0;
  End;
  If OXPos='-' Then Begin
    OX:=SmallShell.X1;
    Odx:=W/(NumOutput+1);
  End Else Begin
    OX:=SmallShell.X1+StrToFloat(OXPos)*W;
    Odx:=0;
  End;
  If OYPos='-' Then Begin
    OY:=SmallShell.Y1;
    Ody:=H/(NumOutput+1);
  End Else Begin
    OY:=SmallShell.Y1+StrToFloat(OYPos)*H;
    Ody:=0;
  End;
  For I:=0 To Obj.PortList.Count-1 Do Begin
    Port:=Obj.PortList.Objects[I] As TVPort;
    If (Port.Connection<>'') And (Port.ConnectionPort='End') Then Begin
      IX:=IX+Idx;
      IY:=IY+Idy;
      Port.AX:=IX;
      Port.AY:=IY;
      If Port.AR='R' Then Begin
        Port.X:=(IX-Obj.Shell.X1)/(Obj.Shell.X2-Obj.Shell.X1);
        Port.Y:=(IY-Obj.Shell.Y1)/(Obj.Shell.Y2-Obj.Shell.Y1);
      End;
    End;
    If (Port.Connection<>'') And (Port.ConnectionPort='Start') Then Begin
      OX:=OX+Odx;
      OY:=OY+Ody;
      Port.AX:=OX;
      Port.AY:=OY;
      If Port.AR='R' Then Begin
        Port.X:=(OX-Obj.Shell.X1)/(Obj.Shell.X2-Obj.Shell.X1);
        Port.Y:=(OY-Obj.Shell.Y1)/(Obj.Shell.Y2-Obj.Shell.Y1);
      End;
    End;
  End;
//  Scene.UpdateObjectPorts(Obj);
  Scene.MoveObjectTo(Obj,Obj.X,Obj.Y,'');
End;

Procedure ArrangeObjectsByRect(ObjList:TStringList;Ms,Ns:String);
Var W,H,dx,dy,X,Y:Extended;
    I,J,K,M,N:Longint;
    Obj:TVObject;
    Port:TVPort;
    NewShell,SmallShell:TShell;
    ObjName:String;
Begin
  If ObjList.Count=0 Then Exit;
  M:=StrToInt(Ms);  N:=StrToInt(Ns);
  If (M=0) And (N=0) Then Begin
    M:=Round(Sqrt(ObjList.Count));
    N:=(ObjList.Count Div M);
    If (ObjList.Count Mod M)>0 Then N:=N+1;
  End;
  NewShell:=Scene.ScreenShell;
  SmallShell.X1:=(NewShell.X1+NewShell.X2)/2-(NewShell.X2-NewShell.X1)*0.8/2;
  SmallShell.X2:=(NewShell.X1+NewShell.X2)/2+(NewShell.X2-NewShell.X1)*0.8/2;
  SmallShell.Y1:=(NewShell.Y1+NewShell.Y2)/2-(NewShell.Y2-NewShell.Y1)*0.8/2;
  SmallShell.Y2:=(NewShell.Y1+NewShell.Y2)/2+(NewShell.Y2-NewShell.Y1)*0.8/2;
  W:=SmallShell.X2-SmallShell.X1;
  H:=SmallShell.Y2-SmallShell.Y1;
  If N>1 Then dx:=W/(N-1) Else dx:=0;
  If M>1 Then dy:=H/(M-1) Else dy:=0;
  Y:=SmallShell.Y1;
  K:=0;
  For I:=1 To M Do Begin
    X:=SmallShell.X1;
    For J:=1 To N Do Begin
      If K=ObjList.Count Then Break;
      ObjName:=ObjList[K];
      Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(ObjName)] As TVObject;
      Scene.MoveObjectTo(Obj,X,Y,'');
      Inc(K);
      X:=X+dx;
    End;
    Y:=Y+dy;
  End;
End;


procedure TForm1.DetachDetailsSpeedButtonClick(Sender: TObject);
begin
  If DetachDetailsSpeedButton.Down Then Begin
    ShowSceneDetailsButton.Down:=True;
    PrimitivesPageControl.Parent:=DetailForm;
    DetailForm.Show;
    SceneDetailsPanel.Hide;
  end Else Begin
    If ShowSceneDetailsButton.Down Then Begin
      DetailForm.Hide;
      SceneDetailsPanel.Show;
      PrimitivesPageControl.Parent:=SceneDetailsPanel;
    end Else Begin
      DetailForm.Hide;
      SceneDetailsPanel.Hide;
      PrimitivesPageControl.Parent:=SceneDetailsPanel;
    end;
  end;
end;

procedure TForm1.Send2SceneSpeedButtonClick(Sender: TObject);
Var I,N:Longint;
     CurlName:String; Curl:TVCurl;
     TemplName:String; Template:TVTemplate;
     ObjName:String; Obj:TVObject;
     AccObject:TAccObject;
begin
  If Pos('curl',TPGEditForm.Caption)=11 Then Begin
    If Scene.View.Count>0 Then Begin
      For I:=0 To Scene.View.Count-1 Do
        Drawer.ExecCommand(Scene.View[I],ZeroAcc);
    end;
    CurlName:=Copy(TPGEditForm.Caption,16,Length(TPGEditForm.Caption)-16);
    N:=Scene.VCurlList.IndexOf(CurlName);
    If N>=0 Then Begin
      Curl:=Scene.VCurlList.Objects[N] As TVCurl;
      For I:=Curl.DisplayList.Count-1 DownTo 0 Do Begin
        AccObject:=Curl.DisplayList.Objects[I] As TAccObject;
        Curl.DisplayList.Delete(I);
        AccObject.Free;
      end;
      For I:=0 To TPGEditMemo.Lines.Count-1 Do Begin
        AccObject:=TAccObject.Create;
        AccObject.AcceleratedCommand:=AccelerateCommand(TPGEditMemo.Lines[I]);
        Curl.DisplayList.AddObject(TPGEditMemo.Lines[I],AccObject);
      end;
    End;
  end;
  If Pos('template',TPGEditForm.Caption)=11 Then Begin
      TemplName:=Copy(TPGEditForm.Caption,20,Length(TPGEditForm.Caption)-19);
      N:=Scene.VTemplateList.IndexOf(TemplName);
      If N>=0 Then Begin
        Template:=Scene.VTemplateList.Objects[N] As TVTemplate;
        For I:=Template.DisplayList.Count-1 DownTo 0 Do Begin
          AccObject:=Template.DisplayList.Objects[I] As TAccObject;
          Template.DisplayList.Delete(I);
          AccObject.Free;
        end;
        For I:=0 To TPGEditMemo.Lines.Count-1 Do Begin
          AccObject:=TAccObject.Create;
          AccObject.AcceleratedCommand:=AccelerateCommand(TPGEditMemo.Lines[I]);
          Template.DisplayList.AddObject(TPGEditMemo.Lines[I],AccObject);
        end;
      end;
  End;
  If Pos('object',TPGEditForm.Caption)=11 Then Begin
      ObjName:=Copy(TPGEditForm.Caption,18,Length(TPGEditForm.Caption)-17);
      N:=Scene.VObjectList.IndexOf(ObjName);
      If N>=0 Then Begin
        Obj:=Scene.VObjectList.Objects[N] As TVObject;
        For I:=Curl.DisplayList.Count-1 DownTo 0 Do Begin
          AccObject:=Curl.DisplayList.Objects[I] As TAccObject;
          Obj.DisplayList.Delete(I);
          AccObject.Free;
        End;
        For I:=0 To TPGEditMemo.Lines.Count-1 Do Begin
          AccObject:=TAccObject.Create;
          AccObject.AcceleratedCommand:=AccelerateCommand(TPGEditMemo.Lines[I]);
          Obj.DisplayList.AddObject(TPGEditMemo.Lines[I],AccObject);
        end;
      end;
  End;

  Form1.DrawingPanel.Invalidate;

end;

procedure TForm1.SourceEditChange(Sender: TObject);
begin

end;

procedure TForm1.SourceEditEditingDone(Sender: TObject);
begin
  If LockBackUpdate Then Exit;
  Case GetTypeByName(Scene,CurrentEditingNameEdit.Text) of
    'object':  Begin
                 ObjectGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    'callout': Begin
                 CalloutGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 TextMemo.Clear;
//                 RepaintView;
                 Dispatcher.QueueCommand('self::CAD_UpdateDraw');
{                 CalloutGUI2Scene;
                 DeleteSelHandles(CurrentEditingNameEdit.Text);
                 CreateSelHandles(CurrentEditingNameEdit.Text);

                 RepaintView;   }

               End;
  end;
end;



procedure TForm1.FontComboBoxChange(Sender: TObject);
begin
  If LockBackUpdate Then Exit;
  FontDialog.Font.Name:=FontComboBox.Text;
  TLabelEdit.Font:=FontDialog.Font;
  Form1.FontSizeEditChange(Sender);
end;

procedure TForm1.LibraryShellTreeViewSelectionChanged(Sender: TObject);
Var Obj:TVObject;
    I,Index:Longint;Buf,ParsedBuf:String;
    Sm,Rm,Scm,tmpm,TransM:TMatrix2D;
    TemplName:String;
begin
    If LockBackUpdate Then Exit;
    If LibraryShellTreeView.Selected=Nil Then Exit;
    If Pos('.tpg',(OSPath(LibraryShellTreeView.Path)))=0 Then Exit;
    TemplName:=Copy(ExtractFileName(Form1.LibraryShellTreeView.Path),1,Length(ExtractFileName(Form1.LibraryShellTreeView.Path))-Length(ExtractFileExt(Form1.LibraryShellTreeView.Path)));
    LoadTemplate(OSPath(LibraryShellTreeView.Path));
    LoadTemplate(TemplName);
    NumTemplatesLabel.Caption:=IntToStr(TemplateList.Items.Count);
    If EditMode='object' Then Begin
      RubberDisplayList.Clear;
      RubberDisplayList.Add('DrawTemplate '+TemplName+' '+Form1.XEdit.Text+','+Form1.YEdit.Text+','+Form1.AEdit.Text+','+Form1.SEdit.Text);
      HintLabel.Hide;
    End;
    If AutoButton.Down Or ObjButton.Down Then Exit; //
    //If ObjectList.SelCount=1 Then Begin
    If EditMode='edit' Then
      If GetTypeByName(Scene,CurrentEditingNameEdit.Text)='object' Then Begin
      //кажется изменяем шаблон уже существующего объекта
      Index:=Scene.VObjectList.IndexOf(CurrentEditingNameEdit.Text);
      Obj:=Scene.VObjectList.Objects[Index] As TVObject;
      TemplName:=Copy(ExtractFileName(LibraryShellTreeView.Path),1,Length(ExtractFileName(LibraryShellTreeView.Path))-Length(ExtractFileExt(LibraryShellTreeView.Path)));
      Obj.Template:=TemplName;
      Scene.ObjectAttr2Style(Obj);
      Scene.UpdateObjectDisplayList(Obj);

{      If Obj.DisplayList.Count>0 Then
        For I:=0 To Obj.DisplayList.Count-1 Do Begin
          Buf:=Obj.DisplayList[I];
          If Pos('DrawTemplate',Buf)=1 Then
          GetNextToken(Buf,ParsedBuf,' ');
          Buf:=ParsedBuf;
          Obj.X:=XEdit.Value; Obj.Y:=YEdit.Value;
          Obj.A:=AEdit.Value; Obj.S:=SEdit.Value;
          TemplName:=Copy(ExtractFileName(LibraryShellTreeView.Path),1,Length(ExtractFileName(LibraryShellTreeView.Path))-Length(ExtractFileExt(LibraryShellTreeView.Path)));
          Obj.Template:=TemplName;
          Obj.DisplayList[I]:='DrawTemplate '+TemplName+' '+Form1.XEdit.Text+','+Form1.YEdit.Text+','+Form1.AEdit.Text+','+Form1.SEdit.Text;
          Sm:=GenShift(Obj.X,Obj.Y);
          Rm:=GenRotate(Obj.X,Obj.Y,Obj.A/180*pi);
          Scm:=GenScale(Obj.X,Obj.Y,Obj.S,Obj.S);
          tmpm:=MulMat2D(Sm,Rm);
          TransM:=MulMat2D(Tmpm,Scm);
          Obj.Shell:=Scene.RenderShell(Obj.DisplayList,TransM);
          Break;
        end;}
      RepaintView;
    end;
  //  JustDrawing:=True;??????
end;

Procedure TForm1.SlideByLinkSpeedButtonClick(Sender: TObject);
Var Destination,DSTBookmark:String;
    Obj:TVObject;
Begin
    If Sender Is TMenuItem Then Begin
      Destination:=(Sender As TMenuItem).Caption;
      If GetTypeByName(Scene,Destination)='object' Then Begin
        Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(Destination)] As TVObject;
        SlideByLinkMenu.Items.Clear;
        Case  Form1.OpComboBox.Text Of
        'Teleport': Begin NavigationMode:='teleport';DstBookMark:=ComputeItemDST(Destination);End;
        'Telezoom': Begin NavigationMode:='telezoom';DstBookMark:=ComputeItemZoomDST(Destination);End;
        'Hover': Begin NavigationMode:='hover';DstBookMark:=ComputeItemDST(Destination);End;
        'HoverZoom': Begin NavigationMode:='hoverzoom';DstBookMark:=ComputeItemZoomDST(Destination);End;
        'Fly': Begin NavigationMode:='fly';DstBookMark:=ComputeItemZoomDST(Destination);End;
//        'FlyZoom': Begin NavigationMode:='flyzoom';DstBookMark:=ComputeItemZoomDST(Destination);End;
        End;
        NavigateTo(DSTBookMark);
      End;
    end;
end;

procedure TForm1.Mul2ButtonClick(Sender: TObject);
begin
  GridGapEdit.Value:=GridGapEdit.Value*2;
end;

procedure TForm1.PeekFontFaceColorButtonClick(Sender: TObject);
begin
  If LockBackUpdate Then Exit;
  FontDialog.Font.Color:=(Sender As TColorButton).ButtonColor;
  TLabelEdit.Font:=FontDialog.Font;
  If GetTypeByName(Scene,CurrentEditingNameEdit.Text)='callout' Then Begin
    CalloutGUI2Scene;
    RepaintView;
  End;
end;

procedure TForm1.DelCurlsButtonClick(Sender: TObject);
Var CurlName:String;
    Curl:TVCurl;I,J,N:Longint;
begin
  TPGEditMemo.Clear;
  If CurlList.Count>0 Then
    For I:=CurlList.Count-1 Downto 0 Do Begin
      If CurlList.Selected[I] Then Begin
        CurlName:=CurlList.Items[I];
        N:=Scene.VCurlList.IndexOf(CurlName);
        Curl:=Scene.VCurlList.Objects[N] As TVCurl;
        Curl.Free;
        If Scene.View.IndexOf('DrawCurl '+CurlName)>-1 Then Scene.View.Delete(Scene.View.IndexOf('DrawCurl '+CurlName));
        Scene.VCurlList.Delete(N);
        CurlList.Items.Delete(I);
        NumCurlsLabel.Caption:=IntToStr(CurlList.Items.Count);
      end;
    end;
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
end;

procedure TForm1.DelObjsButtonClick(Sender: TObject);
Var ObjName:String;
    Obj:TVObject;I,J,N:Longint;
begin
  TPGEditMemo.Clear;
  If ObjectList.Count>0 Then
    For I:=ObjectList.Count-1 Downto 0 Do Begin
      If ObjectList.Selected[I] Then Begin
        ObjName:=ObjectList.Items[I];
        Scene.DeleteSelHandles(ObjName);
        N:=Scene.VObjectList.IndexOf(ObjName);
        Obj:=Scene.VObjectList.Objects[N] As TVObject;
        Obj.Free;
        If Scene.View.IndexOf('DrawObject '+ObjName)>-1 Then Scene.View.Delete(Scene.View.IndexOf('DrawObject '+ObjName));
        Scene.VObjectList.Delete(N);
        ObjectList.Items.Delete(I);
        NumObjectsLabel.Caption:=IntToStr(ObjectList.Items.Count);
      end;
    end;
  UpdateMultiSelection;
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  RepaintView;
end;

procedure TForm1.DelTemplButtonClick(Sender: TObject);
Var TemplName:String;
    Template:TVTemplate;I,J,N:Longint;
begin
  TPGEditMemo.Clear;
  If TemplateList.Count>0 Then
    For I:=TemplateList.Count-1 Downto 0 Do Begin
      If TemplateList.Selected[I] Then Begin
        TemplName:=TemplateList.Items[I];
        TemplateList.Items.Delete(I);
        NumTemplatesLabel.Caption:=IntToStr(TemplateList.Items.Count);
        N:=Scene.VTemplateList.IndexOf(TemplName);
        Template:=Scene.VTemplateList.Objects[N] As TVTemplate;
        Template.Free;
        Scene.VTemplateList.Delete(N);
//    deletion of objects referencing to the Template shopuld be here
//        If Scene.View.IndexOf('DrawCurl '+CurlName)>-1 Then Scene.View.Delete(Scene.View.IndexOf('DrawCurl '+CurlName));
//        Scene.VCurlList.Delete(N);
      end;
    end;
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
end;

procedure TForm1.FileNewButtonClick(Sender: TObject);
begin
  If QuestionDlg(Application.Title,'Erase whole scene?',mtConfirmation,[mrOK, 'Ok', mrCancel,'Cancel'], 0)=mrCancel Then Exit;
  SelectionListEditor.Clear;
  Scene.Clear;
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  SceneFileName:='';
  Form1.Caption:=TitleString+' '+SceneFileName;
end;

procedure TForm1.GUI2SceneBtnClick(Sender: TObject);
begin
  Dispatcher.ExecCommand('self::CAD_GUI2Scene');
end;

procedure TForm1.LdXEditChange(Sender: TObject);
Var L,Fi,x1,y1,x2,y2,dx,dy:Extended;
begin
  If LockBackUpdate then Exit;
  If UpdateFrom<>updDX Then Exit;
  X1:=LX1Edit.Value;  dx:=LDXEdit.Value;
  Y1:=LY1Edit.Value;  dy:=LDYEdit.Value;
  X2:=X1+dx;
  Y2:=Y1+dy;
  L:=Sqrt(Sqr(dx)+Sqr(dy));
  Fi:=ComputeFi(dx,dy);
  LLEdit.Value:=L;
  LFiEdit.Value:=Fi/pi*180;
  LX2Edit.Value:=X2;
  LY2Edit.Value:=Y2;
  Case GetTypeByName(Scene,CurrentEditingNameEdit.Text) of
    'object':  Begin
                 ObjectGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    'callout': Begin
                 CalloutGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    end;

end;

procedure TForm1.LdXEditEditingDone(Sender: TObject);
begin
  UpdateFrom:=upddX;
end;

procedure TForm1.LdYEditChange(Sender: TObject);
Var L,Fi,x1,y1,x2,y2,dx,dy:Extended;
begin
  If LockBackUpdate then Exit;
  If UpdateFrom<>upddY Then Exit;
  X1:=LX1Edit.Value;  dx:=LDXEdit.Value;
  Y1:=LY1Edit.Value;  dy:=LDYEdit.Value;
  X2:=X1+dx;
  Y2:=Y1+dy;
  L:=Sqrt(Sqr(dx)+Sqr(dy));
  Fi:=ComputeFi(dx,dy);
  LLEdit.Value:=L;
  LFiEdit.Value:=Fi/pi*180;
  LX2Edit.Value:=X2;
  LY2Edit.Value:=Y2;
  Case GetTypeByName(Scene,CurrentEditingNameEdit.Text) of
    'object':  Begin
                 ObjectGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    'callout': Begin
                 CalloutGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    end;

end;

procedure TForm1.LdYEditEditingDone(Sender: TObject);
begin
  UpdateFrom:=upddY;
end;

procedure TForm1.LFiEditChange(Sender: TObject);
Var L,Fi,x1,y1,x2,y2,dx,dy:Extended;
begin
  If LockBackUpdate then Exit;
  If UpdateFrom<>updFI Then Exit;
  X1:=LX1Edit.Value;  L:=LLEdit.Value;
  Y1:=LY1Edit.Value;  Fi:=LFiEdit.Value/180*pi;
  X2:=X1+Cos(Fi)*L;
  Y2:=Y1+Sin(Fi)*L;
  LX2Edit.Value:=X2;
  LY2Edit.Value:=Y2;
  Case GetTypeByName(Scene,CurrentEditingNameEdit.Text) of
    'object':  Begin
                 ObjectGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    'callout': Begin
                 CalloutGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    end;

end;

procedure TForm1.LFiEditEditingDone(Sender: TObject);
begin
  UpdateFrom:=updFI;
end;

procedure TForm1.LineToBtnClick(Sender: TObject);
var L,Fi,x1,y1,x2,y2,dx,dy:Extended;
    X,Y:Longint;
begin
  X2:=LX2Edit.Value;
  Y2:=LY2Edit.Value;
  Drawer.WtoS(X2,Y2,X,Y);
  Image1MouseUp(Sender,mbLeft,[],X,Y);
  LX1Edit.Value:=X2;
  LY1Edit.Value:=Y2;
end;

procedure TForm1.LLEditChange(Sender: TObject);
Var L,Fi,x1,y1,x2,y2,dx,dy:Extended;
begin
  If LockBackUpdate then Exit;
  If UpdateFrom<>updL Then Exit;
  X1:=LX1Edit.Value;  L:=LLEdit.Value;
  Y1:=LY1Edit.Value;  Fi:=LFiEdit.Value/180*pi;
  X2:=X1+Cos(Fi)*L;
  Y2:=Y1+Sin(Fi)*L;
  LX2Edit.Value:=X2;LdXEdit.Value:=X2-X1;
  LY2Edit.Value:=Y2;LdYEdit.Value:=Y2-Y1;
  Case GetTypeByName(Scene,CurrentEditingNameEdit.Text) of
    'object':  Begin
                 ObjectGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    'callout': Begin
                 CalloutGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    end;

end;

procedure TForm1.LLEditEditingDone(Sender: TObject);
begin
  UpdateFrom:=updL;
end;

procedure TForm1.LoadTemplateButtonClick(Sender: TObject);
var I,N:Longint;Template:TVTemplate;
    AccObject:TAccObject;
    B:String;
begin
  If Not OpenTemplateDialog.Execute Then Exit;
  For I:=0 To OpenTemplateDialog.Files.Count-1 Do Begin
    LoadTemplate(OpenTemplateDialog.Files[I]);
  End;
  NumTemplatesLabel.Caption:=IntToStr(TemplateList.Items.Count);
end;

procedure TForm1.LX1EditChange(Sender: TObject);
Var L,Fi,x1,y1,x2,y2,dx,dy:Extended;
begin
  If LockBackUpdate then Exit;
  If UpdateFrom<>updX1 Then Exit;
  X1:=LX1Edit.Value;  X2:=LX2Edit.Value;
  Y1:=LY1Edit.Value;  Y2:=LY2Edit.Value;
  dx:=X2-X1;dy:=Y2-Y1;
  L:=Sqrt(Sqr(dx)+Sqr(dy));
  Fi:=ComputeFI(dx,dy);
  LLEdit.Value:=L;
  LFiEdit.Value:=Fi/Pi*180;
  Case GetTypeByName(Scene,CurrentEditingNameEdit.Text) of
  'object':  Begin
               ObjectGUI2Scene;
               Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
               RepaintView;
             End;
  'callout': Begin
               CalloutGUI2Scene;
               Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
               RepaintView;
             End;
  end;
end;

procedure TForm1.LX1EditEditingDone(Sender: TObject);
begin
  UpdateFrom:=updX1;//101;
end;

procedure TForm1.LX2EditChange(Sender: TObject);
Var L,Fi,x1,y1,x2,y2,dx,dy:Extended;
begin
  If LockBackUpdate then Exit;
  If UpdateFrom<>updX2 Then Exit;
  X1:=LX1Edit.Value;  X2:=LX2Edit.Value;
  Y1:=LY1Edit.Value;  Y2:=LY2Edit.Value;
  dx:=X2-X1;dy:=Y2-Y1;
  L:=Sqrt(Sqr(dx)+Sqr(dy));
  FI:=ComputeFI(Dx,Dy);
  LdXEdit.Value:=dx;
  LdYEdit.Value:=dy;
  LLEdit.Value:=L;
  LFiEdit.Value:=Fi/Pi*180;
  LX1GEdit.Value:=Round(LX1Edit.Value/GridGapEdit.Value);
  Case GetTypeByName(Scene,CurrentEditingNameEdit.Text) of
    'object':  Begin
                 ObjectGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    'callout': Begin
                 CalloutGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    end;
end;

procedure TForm1.LX2EditEditingDone(Sender: TObject);
begin
  UpdateFrom:=updX2;//102;
end;

procedure TForm1.LY1EditChange(Sender: TObject);
Var L,Fi,x1,y1,x2,y2,dx,dy:Extended;
begin
  If LockBackUpdate then Exit;
  If UpdateFrom<>updY1 Then Exit;
  X1:=LX1Edit.Value;  X2:=LX2Edit.Value;
  Y1:=LY1Edit.Value;  Y2:=LY2Edit.Value;
  dx:=X2-X1;dy:=Y2-Y1;
  L:=Sqrt(Sqr(dx)+Sqr(dy));
  Fi:=ComputeFI(dx,dy);
  LLEdit.Value:=L;
  LFiEdit.Value:=Fi/Pi*180;
  Case GetTypeByName(Scene,CurrentEditingNameEdit.Text) of
   'object':  Begin
                ObjectGUI2Scene;
                Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                RepaintView;
              End;
   'callout': Begin
                CalloutGUI2Scene;
                Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                RepaintView;
              End;
   end;

end;

procedure TForm1.LY1EditEditingDone(Sender: TObject);
begin
  UpdateFrom:=updY1;//51;
end;

procedure TForm1.LY2EditChange(Sender: TObject);
Var L,Fi,x1,y1,x2,y2,dx,dy:Extended;
begin
  If LockBackUpdate then Exit;
  If UpdateFrom<>updY2 Then Exit;
  X1:=LX1Edit.Value;  X2:=LX2Edit.Value;
  Y1:=LY1Edit.Value;  Y2:=LY2Edit.Value;
  dx:=X2-X1;dy:=Y2-Y1;
  L:=Sqrt(Sqr(dx)+Sqr(dy));
  Fi:=ComputeFI(dx,dy);
  LdXEdit.Value:=dx;
  LdYEdit.Value:=dy;
  LLEdit.Value:=L;
  LFiEdit.Value:=Fi/pi*180;
  Case GetTypeByName(Scene,CurrentEditingNameEdit.Text) of
    'object':  Begin
                 ObjectGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    'callout': Begin
                 CalloutGUI2Scene;
                 Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
                 RepaintView;
               End;
    end;
end;

procedure TForm1.LY2EditEditingDone(Sender: TObject);
begin
  UpdateFrom:=updY2;//52;
end;

procedure TForm1.MoveToBtnClick(Sender: TObject);
var L,Fi,x1,y1,x2,y2,dx,dy:Extended;
    X,Y:Longint;
begin
  X1:=LX1Edit.Value;
  Y1:=LY1Edit.Value;
  Drawer.WtoS(X1,Y1,X,Y);
  Image1MouseUp(Sender,mbLeft,[],X,Y);
end;


procedure TForm1.ObjectListSelectionChange(Sender: TObject; User: boolean);
Var ObjectName:String;
    Obj:TVObject;I,J,N:Longint;
    Sm,Rm,Scm,tmpm,OldTransM:TMatrix2D;
    Buf,ParsedBuf:String;
begin
  If LockSelectionUpdate Then Exit;
  If Not ObjButton.Down Then Begin
    For I:=0 To ObjectList.Items.Count-1 Do Begin
      If (Scene.SelectedList.IndexOf(ObjectList.Items[I])<0)And(ObjectList.Selected[I]) Then Begin
        //свежевыбранный
        AddItemToSelection(ObjectList.Items[I]);
        Continue;
      End;
      If (Scene.SelectedList.IndexOf(ObjectList.Items[I])>=0)And(Not ObjectList.Selected[I]) Then Begin
        //свежеудаленный
        RemoveItemFromSelection(ObjectList.Items[I]);
        Continue;
      End;
    End;
  End;
  TPGEditMemo.Clear;
  TPGEditForm.Caption:='TPG edit: ';
  If ObjectList.Count>0 Then
    For I:=0 To ObjectList.Count-1 Do Begin
      ObjectName:=ObjectList.Items[I];
      N:=Scene.VObjectList.IndexOf(ObjectName);
      Obj:=Scene.VObjectList.Objects[N] As TVObject;
      If ObjectList.Selected[I] Then Begin
        TPGEditForm.Caption:=TPGEditForm.Caption+ObjectName+' ';
        TPGEditMemo.Lines.AddStrings(Obj.DisplayList);
      End;
    end;
  Scene.Drawer.Canvas.Pen.Mode:=pmCopy;
  If Not NavigateButton.Down Then
    If ObjectList.SelCount=1 Then Begin
      N:=Scene.VObjectList.IndexOf(ObjectList.Items[ObjectList.ItemIndex]);
      Obj:=Scene.VObjectList.Objects[N] As TVObject;
      PrepareObjectPropEdit(Obj);
    end Else Begin
      //XYASPanel.Hide;
    End;
end;

procedure TForm1.PanDownButtonClick(Sender: TObject);
Var wx1,wy1:Extended;
begin
  LockCoordUpdate:=True;
  Scene.Drawer.StoW(Drawer.wx div 2,Drawer.wy+Drawer.wy div 2-1,wx1,wy1);
  ViewXEdit.Value:=wx1;
  ViewYEdit.Value:=wy1;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  LockCoordUpdate:=False;
end;

procedure TForm1.PanLeftButtonClick(Sender: TObject);
Var wx1,wy1:Extended;
begin
  LockCoordUpdate:=True;
  Scene.Drawer.StoW(-Drawer.wx div 2,Drawer.Wy div 2,wx1,wy1);
  ViewXEdit.Value:=wx1;
  ViewYEdit.Value:=wy1;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  LockCoordUpdate:=False;
end;

procedure TForm1.PanRightButtonClick(Sender: TObject);
Var wx1,wy1:Extended;
begin
  LockCoordUpdate:=True;
  Scene.Drawer.StoW(Drawer.Wx+Drawer.wx div 2-1,Drawer.Wy div 2,wx1,wy1);
  ViewXEdit.Value:=wx1;
  ViewYEdit.Value:=wy1;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  LockCoordUpdate:=False;
end;

procedure TForm1.PanUpButtonClick(Sender: TObject);
Var wx1,wy1:Extended;
begin
  LockCoordUpdate:=True;
  Scene.Drawer.StoW(Drawer.wx div 2,-Drawer.wy div 2,wx1,wy1);
  ViewXEdit.Value:=wx1;
  ViewYEdit.Value:=wy1;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  LockCoordUpdate:=False;
end;



procedure TForm1.PeekColorButtonClick(Sender: TObject);
begin
  If LockBackUpdate Then Exit;
  LogMessage(0,ColorToString((Sender As TColorButton).ButtonColor));
  TLabelEdit.Color:=(Sender As TColorButton).ButtonColor;

 Case GetTypeByName(Scene,CurrentEditingNameEdit.Text) of
  'object':  Begin
               ObjectGUI2Scene;
               Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
               RepaintView;
             End;
  'callout': Begin
               CalloutGUI2Scene;
               Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
               RepaintView;
             End;
  'connection': Begin
               ConnectionGUI2Scene;
               //Scene.UpdateSelHandles(CurrentEditingNameEdit.Text);
               RepaintView;
             End;
  end;
end;


procedure TForm1.CurlListSelectionChange(Sender: TObject; User: boolean);
Var CurlName:String;
    Curl:TVCurl;I,J,N:Longint;
begin
  If LockSelectionUpdate Then Exit;
  For I:=0 To ObjectList.Items.Count-1 Do Begin
    If (Scene.SelectedList.IndexOf(CurlList.Items[I])<0)And(CurlList.Selected[I]) Then Begin
      //свежевыбранный
      AddItemToSelection(CurlList.Items[I]);
      Continue;
    End;
    If (Scene.SelectedList.IndexOf(CurlList.Items[I])>=0)And(Not CurlList.Selected[I]) Then Begin
      //свежеудаленный
      RemoveItemFromSelection(CurlList.Items[I]);
      Continue;
    End;
  End;

  TPGEditMemo.Clear;
//  If TPGEditForm.Visible Then
  TPGEditForm.Caption:='TPG edit: curl ';
  If CurlList.Count>0 Then
    For I:=0 To CurlList.Count-1 Do Begin
      CurlName:=CurlList.Items[I];
      N:=Scene.VCurlList.IndexOf(CurlName);
      Curl:=Scene.VCurlList.Objects[N] As TVCurl;
      If CurlList.Selected[I] Then Begin
//        If TPGEditForm.Visible Then Begin
          TPGEditMemo.Lines.AddStrings(Curl.DisplayList);
          TPGEditForm.Caption:=TPGEditForm.Caption+CurlName+' ';
//        End;
        If DrawingPanel.Color=clBlack Then Scene.Drawer.Canvas.Pen.Mode:=pmWhite
        Else Scene.Drawer.Canvas.Pen.Mode:=pmNotCopy;//pmNotCopy;
        For J:=0 To Curl.DisplayList.Count-1 Do Begin
          Drawer.ExecCommand(Curl.DisplayList[J],ZeroAcc);
        end;
      end Else Begin
      //рисуем невыделенное
        Scene.Drawer.Canvas.Pen.Mode:=pmCopy;
        For J:=0 To Curl.DisplayList.Count-1 Do Begin
          Drawer.ExecCommand(Curl.DisplayList[J],ZeroAcc);
        end;
      end;
    end;
    Scene.Drawer.Canvas.Pen.Mode:=pmCopy;
end;

procedure TForm1.DrawingPanelResize(Sender: TObject);
begin
  {BufBitMap.Width:=Scene.Drawer.Canvas.Width;
  BufBitMap.Height:=Scene.Drawer.Canvas.Height;}
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
end;

procedure TForm1.FileOpenButtonClick(Sender: TObject);
begin
  LoadPopupMenu.Popup(Form1.Left+FileOpenButton.Left,Form1.Top+FileOpenButton.Top+FileOpenButton.Height+1);
end;

procedure TForm1.FontSizeEditChange(Sender: TObject);
Var W,H:Longint;
begin
  If LockBackUpdate Then Exit;
  FontDialog.Font.Height:=FontSizeEdit.Value;//was font.size:=
  TLabelEdit.Font.Assign(FontDialog.Font);
  DrawingPanel.Canvas.Font.Assign(FontDialog.Font);
  DrawingPanel.Canvas.GetTextSize(TLabelEdit.Text+'  ',w,h);
  TLabelEdit.Width:=W+15;
  TLabelEdit.Height:=H+5;
  If GetTypeByName(Scene,CurrentEditingNameEdit.Text)='callout' Then Begin
    CalloutGUI2Scene;
    RepaintView;
  End;
end;

procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  //Interpreter.DoMultipleSteps:=False;
  Application.Terminate;
end;



procedure TForm1.GridButtonClick(Sender: TObject);
begin
  Dispatcher.ExecCommand('self::CAD_UpdateDraw');
end;

procedure TForm1.GridGapEditChange(Sender: TObject);
begin
  XEdit.Increment:=GridGapEdit.Value;
  YEdit.Increment:=GridGapEdit.Value;
  LX1Edit.Increment:=GridGapEdit.Value;
  LX2Edit.Increment:=GridGapEdit.Value;
  LY1Edit.Increment:=GridGapEdit.Value;
  LY2Edit.Increment:=GridGapEdit.Value;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
//  Dispatcher.ExecCommand('self::CAD_UpdateDraw');
end;

Procedure MD_CommonRect;
Begin
    If Form1.SnapToGridButton.Down Then Begin
      SelectX1s:=CurrentXGs;SelectY1s:=CurrentYGs;
      SelectX1w:=CurrentXGw;SelectY1w:=CurrentYGw;
    end Else Begin
      SelectX1s:=CurrentXs;SelectY1s:=CurrentYs;
      SelectX1w:=CurrentXw;SelectY1w:=CurrentYw;
    End;
    SelectX2s:=SelectX1s;SelectY2s:=SelectY1s;
    Form1.LX1Edit.Value:=SelectX1w;Form1.LX2Edit.Value:=SelectX1w;
    Form1.LY1Edit.Value:=SelectY1w;Form1.LY2Edit.Value:=SelectY1w;
    Form1.LdXEdit.Value:=0;Form1.LdYEdit.Value:=0;
    If Form1.SnapToGridButton.Down Then Begin
      Form1.LX1GEdit.Value:=CurrentXGw;
      Form1.LY1GEdit.Value:=CurrentYGw;
      Form1.LdXGEdit.Value:=0;Form1.LdYGEdit.Value:=0;
    end;
    LastXs:=SelectX1s;LastYs:=SelectY1s;
    LastXw:=SelectX1w;LastYw:=SelectY1w;
    Drawing:=True;
    JustDrawing:=True;
    WCanvas.Pen.Mode:=pmnotXOR;
    WCanvas.Pen.Style:=psDot;
    WCanvas.Pen.Color:=Form1.BorderColorButton.ButtonColor;
    WCanvas.Brush.Color:=Form1.BGColorButton.ButtonColor;
    If EditMode='curl rect' Then
      WCanvas.Rectangle(SelectX1s,SelectY1s,LastXs,LastYs);
    If EditMode='curl rrect' Then
      WCanvas.RoundRect(SelectX1s,SelectY1s,LastXs,LastYs,20,20);
    If EditMode='curl ellipse' Then
      WCanvas.Ellipse(SelectX1s,SelectY1s,LastXs,LastYs);
    If EditMode='curl callout' Then
      WCanvas.Rectangle(SelectX1s,SelectY1s,LastXs,LastYs);
    If EditMode='object' Then
      Case Form1.ObjStyleRadioGroup.ItemIndex Of
      2: WCanvas.Rectangle(SelectX1s,SelectY1s,LastXs,LastYs);
      3: WCanvas.RoundRect(SelectX1s,SelectY1s,LastXs,LastYs,20,20);
      4: WCanvas.Ellipse(SelectX1s,SelectY1s,LastXs,LastYs);
      5,6: WCanvas.Rectangle(SelectX1s,SelectY1s,LastXs,LastYs);
      end;
    Drawing:=True; //или в онмув не проверять
End;

procedure MD_Navigation(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin

End;

procedure MD_Control(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin

End;

Function MD_ProcessSelHandle:Boolean;
Var SelHandle,SelHandleD:TVSelHandle;
    Obj:TVObject;
    Callout:TVCallout;
    Connection:TVConnection;
    ConnPort:TVConnectionPort;
    I,J,N:Longint;
Begin
  Result:=False;
  If Scene.VHandleList.Count>0 Then
    For I:=0 To Scene.VHandleList.Count-1 Do Begin
      SelHandle:=Scene.VHandleList.Objects[I] As TVSelHandle;
      If Abs(SelHandle.X-CurrentXs)+Abs(SelHandle.Y-CurrentYs)<=SelHandleZone Then Begin
          //object resizing started
          Unit1.Resizing:=True;
          Result:=True;
          ActiveSelHandle:=SelHandle;
          Case GetTypeByName(Scene,ActiveSelHandle.Name) Of
          'curl': Begin
                  end;
          'object': Begin
                      N:=Scene.VObjectList.IndexOf(ActiveSelHandle.Name);
                      If N<0 Then Exit;
                      Obj:=Scene.VObjectList.Objects[N] As TVObject;
                     // Form1.CurrentEditingNameEdit.Text:=ActiveSelHandle.Name;
                      UnselectAllBut(Obj.Name);
                      PrepareObjectPropEdit(Obj);
                      RubberDisplayList.Add('DrawObject '+Obj.Name);
                    End;
           'callout': Begin
                       N:=Scene.VCalloutList.IndexOf(ActiveSelHandle.Name);
                       If N<0 Then Exit;
                       Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
                       UnselectAllBut(Callout.Name);
                       AddItemToSelection(Callout.Name);
                       PrepareCalloutPropEdit(Callout);
                       RubberDisplayList.Add('DrawCallout '+Callout.Name);
                     End;
           'connection': Begin
                       N:=Scene.VConnectionList.IndexOf(ActiveSelHandle.Name);
                       If N<0 Then Exit;
                       Connection:=Scene.VConnectionList.Objects[N] As TVConnection;
                       For J:=0 To Connection.PortList.Count-1 Do Begin
                         ConnPort:=Connection.PortList.Objects[J] As TVConnectionPort;
                         If (ConnPort.PortType='Node')Or(ConnPort.PortType='Text') Then
                           If (Abs(SelHandle.Xw-ConnPort.Ax)+Abs(SelHandle.Yw-ConnPort.AY))/Scene.Drawer.ViewScale <=SelHandleZone Then Begin
                             ActiveNodeNum:=J;
                             Break;
                           End;
                       End;
                       UnselectAllBut(Connection.Name);
                       PrepareConnectionPropEdit(Connection);
                       RubberDisplayList.Add('DrawConnection '+Connection.Name);
                         End;
           End;
          Exit;
         //Break;
      End;
    End;
end;

procedure MD_Edit(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var SelHandle:TVSelHandle;
    Obj:TVObject;
    Callout:TVCallout;
    I,N:Longint;
Begin
     If (ssAlt in Shift) Then Begin //Box selection
       JustDrawing:=True; // needed for Rubber
       DisplayDebug;
       Exit;
     End;
     JustDrawing:=True; // needed for Rubber
     AllowMove:=False;
     UnderMouseDOWN.Free;
     UnderMouseDOWN:=Scene.BuildUnderMouse(CurrentXw,CurrentYw,SamePlaceZone);
     //Если на SelHandle?
     If MD_ProcessSelHandle Then Exit;
     //если опустили над выделенным - может быть будут нести или снимают выделение
     If UnderMouseDOWN.Count>0 Then
       For I:=0 To UnderMouseDOWN.Count-1 Do
         If Scene.SelectedList.IndexOf(UnderMouseDOWN[I]) >=0 Then Begin AllowMove:=True;Break;End;
     DisplayDebug;
     //если над невыделенным - изменяют выделение или скроллят
     //если над ничем - сбрасывают или скроллят
End;

procedure MD_Object(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin
    //Если на SelHandle?
    If MD_ProcessSelHandle Then Exit;
    UnselectAllBut('');
    Form1.CurrentEditingNameEdit.Text:='';
    JustDrawing:=True;
    DisplayDebug;
    MD_CommonRect;
End;

procedure MD_Connection(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var Obj:TVObject;  Port:TVPort;
    Connection:TVConnection;
    PortFound:Boolean;
    I,J,N,ObjCount:Longint;
    ObjName,PortName:String;
Begin
       UnderMouseDOWN.Free;
       UnderMouseDOWN:=Scene.BuildUnderMouse(CurrentXw,CurrentYw,SamePlaceZone);
       If UnderMouseDOWN.Count=0 Then Exit;
       ObjCount:=0;
       For I:=0 To UnderMouseDOWN.Count-1 Do
         If GetTypeByName(Scene,UnderMouseDOWN[I])='object' Then Begin
           Inc(ObjCount);
           ObjName:=UnderMouseDOWN[I];
         End;
       If ObjCount<>1 Then Begin
          If MD_ProcessSelHandle Then Begin
            Connection:=UnderMouseDOWN.Objects[0] As TVConnection;
            Unit1.Resizing:=True;
            RubberDisplayList.Add('DrawConnection '+Connection.Name);
            If Scene.SelectedList.IndexOf(Connection.Name)<0 Then
              Scene.SelectedList.AddObject(Connection.Name,Connection);
          //двигаем узел?
          End;
          Exit;
       end;
       N:=Scene.VObjectList.IndexOf(ObjName);
       Obj:=Scene.VObjectList.Objects[N] As TVObject;
       SourceObj:=Obj;SourcePort:=Nil;
         If (Form1.AutoButton.Down) And (Form1.AutoCreatePortSpeedButton.Down) Then Begin
            //авторежим - создаем порты автоматом
           If Not PortFound Then Begin
             PortName:=CreateObjectPort(Obj.Name,
                  'X='+FloatToStr((SelectX1w-Obj.Shell.X1)/(Obj.Shell.X2-Obj.Shell.X1))+
                 ' Y='+FloatToStr((SelectY1w-Obj.Shell.Y1)/(Obj.Shell.Y2-Obj.Shell.Y1)));
             N:=Obj.PortList.IndexOf(PortName);
             If N>=0 Then Port:=Obj.PortList.Objects[N] As TVPort;
             PortFound:=True;
           End;
         end;
         //здесь надо уточнить порт или весь объект
         PortFound:=False;
         If Obj.PortList.Count>0 Then
           For J:=0 To Obj.PortList.Count-1 Do Begin
             Port:=Obj.PortList.Objects[J] As TVPort;
             If (Abs(CurrentXNGw-Port.AX)<=PortHandleZone*Drawer.ViewScale) and (Abs(CurrentYNGw-Port.AY)<=PortHandleZone*Drawer.ViewScale)
             Then Begin
               PortFound:=True; Break;
             End;
           End;
         If (Not PortFound) And ((Form1.AutoButton.Down) Or (Form1.AutoCreatePortSpeedButton.Down)) then Begin
            //авторежим - создаем порты автоматом
            PortFound:=True;
            SourceObj:=Obj;SourcePort:=Nil;
         end Else Begin
         //резиновую линию от первого объекта
           If PortFound Then Begin
             SelectX1w:=Port.AX;SelectY1w:=Port.AY;
             SourceObj:=Obj;SourcePort:=Port;
             //если порт уже занят - надо отсоединить от него связь
             If Port.Connection='' Then Begin
               MovingConnectionPort:=False;
             end else MovingConnectionPort:=True;
           End Else Begin
             SelectX1w:=Obj.X;SelectY1w:=Obj.Y;
             SourceObj:=Obj;SourcePort:=Nil;
           End;
         end;
         RubberDisplayList.Clear;
         Drawer.WtoS(SelectX1w,SelectY1w,SelectX1s,SelectY1s);
         LastXs:=SelectX1s;LastYs:=SelectY1s;
         LastXw:=SelectX1w;LastYw:=SelectY1w;
         WCanvas.MoveTo(SelectX1s,SelectY1s);
         Drawing:=True;
         JustDrawing:=True;
         DisplayDebug;
End;

procedure MD_Callout(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin
 //Если на SelHandle?
 If MD_ProcessSelHandle Then Exit;
 UnselectAllBut('');
 Form1.CurrentEditingNameEdit.Text:='';
 JustDrawing:=True;
 DisplayDebug;
 MD_CommonRect;
End;

procedure MD_Curl_Pen(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var Curl:TVCurl;
    PrimitiveName:String;
Begin
    Drawing:=True;
    JustDrawing:=True;
    WCanvas.Pen.Color:=Form1.BorderColorButton.ButtonColor;
    If Form1.SnapToGridButton.Down Then Begin //надо ли огрублять до сетки рисование карандашом?
      SelectX1s:=CurrentXGs;SelectY1s:=CurrentYGs;
      SelectX1w:=CurrentXGw;SelectY1w:=CurrentYGw;
    end Else Begin
      SelectX1s:=CurrentXs;SelectY1s:=CurrentYs;
      SelectX1w:=CurrentXw;SelectY1w:=CurrentYw;
    End;
    WCanvas.MoveTo(SelectX1s,SelectY1s);
    Curl:=TVCurl.Create;
    Curl.Saveable:=True;
    PrimitiveName:=GetNewName(Scene,Scene.VCurlList,'pen');
    Scene.VCurlList.AddObject(PrimitiveName,Curl);
    Curl.Name:=PrimitiveName;
    Scene.View.Add('DrawCurl '+PrimitiveName);
    Dispatcher.ExecCommand('self::CAD_Scene2GUI');
End;

procedure MD_Curl_Label(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var Curl:TVCurl;
    PrimitiveName,BIUS:String;
    AccObject:TAccObject;

Begin
//  If (EditMode='curl text') Or (EditMode='curl scaledtext') Then Begin
    If Drawing Then Begin
      //hide label edit handle
      Curl:=TVCurl.Create;
      Curl.Saveable:=True;
      PrimitiveName:=GetNewName(Scene,Scene.VCurlList,'text');
      Scene.VCurlList.AddObject(PrimitiveName,Curl);
      Curl.Name:=PrimitiveName;
      Form1.CurrentEditingNameEdit.Text:=PrimitiveName;
      Form1.CurrentEditingNameEdit.Enabled:=True;
      Scene.View.Add('DrawCurl '+PrimitiveName);
      Form1.TLabelEdit.Hide;
      Drawing:=False;
      SelectX1s:=Form1.TLabelEdit.Left;
      SelectY1s:=Form1.TLabelEdit.Top;
      BIUS:='';
      If fsBold in Form1.FontDialog.Font.Style Then BIUS:=BIUS+'b';
      If fsItalic in Form1.FontDialog.Font.Style Then BIUS:=BIUS+'i';
      If fsUnderline in Form1.FontDialog.Font.Style Then BIUS:=BIUS+'u';
      If fsStrikeOut in Form1.FontDialog.Font.Style Then BIUS:=BIUS+'s';
      AccObject:=TAccObject.Create;
      AccObject.AcceleratedCommand:=AccelerateCommand('SetFont '+Form1.FontDialog.Font.Name+','+IntToStr(Form1.FontDialog.Font.Size)+','+ColorToString(Form1.FontDialog.Font.Color)+','+bius);
      Curl.DisplayList.AddObject('SetFont '+Form1.FontDialog.Font.Name+','+IntToStr(Form1.FontDialog.Font.Size)+','+ColorToString(Form1.FontDialog.Font.Color)+','+bius,AccObject);
      If Form1.TransparentBGCheckBox.Checked Then Begin
         AccObject:=TAccObject.Create;
         AccObject.AcceleratedCommand:=AccelerateCommand('SetBGColor clNone');
         Curl.DisplayList.AddObject('SetBGColor clNone',AccObject);
      end Else Begin
         AccObject:=TAccObject.Create;
         AccObject.AcceleratedCommand:=AccelerateCommand('SetBGColor '+ColorToString(Form1.PeekBGColorButton.ButtonColor));
         Curl.DisplayList.AddObject('SetBGColor '+ColorToString(Form1.PeekBGColorButton.ButtonColor),AccObject);
      end;
         AccObject:=TAccObject.Create;
         AccObject.AcceleratedCommand:=AccelerateCommand('TextOut '+FloatToStr(CurrentXw)+','+FloatToStr(CurrentYw)+','+Form1.TLabelEdit.Caption);
         Curl.DisplayList.AddObject('TextOut '+FloatToStr(CurrentXw)+','+FloatToStr(currentYw)+','+Form1.TLabelEdit.Caption+#10+'sdcdscds',AccObject);
         Dispatcher.ExecCommand('self::CAD_Scene2GUI');
    end Else Begin
      //Show Label Edit handle
      If Form1.SnapToGridButton.Down Then Begin
        SelectX1s:=CurrentXGs;
        SelectY1s:=CurrentYGs;
        SelectX1w:=CurrentXGw;
        SelectY1w:=CurrentYGw;
      end Else Begin
        SelectX1s:=CurrentXs;
        SelectY1s:=CurrentYs;
        SelectX1w:=CurrentXw;
        SelectY1w:=CurrentYw;
      end;
      Form1.FontDialog.Font.Name:=Form1.FontComboBox.Font.Name;
      Form1.FontDialog.Font.Size:=Form1.FontSizeEdit.Value;
      Form1.FontDialog.Font.Color:=Form1.PeekFontFaceColorButton.ButtonColor;
      Form1.TLabelEdit.Font:=Form1.FontDialog.Font;
//      TLabelEdit.AutoSize:=True;
      Form1.TLabelEdit.BorderStyle:=bsNone;
      Form1.TLabelEdit.BorderWidth:=0;
      Form1.TLabelEdit.AdjustSize;
      Form1.TLabelEdit.Left:=SelectX1s;
      Form1.TLabelEdit.Top:=SelectY1s;

      Form1.TLabelEdit.Show;
      Form1.TLabelEdit.Text:='';
      Form1.TLabelEdit.SetFocus;
      Drawing:=True;
    End;
End;

procedure MD_Curl_MultiLine(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin

End;

procedure MD_Curl_Line(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin
    //   JustDrawing:=True;
       Exit;
End;

procedure MD_Curl_Rect(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin
  MD_CommonRect;
End;

procedure MD_Curl_RRect(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin
  MD_CommonRect;
End;

procedure MD_Curl_Ellipse(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin
  MD_CommonRect;
End;

procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var Curl:TVCurl;TName,CName,OName,BIUS,Selection:String;
    Obj:TVObject;Port:TVPort;Templ:TVTemplate;
    Callout:TVCallout;
    Xw,Yw,Xw0,Yw0:Extended;Xg,Yg,N,BaseN:Longint;
    AccObject:TAccObject;
    Sm,Rm,Scm,tmpm,TransM:TMatrix2D;
    I,J,K:Longint;PortFound:Boolean;
    ActiveObject:Boolean;
    SelHandle:TVSelHandle;
    PrimitiveName:String;
begin
  If Form1.Active Then DrawingPanel.SetFocus;
  InitScalerY:=Y;
  InitScale:=ViewScaleEdit.Value;
  CurrentXs:=X+Image1.Left;
  CurrentYs:=Y+Image1.Top;
  Drawer.StoW(CurrentXs,CurrentYs,CurrentXw,CurrentYw);
  CurrentXGw:=GridGapEdit.Value*Round(CurrentXw/GridGapEdit.Value);
  CurrentYGw:=GridGapEdit.Value*Round(CurrentYw/GridGapEdit.Value);
  Drawer.WtoS(CurrentXGw,CurrentYGw,CurrentXGs,CurrentYGs);
  If SnapToGridButton.Down Then Begin
    XcoordLabel.Caption:=FloatToStrF(CurrentXGw,ffGeneral,12,6)+'('+FloatToStr(CurrentXGw/GridGapEdit.Value)+')';
    YcoordLabel.Caption:=FloatToStrF(CurrentYGw,ffGeneral,12,6)+'('+FloatToStr(CurrentYGw/GridGapEdit.Value)+')';
    SelectX1s:=CurrentXGs;SelectY1s:=CurrentYGs;
    SelectX1w:=CurrentXGw;SelectY1w:=CurrentYGw;
  end Else Begin
    XcoordLabel.Caption:=FloatToStrF(CurrentXw,ffGeneral,12,6);
    YcoordLabel.Caption:=FloatToStrF(CurrentYw,ffGeneral,12,6);
    SelectX1s:=CurrentXs;SelectY1s:=CurrentYs;
    SelectX1w:=CurrentXw;SelectY1w:=CurrentYw;
  end;
  SelectX1NGw:=CurrentXw;
  SelectY1NGw:=CurrentYw;

  ClickNotDrag:=True;
  If HintLabel.Caption<>'' Then HintLabel.Hide;

  Case EditMode Of
  'navigation':    Begin MD_Navigation(Button,Shift,X,Y);End;
  'control':       Begin MD_Control(Button,Shift,X,Y);End;
  '','edit':       Begin MD_Edit(Button,Shift,X,Y);End;
  'object':        Begin MD_Object(Button,Shift,X,Y);End;
  'connection':    Begin MD_Connection(Button,Shift,X,Y);End;
  'callout':       Begin MD_Callout(Button,Shift,X,Y);End;
  'curl pen':      Begin MD_Curl_Pen(Button,Shift,X,Y);End;
  'curl label':    Begin MD_Curl_Label(Button,Shift,X,Y);End;
  'curl multiline':Begin MD_Curl_Multiline(Button,Shift,X,Y);End;
  'curl line':     Begin MD_Curl_Line(Button,Shift,X,Y);End;
  'curl rect':     Begin MD_Curl_Rect(Button,Shift,X,Y);End;
  'curl rrect':    Begin MD_Curl_RRect(Button,Shift,X,Y);End;
  'curl ellipse':  Begin MD_Curl_Ellipse(Button,Shift,X,Y);End;
  End;

end;

Procedure MM_ProcessHint;
Var ItemsUnder:TStringList;
    Selection:String;
    Obj:TVObject;
    Conn:TVConnection;
    Port:TVPort;
    I,J,Xs,Ys:Longint;
Begin
  Selection:='';
  If (EditMode='object') And (Form1.ObjStyleRadioGroup.ItemIndex=0) Then Exit;
  ItemsUnder:=Scene.BuildUnderMouse(CurrentXNGw,CurrentYNGw,SamePlaceZone);
  If ItemsUnder.Count>0 Then Begin
    For I:=0 To ItemsUnder.Count-1 Do Begin
      Case GetTypeByName(Scene,ItemsUnder[I]) of
      'curl':  If Form1.SearchFilterCurlSpeedButton.Down Then Selection:=Selection+#13#10+ItemsUnder[I];
      'object': Begin
                  If not Form1.SearchFilterObjectSpeedButton.Down Then Exit;
                  Selection:=Selection+#13#10+ItemsUnder[I];
                  Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(ItemsUnder[I])] As TVObject;
                  If Obj.PortList.Count>0 Then
                    For J:=0 To Obj.PortList.Count-1 Do Begin
                      Port:=Obj.PortList.Objects[J] As TVPort;
                      Scene.Drawer.WtoS(Port.AX,Port.AY,Xs,Ys);
                      If Abs(CurrentXs-Xs)+Abs(CurrentYs-Ys)<=SamePlaceZone Then Begin
                        Selection:=Selection+#13#10+Obj.Name+':'+Port.Name;
                      end;
                    end;
                 end;
      'callout': If Form1.SearchFilterCalloutSpeedButton.Down Then Selection:=Selection+#13#10+ItemsUnder[I];
      'connection': Begin
                      If Not Form1.SearchFilterConnSpeedButton.Down Then Exit;
                      Case SettingsForm.ConnNameDisplayStyleComboBox.ItemIndex of
                      0: Selection:=Selection+#13#10+ItemsUnder[I];
                      1: Begin
            Conn:=Scene.VConnectionList.Objects[Scene.VConnectionList.IndexOf(ItemsUnder[I])] As TVConnection;
            Selection:=Selection+#13#10+Conn.StartObj+'<->'+Conn.EndObj;
                           end;
                      2: Begin
            Conn:=Scene.VConnectionList.Objects[Scene.VConnectionList.IndexOf(ItemsUnder[I])] As TVConnection;
            Selection:=Selection+#13#10+Conn.StartObj+':'+Conn.StartPort+'<->'+Conn.EndObj+':'+Conn.EndPort;
                           end;
                      3: Begin
            Conn:=Scene.VConnectionList.Objects[Scene.VConnectionList.IndexOf(ItemsUnder[I])] As TVConnection;
            Selection:=Selection+#13#10+ItemsUnder[I]+' ('+Conn.StartObj+'<->'+Conn.EndObj+')';
                           end;
                      end;
                    end;
      end;
    end;
    Form1.HintLabel.Left:=CurrentXs+15;
    Form1.HintLabel.Top:=CurrentYs+15;
    Form1.HintLabel.Font.Bold:=True;
    Form1.HintLabel.Caption:=Selection;
    Form1.HintLabel.Show;
  end Else Begin
    Form1.HintLabel.Hide;
  end;
  ItemsUnder.Free;
End;

Procedure MoveSelectionTo(X,Y:Extended);
Var I:Longint;
    Obj:TVObject;
    Callout:TVCallout;
    BaseX,BaseY,Dx,Dy:Extended;
Begin
  If Scene.SelectedList.Count=0 Then Exit;
    Case GetTypeByName(Scene,Scene.SelectedList[0]) Of
    'curl': Begin End;
    'object': Begin Obj:=Scene.SelectedList.Objects[0] As TVObject;
                    BaseX:=Obj.X; BaseY:=Obj.Y;
              End;
    'callout': Begin Callout:=Scene.SelectedList.Objects[0] As TVCallout;
                    BaseX:=Callout.X; BaseY:=Callout.Y;
               End;
    'connection': Begin End;
    end;
  For I:=0 To Scene.SelectedList.Count-1 Do Begin
    Case GetTypeByName(Scene,Scene.SelectedList[I]) Of
    'curl': Begin End;
    'object': Begin Obj:=Scene.SelectedList.Objects[I] As TVObject;
                    Dx:=Obj.X-BaseX;
                    Dy:=Obj.Y-BaseY;
                    Scene.MoveObjectTo(Obj,X+Dx,Y+Dy,'');
                    Scene.UpdateSelHandles(Obj.Name);
              End;
    'callout': Begin Callout:=Scene.SelectedList.Objects[I] As TVCallout;
                    Dx:=Callout.X-BaseX;
                    Dy:=Callout.Y-BaseY;
                    Scene.MoveCalloutTo(Callout,X+Dx,Y+Dy,'');
                    Scene.UpdateSelHandles(Callout.Name);
               End;
    'connection': Begin End;
    end;
  end;
  Scene.UpdateVisibility;
  RepaintView;
end;

Procedure AddConnectionNodeAt(Connection:TVConnection;Xs,Ys:Longint);
Var Port,Port1,Port2:TVConnectionPort;AccObject:TAccObject;
    ObjName:String;
    I,J,N,X1s,Y1s,X2s,Y2s:Longint;
    Xw,Yw:Extended;
    ProceedWithNewNode:Boolean;
Begin
  ProceedWithNewNode:=False;
  // уточненная проверка поотрезочно
  If Connection.PortList.Count>1 Then Begin
    Port1:=Connection.PortList.Objects[0] As TVConnectionPort;
    Drawer.WToS(Port1.AX,Port1.AY,x1s,y1s);
    For J:=1 To Connection.PortList.Count-1 Do Begin
      Port2:=Connection.PortList.Objects[J] As TVConnectionPort;
      Drawer.WToS(Port2.AX,Port2.AY,x2s,y2s);
      If Abs(x1s-x2s)<=SamePlaceZone Then Begin
        //вырожденный случай - вертикальная линия
        If ((Abs(Xs-x1s)<=SamePlaceZone)Or((Abs(Xs-x2s)<=SamePlaceZone))) And
           ( ((y1s<=Ys)And(Ys<=y2s))
             Or
             (y1s<=Ys)And(Ys<=y2s))
           Then Begin //ставим новый порт на отрезке
             ProceedWithNewNode:=True;
             Break;
           End;
      End Else Begin
    //    If Abs((SelectY2s-y1s)-(SelectX2s-x1s)*(y2s-y1s)/(x2s-x1s))<=SamePlaceZone Then Begin
        If (Abs((Ys-y1s)-(Xs-x1s)*(y2s-y1s)/(x2s-x1s))<=SamePlaceZone)
           And
           (((Xs>=x1s) And (Xs<=x2s))Or((Xs>=x2s) And (Xs<=x1s)))



        Then Begin
          //ставим новый порт на отрезке
          ProceedWithNewNode:=True;
          Break;
        end;
      End;
      Port1:=Port2;
      x1s:=x2s;y1s:=y2s;
    end;
  end;
  If Not ProceedWithNewNode Then Exit;
  Scene.Drawer.StoW(Xs,Ys,Xw,Yw);
  Port:=TVConnectionPort.Create;
  Port.PortType:='Node';
{  Port.AR:='R';
  Port.X:=(SelectX1w-Conn.Shell.X1)/(Conn.Shell.X2-Conn.Shell.X1);
  Port.Y:=(SelectY1w-Conn.Shell.Y1)/(Conn.Shell.Y2-Conn.Shell.Y1);}
  Port.AR:='A';
  Port.AX:=Xw;
  Port.AY:=Yw;
  Connection.PortList.InsertObject(J,'',Port);
  PrepareConnectionPropEdit(Connection);
  Scene.UpdateConnectionDisplayList(Connection);
  Scene.CreateSelHandles(Connection.Name);

//  If Conn.PortList.Count<ConnPortStringGrid.RowCount-1 Then Begin
{    AccObject:=TAccObject.Create;
    AccObject.AcceleratedCommand:=AccelerateCommand('UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone));
    Obj.DisplayList.AddObject('UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone),AccObject);}
    Scene.ExecCommand('DrawConnection '+Connection.Name,ZeroAcc,0);
    Drawer.Updated:=True;
    RepaintView;
//  End;
End;

Function MM_ProcessMoving(Shift: TShiftState; X, Y: Integer):Boolean;
Var I:Longint;
    Obj:TVObject;
    Callout:TVCallout;
    NewX,NewY:Extended;
Begin
  Result:=False;
  If (ssLeft in Shift) And JustDrawing And (Not ClickNotDrag) And AllowMove Then Begin
    For I:=0 To Scene.SelectedList.Count-1 Do Begin
      Case GetTypeByName(Scene,Scene.SelectedList[I]) Of
      'curl': RubberDisplayList.Add('DrawCurl '+Scene.SelectedList[I]);
      'object': RubberDisplayList.Add('DrawObject '+Scene.SelectedList[I]);
      'callout': RubberDisplayList.Add('DrawCallout '+Scene.SelectedList[I]);
      'connection': RubberDisplayList.Add('DrawConnection '+Scene.SelectedList[I]);
      end;
    End;
    Form1.HintLabel.Hide;
    DrawRubber;
    Moving:=True;
    LockBackUpdate:=False;
    JustDrawing:=False;
    Result:=True;
  end;
  If Moving Then Begin
      If RubberDisplayList.Count>0 Then Begin
        DrawRubber;
        For I:=0 To Scene.SelectedList.Count-1 Do Begin
          Case GetTypeByName(Scene,Scene.SelectedList[I]) Of
          'curl': Begin End;
          'object': Begin Obj:=Scene.SelectedList.Objects[I] As TVObject;
                          NewX:=Obj.X+CurrentXw-SelectX1w;
                          NewY:=Obj.Y+CurrentYw-SelectY1w;
                          Scene.MoveObjectTo(Obj,NewX,NewY,'');
                       //   UpdateSelHandles(Obj.Name);
                          If Scene.SelectedList.Count=1 Then Begin
                            LockBackUpdate:=True;
                            Form1.XEdit.Value:=Obj.X;
                            Form1.YEdit.Value:=Obj.Y;
                            Form1.LX1Edit.Value:=Obj.X;
                            Form1.LY1Edit.Value:=Obj.Y;
                            If Obj.Template='' Then  Begin
                              Form1.LX2Edit.Value:=Obj.X+Obj.W;
                              Form1.LY2Edit.Value:=Obj.Y+Obj.H;
                            End;
                         //   LockBackUpdate:=False;
                          End;
                    End;
          'callout': Begin Callout:=Scene.SelectedList.Objects[I] As TVCallout;
                           NewX:=Callout.X+CurrentXw-SelectX1w;
                           NewY:=Callout.Y+CurrentYw-SelectY1w;
                           Scene.MoveCalloutTo(Callout,NewX,NewY,'');
                           Scene.UpdateSelHandles(Callout.Name);
                           //RepaintView надо делать после этого
                           If Scene.SelectedList.Count=1 Then Begin
                             LockBackUpdate:=True;
                             Form1.LX1Edit.Value:=Callout.X;
                             Form1.LX2Edit.Value:=Callout.X+Callout.W;
                             Form1.LY1Edit.Value:=Callout.Y;
                             Form1.LY2Edit.Value:=Callout.Y-Callout.H;
                             LockBackUpdate:=False;
                           End;
                    End;
          'connection': Begin End;
          end;
        end;
        SelectX1w:=CurrentXw;
        SelectY1w:=CurrentYw;
        DrawRubber;
      End;
      Result:=True;
  End;
  DisplayDebug;
end;

Function MM_ProcessResizing(Shift: TShiftState; X, Y: Integer):Boolean;
Var I,J,ModCommandNumber:Longint;
    Obj:TVObject;
    Callout:TVCallout;
    Connection:TVConnection;
    NewX,NewY:Extended;
    Buf,ParsedBuf,Cmd:String;
    Xw1s,Xw2s,Yw1s,Yw2s:String;
    Xw1,Yw1,Xw2,Yw2,XB:Extended;
    ConnPort:TVConnectionPort;
    Port:TVPort;
Begin
  Result:=False;
 // If JustDrawing then Exit;
  If Unit1.Resizing Then Begin
      If RubberDisplayList.Count>0 Then Begin
        DrawRubber;
        For I:=0 To Scene.SelectedList.Count-1 Do Begin
          Case GetTypeByName(Scene,Scene.SelectedList[I]) Of
          'curl': Begin End;
          'object': Begin Obj:=Scene.SelectedList.Objects[I] As TVObject;
                      If (Obj.A=720) Or (Obj.A=720+360) Or (Obj.A=720+2*360) Or (Obj.A=720+3*360) Or (Obj.A=720+4*360) Then Begin
                      // объект - фигура
                      LockBackUpdate:=True;
                      Case ActiveSelHandle.Style of
                      'LT': Begin
                                  Form1.LX1Edit.Value:=CurrentXw;
                                  Form1.LY2Edit.Value:=CurrentYw;
                            End;
                      'LB': Begin
                                  Form1.LX1Edit.Value:=CurrentXw;
                                  Form1.LY1Edit.Value:=CurrentYw;
                            End;
                      'RT': Begin
                                  Form1.LX2Edit.Value:=CurrentXw;
                                  Form1.LY2Edit.Value:=CurrentYw;
                            End;
                      'RB': Begin
                                  Form1.LX2Edit.Value:=CurrentXw;
                                  Form1.LY1Edit.Value:=CurrentYw;
                            End;
                      'MT': Begin
                                  Form1.LY2Edit.Value:=CurrentYw;
                            End;
                      'MB': Begin
                                  Form1.LY1Edit.Value:=CurrentYw;
                            End;
                      'LM': Begin
                                  Form1.LX1Edit.Value:=CurrentXw;
                            End;
                      'RM': Begin
                                  Form1.LX2Edit.Value:=CurrentXw;
                            End;
                      end;
                    end; //special objects
                    LockBackUpdate:=False;
                    If ActiveSelHandle.Style='Box' Then Begin
                      For J:=0 To Obj.PortList.Count-1 Do Begin
                        Port:=Obj.PortList.Objects[J] As TVPort;
                        If (Abs(Port.AX-ActiveSelHandle.Xw)+Abs(Port.AY-ActiveSelHandle.Yw))/Scene.Drawer.ViewScale<=SelHandleZone Then Begin
                          Port.AX:=CurrentXw;
                          Port.AY:=CurrentYw;
                          If Port.AX<Obj.Shell.X1 Then Obj.Shell.X1:=Port.AX;
                          If Port.AX>Obj.Shell.X2 Then Obj.Shell.X2:=Port.AX;
                          If Port.AY<Obj.Shell.Y1 Then Obj.Shell.Y1:=Port.AY;
                          If Port.AY>Obj.Shell.Y2 Then Obj.Shell.Y2:=Port.AY;
                          If Port.AR='R' Then Begin
                            Port.X:=(Port.AX-Obj.Shell.X1)/(Obj.Shell.X2-Obj.Shell.X1);
                            Port.Y:=(Port.AY-Obj.Shell.Y1)/(Obj.Shell.Y2-Obj.Shell.Y1);
                          End;
                          Scene.UpdateObjectDisplayList(Obj);
                          Scene.UpdateSelHandles(Obj.Name);
                        End;
                      End;
                    End;
                      ObjectGUI2Scene;
                      Scene.ObjectAttr2Style(Obj);
                      Scene.UpdateObjectDisplayList(Obj);
                      Scene.MoveObjectTo(Obj,Obj.X,Obj.Y,'');
                      Scene.UpdateSelHandles(Obj.Name);
{                      If Obj.RelatedCAList.Count>0 Then
                        For J:=0 To Obj.RelatedCAList.Count-1 Do Begin
                          Callout:=Obj.RelatedCAList.Objects[J] As TVCallout;
                          Scene.UpdateCalloutDisplayList(Callout);
                          UpdateSelHandles(Callout.Name);
                        End;}
                    End;
          'callout': Begin Callout:=Scene.SelectedList.Objects[I] As TVCallout;
                      If Form1.SnapToGridButton.Down Then Begin
                        NewX:=Form1.GridGapEdit.Value*Round(Callout.X/Form1.GridGapEdit.Value)+Form1.GridGapEdit.Value*Round((CurrentXw-SelectX1w)/Form1.GridGapEdit.Value);
                        NewY:=Form1.GridGapEdit.Value*Round(Callout.Y/Form1.GridGapEdit.Value)+Form1.GridGapEdit.Value*Round((CurrentYw-SelectY1w)/Form1.GridGapEdit.Value);
                      End Else Begin
                        NewX:=Callout.X+CurrentXw-SelectX1w;
                        NewY:=Callout.Y+CurrentYw-SelectY1w;
                      End;
                    {    Callout.X:=Min(Form1.LX1Edit.Value,Form1.LX2Edit.Value);
                        Callout.Y:=Max(Form1.LY1Edit.Value,Form1.LY2Edit.Value);
                        Callout.W:=Abs(Form1.LX2Edit.Value-Form1.LX1Edit.Value);
                        Callout.H:=Abs(Form1.LY2Edit.Value-Form1.LY1Edit.Value);}
                      LockBackUpdate:=True;
                      Case ActiveSelHandle.Style of
                      'LT': Begin Callout.X:=NewX;Callout.Y:=NewY;
                                  Callout.W:=Form1.GridGapEdit.Value*Round(Callout.W/Form1.GridGapEdit.Value)-Form1.GridGapEdit.Value*Round((CurrentXw-SelectX1w)/Form1.GridGapEdit.Value);
                                  Callout.H:=Form1.GridGapEdit.Value*Round(Callout.H/Form1.GridGapEdit.Value)+Form1.GridGapEdit.Value*Round((CurrentYw-SelectY1w)/Form1.GridGapEdit.Value);
                            End;
                      'LB': Begin Callout.X:=NewX;
                                  Callout.W:=Form1.GridGapEdit.Value*Round(Callout.W/Form1.GridGapEdit.Value)-Form1.GridGapEdit.Value*Round((CurrentXw-SelectX1w)/Form1.GridGapEdit.Value);
                                  Callout.H:=Form1.GridGapEdit.Value*Round(Callout.H/Form1.GridGapEdit.Value)-Form1.GridGapEdit.Value*Round((CurrentYw-SelectY1w)/Form1.GridGapEdit.Value);
                            End;
                      'RT': Begin Callout.Y:=NewY;
                                  Callout.W:=Form1.GridGapEdit.Value*Round(Callout.W/Form1.GridGapEdit.Value)+Form1.GridGapEdit.Value*Round((CurrentXw-SelectX1w)/Form1.GridGapEdit.Value);
                                  Callout.H:=Form1.GridGapEdit.Value*Round(Callout.H/Form1.GridGapEdit.Value)+Form1.GridGapEdit.Value*Round((CurrentYw-SelectY1w)/Form1.GridGapEdit.Value);
                            End;
                      'RB': Begin
                                  Callout.W:=Form1.GridGapEdit.Value*Round(Callout.W/Form1.GridGapEdit.Value)+Form1.GridGapEdit.Value*Round((CurrentXw-SelectX1w)/Form1.GridGapEdit.Value);
                                  Callout.H:=Form1.GridGapEdit.Value*Round(Callout.H/Form1.GridGapEdit.Value)-Form1.GridGapEdit.Value*Round((CurrentYw-SelectY1w)/Form1.GridGapEdit.Value);
                            End;
                      'MT': Begin Callout.Y:=NewY;
                                  Callout.H:=Form1.GridGapEdit.Value*Round(Callout.H/Form1.GridGapEdit.Value)+Form1.GridGapEdit.Value*Round((CurrentYw-SelectY1w)/Form1.GridGapEdit.Value);
                            End;
                      'MB': Begin Callout.H:=Form1.GridGapEdit.Value*Round(Callout.H/Form1.GridGapEdit.Value)-Form1.GridGapEdit.Value*Round((CurrentYw-SelectY1w)/Form1.GridGapEdit.Value);
                            End;
                      'LM': Begin Callout.X:=NewX;
                                  Callout.W:=Form1.GridGapEdit.Value*Round(Callout.W/Form1.GridGapEdit.Value)-Form1.GridGapEdit.Value*Round((CurrentXw-SelectX1w)/Form1.GridGapEdit.Value);
                            End;
                      'RM': Begin Callout.W:=Form1.GridGapEdit.Value*Round(Callout.W/Form1.GridGapEdit.Value)+Form1.GridGapEdit.Value*Round((CurrentXw-SelectX1w)/Form1.GridGapEdit.Value);
                            End;
                      end;
                      Form1.LX1Edit.Value:=Callout.X;
                      Form1.LX2Edit.Value:=Callout.X+Callout.W;
                      Form1.LY1Edit.Value:=Callout.Y;
                      Form1.LY2Edit.Value:=Callout.Y-Callout.H;
                      LockBackUpdate:=False;
                      CalloutGUI2Scene;
                      Scene.UpdateSelHandles(Callout.Name);
                    End;
          'connection': Begin
                      Connection:=Scene.SelectedList.Objects[I] As TVConnection;
                      LockBackUpdate:=True;
                      Case ActiveSelHandle.Style of
                      'Box': Begin
                               For J:=0 To Connection.PortList.Count-1 Do Begin;
                                 ConnPort:=Connection.PortList.Objects[J] As TVConnectionPort;
                                 If (ConnPort.PortType='Node')Or(ConnPort.PortType='Text') Then Begin
                                   If (Abs(ConnPort.AX-ActiveSelHandle.Xw)+Abs(ConnPort.AY-ActiveSelHandle.Yw))/Scene.Drawer.ViewScale<=SelHandleZone Then Begin
                                     ConnPort.AX:=CurrentXw;
                                     ConnPort.AY:=CurrentYw;
                                     If ConnPort.AX<Connection.Shell.X1 Then Connection.Shell.X1:=ConnPort.AX;
                                     If ConnPort.AX>Connection.Shell.X2 Then Connection.Shell.X2:=ConnPort.AX;
                                     If ConnPort.AY<Connection.Shell.Y1 Then Connection.Shell.Y1:=ConnPort.AY;
                                     If ConnPort.AY>Connection.Shell.Y2 Then Connection.Shell.Y2:=ConnPort.AY;

                                     If ConnPort.AR='R' Then Begin
                                       ConnPort.X:=(ConnPort.AX-Connection.Shell.X1)/(Connection.Shell.X2-Connection.Shell.X1);
                                       ConnPort.Y:=(ConnPort.AY-Connection.Shell.Y1)/(Connection.Shell.Y2-Connection.Shell.Y1);
                                     End;
                                     Scene.UpdateConnectionDisplayList(Connection);
                                     Scene.UpdateSelHandles(Connection.Name);
                                   End;
                                 End;
                               End;
                             End;
                      End;
                      Scene.UpdateSelHandles(Connection.Name);
                    End;
          end;
        end;
        SelectX1w:=CurrentXw;
        SelectY1w:=CurrentYw;
        DrawRubber;
      End;
    Result:=True;
  End;
  displayDebug;
end;

Procedure MM_ProcessSetCursorType;
Var SelHandle:TVSelHandle;
    I:Longint;
    CursorTypeIsSet:Boolean;
Begin
CursorTypeIsSet:=False;
If Scene.VHandleList.Count>0 Then
  For I:=0 To Scene.VHandleList.Count-1 Do Begin
    SelHandle:=Scene.VHandleList.Objects[I] As TVSelHandle;
    If Abs(SelHandle.X-CurrentXs)+Abs(SelHandle.Y-CurrentYs)<=SelHandleZone Then Begin
      CursorTypeIsSet:=True;
      Case SelHandle.Style Of
      'Box': Form1.Image1.Cursor:=crCross;
      'LT': Form1.Image1.Cursor:=crSizeNW;
      'RB': Form1.Image1.Cursor:=crSizeSE;
      'MT','MB': Form1.Image1.Cursor:=crSizeNS;
      'LM','RM': Form1.Image1.Cursor:=crSizeWE;
      'RT': Form1.Image1.Cursor:=crSizeNE;
      'LB': Form1.Image1.Cursor:=crSizeSW;
      End;
      Break;
    end;
  end;
If Not CursorTypeIsSet Then Form1.Image1.Cursor:=crDefault;
End;

procedure MM_Navigation(Shift: TShiftState; X, Y: Integer);
Var ItemsUnder:TStringList;
    Selection:String;
Begin
  If not(ssLeft in Shift) Then MM_ProcessHint;
End;

procedure MM_Control(Shift: TShiftState; X, Y: Integer);
Begin
  If not(ssLeft in Shift) Then MM_ProcessHint;
End;

procedure MM_Edit(Shift: TShiftState; X, Y: Integer);
Begin
  If (ssAlt in Shift)And(ssLeft in Shift) Then Begin //Box selection
    If Not JustDrawing Then
      If RubberDisplayList.Count>0 Then DrawRubber;
    JustDrawing:=False;
    SelectX2s:=CurrentXs;
    SelectY2s:=CurrentYs;
    SelRect.Left:=Min(SelectX1s,SelectX2s);
    SelRect.Top:=Min(SelectY1s,SelectY2s);
    SelRect.Right:=Max(SelectX1s,SelectX2s);
    SelRect.Bottom:=Max(SelectY1s,SelectY2s);
    RubberDisplayList.Clear;
    RubberDisplayList.Add('SetColor '+ColorToString(clRed));
    RubberDisplayList.Add('SetBGColor '+ColorToString(clNone));
    RubberDisplayList.Add('SetWidth 2');
    RubberDisplayList.Add('Rect '+FloatToStr(SelectX1NGw)+','+FloatToStr(SelectY1NGw)+','+FloatToStr(CurrentXNGw)+','+FloatToStr(CurrentYNGw));
    DrawRubber;
    DisplayDebug;
    Exit;
  End;

  If Not ((ssLeft in Shift) or Moving or Unit1.Resizing) Then MM_ProcessHint;
  //движение резинового объекта
  If MM_ProcessMoving(Shift,X,Y) Then Exit;
  If MM_ProcessResizing(Shift,X,Y) Then Exit;
  //Handle cursor надо ли менять курсор?
  //если мы в режиме редактирование и рисования - да, в режиме навигации - нет
  MM_ProcessSetCursorType;
End;

Procedure MM_Common;
Var dx,dy,Fi,L:Extended;
Begin
  If Not Drawing then Exit;
      WCanvas.Pen.Mode:=pmnotXOR;
      WCanvas.Pen.Style:=psDot;
      WCanvas.Pen.Color:=Form1.BorderColorButton.ButtonColor;
      WCanvas.Pen.Width:=Form1.WidthButton1.Tag;
      WCanvas.Brush.Color:=Form1.BGColorButton.ButtonColor;
      If EditMode='curl rect' Then
        WCanvas.Rectangle(SelectX1s,SelectY1s,LastXs,LastYs);
      If EditMode='curl rrect' Then
        WCanvas.RoundRect(SelectX1s,SelectY1s,LastXs,LastYs,20,20);
      If EditMode='curl ellipse' Then
        WCanvas.Ellipse(SelectX1s,SelectY1s,LastXs,LastYs);
      If EditMode='callout' Then
        WCanvas.Rectangle(SelectX1s,SelectY1s,LastXs,LastYs);
      If EditMode='object' Then
        Case Form1.ObjStyleRadioGroup.ItemIndex Of
        2,5,6: WCanvas.Rectangle(SelectX1s,SelectY1s,LastXs,LastYs);
        3: WCanvas.RoundRect(SelectX1s,SelectY1s,LastXs,LastYs,20,20);
        4: WCanvas.Ellipse(SelectX1s,SelectY1s,LastXs,LastYs);
        end;
      If Form1.SnapToGridButton.Down Then Begin
        SelectX2s:=CurrentXGs;SelectY2s:=CurrentYGs;
        SelectX2w:=CurrentXGw;SelectY2w:=CurrentYGw;
      end Else Begin
        SelectX2s:=CurrentXs;SelectY1s:=CurrentYs;
        SelectX2w:=CurrentXw;SelectY1w:=CurrentYw;
      End;

      UpdateFrom:=updGUI;
      Form1.LX2Edit.Value:=SelectX2w;
      Form1.LY2Edit.Value:=SelectY2w;
      dx:=SelectX2w-SelectX1w;dy:=SelectY2w-SelectY1w;
      Form1.LdXEdit.Value:=dX;
      Form1.LdYEdit.Value:=dY;
      If Form1.SnapToGridButton.Down Then Begin
        Form1.LX2GEdit.Value:=Round(SelectX2w/Form1.GridGapEdit.Value);
        Form1.LY2GEdit.Value:=Round(SelectY2w/Form1.GridGapEdit.Value);
        Form1.LdXGEdit.Value:=Round(dX/Form1.GridGapEdit.Value);
        Form1.LdYGEdit.Value:=Round(dY/Form1.GridGapEdit.Value);
      end;
      L:=Sqrt(Sqr(dx)+Sqr(dy));
      Fi:=ComputeFi(dx,dy);
      Form1.LLEdit.Value:=L;
      Form1.LFiEdit.Value:=Fi/pi*180;
      LastXs:=SelectX2s;LastYs:=SelectY2s;
      LastXw:=SelectX2w;LastYw:=SelectY2w;
      If EditMode='curl rect' Then
        WCanvas.Rectangle(SelectX1s,SelectY1s,LastXs,LastYs);
      If EditMode='curl rrect' Then
        WCanvas.RoundRect(SelectX1s,SelectY1s,LastXs,LastYs,20,20);
      If EditMode='curl ellipse' Then
        WCanvas.Ellipse(SelectX1s,SelectY1s,LastXs,LastYs);
      If EditMode='callout' Then
        WCanvas.Rectangle(SelectX1s,SelectY1s,LastXs,LastYs);
      If EditMode='object' Then
        Case Form1.ObjStyleRadioGroup.ItemIndex Of
        2,5,6: WCanvas.Rectangle(SelectX1s,SelectY1s,LastXs,LastYs);
        3: WCanvas.RoundRect(SelectX1s,SelectY1s,LastXs,LastYs,20,20);
        4: WCanvas.Ellipse(SelectX1s,SelectY1s,LastXs,LastYs);
        end;
end;

procedure MM_Object(Shift: TShiftState; X, Y: Integer);
Var I:Longint;
    RubberCmd,TemplName:String;
Begin
   If Not ((ssLeft in Shift) Or Moving or Unit1.Resizing) Then MM_ProcessHint;
    //движение резинового объекта
    MM_ProcessSetCursorType;
    MM_ProcessMoving(Shift,X,Y);
    If MM_ProcessResizing(Shift,X,Y) Then Exit;
    //Handle cursor надо ли менять курсор?
    //если мы в режиме редактирование и рисования - да, в режиме навигации - нет
    LockBackUpdate:=True;
    If (ssLeft in Shift) Then Begin
      If JustDrawing And (Not ClickNotDrag) And (RubberDisplayList.Count=0) Then Begin
        // самое начало рисования - набираем резину
        RubberDisplayList.Add('SetColor '+ColorToString(Form1.BorderColorButton.ButtonColor));
        RubberDisplayList.Add('SetBGColor '+ColorToString(Form1.BGColorButton.ButtonColor));
        RubberDisplayList.Add('SetWidth '+IntToStr(Form1.WidthButton1.Tag));
        Case Form1.ObjStyleRadioGroup.ItemIndex Of
        2: RubberCmd:='Rect '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w)+','+FloatToStr(CurrentXw)+','+FloatToStr(CurrentYw);
        3: RubberCmd:='RoundRect '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w)+','+FloatToStr(CurrentXw)+','+FloatToStr(CurrentYw);
        4: RubberCmd:='Ellipse '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w)+','+FloatToStr(CurrentXw)+','+FloatToStr(CurrentYw);
        5,6: RubberCmd:='Rect '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w)+','+FloatToStr(CurrentXw)+','+FloatToStr(CurrentYw);
        End;
        RubberDisplayList.Add(RubberCmd);
        Scene.ExecCommand(RubberDisplayList[0],ZeroAcc,0);
        Form1.CurrentEditingNameEdit.Text:='';
        JustDrawing:=False;
        Drawing:=True;
      End;DrawRubber;
      RubberDisplayList.Clear;
      RubberDisplayList.Add('SetColor '+ColorToString(Form1.BorderColorButton.ButtonColor));
      RubberDisplayList.Add('SetBGColor '+ColorToString(Form1.BGColorButton.ButtonColor));
      RubberDisplayList.Add('SetWidth '+IntToStr(Form1.WidthButton1.Tag));
      Case Form1.ObjStyleRadioGroup.ItemIndex Of
      2: RubberCmd:='Rect '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w)+','+FloatToStr(CurrentXw)+','+FloatToStr(CurrentYw);
      3: RubberCmd:='RoundRect '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w)+','+FloatToStr(CurrentXw)+','+FloatToStr(CurrentYw);
      4: RubberCmd:='Ellipse '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w)+','+FloatToStr(CurrentXw)+','+FloatToStr(CurrentYw);
      5,6: RubberCmd:='Rect '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w)+','+FloatToStr(CurrentXw)+','+FloatToStr(CurrentYw);
      End;
      RubberDisplayList.Add(RubberCmd);
      If RubberDisplayList.Count>0 Then Begin
        DrawRubber;
      End;

      Form1.XEdit.Value:=SelectX1w;
      Form1.YEdit.Value:=SelectY1w;
      Form1.LX1Edit.Value:=SelectX1w;
      Form1.LX2Edit.Value:=CurrentXw;
      Form1.LY1Edit.Value:=SelectY1w;
      Form1.LY2Edit.Value:=CurrentYw;
    End;
    //Templated object
    If Not (ssLeft in Shift) And (Form1.ObjStyleRadioGroup.ItemIndex=0) Then Begin
      If JustDrawing Then Begin
        //самое начало - набираем резину
        Form1.XEdit.Value:=CurrentXw;
        Form1.YEdit.Value:=CurrentYw;
        RubberDisplayList.Clear;
        TemplName:=Copy(ExtractFileName(Form1.LibraryShellTreeView.Path),1,Length(ExtractFileName(Form1.LibraryShellTreeView.Path))-Length(ExtractFileExt(Form1.LibraryShellTreeView.Path)));
        RubberDisplayList.Add('DrawTemplate '+TemplName+' '+Form1.XEdit.Text+','+Form1.YEdit.Text+','+Form1.AEdit.Text+','+Form1.SEdit.Text);
        Form1.HintLabel.Hide;
        JustDrawing:=False;
        DrawRubber;
      End;
      DrawRubber;
      Form1.XEdit.Value:=CurrentXw;
      Form1.YEdit.Value:=CurrentYw;
        RubberDisplayList.Clear;
        TemplName:=Copy(ExtractFileName(Form1.LibraryShellTreeView.Path),1,Length(ExtractFileName(Form1.LibraryShellTreeView.Path))-Length(ExtractFileExt(Form1.LibraryShellTreeView.Path)));
        RubberDisplayList.Add('DrawTemplate '+TemplName+' '+Form1.XEdit.Text+','+Form1.YEdit.Text+','+Form1.AEdit.Text+','+Form1.SEdit.Text);
      DrawRubber;
    End;
    LockBackUpdate:=False;
    DisplayDebug;
End;

procedure MM_Connection(Shift: TShiftState; X, Y: Integer);
Begin
  If not(ssLeft in Shift) Then MM_ProcessHint;
  //Здесь передвижение узлов на свеженарисованной связи?
  MM_ProcessSetCursorType;
  If Unit1.Resizing Then If MM_ProcessResizing(Shift,X,Y) Then Exit;
  If Drawing Then Begin
    If MovingConnectionPort Then Begin
    End Else Begin
        DrawRubber;
        RubberDisplayList.Clear;
        RubberDisplayList.Add('SetColor '+ColorToString(Form1.BorderColorButton.ButtonColor));
        RubberDisplayList.Add('SetWidth '+IntToStr(Form1.WidthButton1.Tag));
        RubberDisplayList.Add('MoveTo '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w));
        RubberDisplayList.Add('LineTo '+FloatToStr(LastXw)+','+FloatToStr(LastYw));
        SelectX2s:=CurrentXs;SelectY2s:=CurrentYs;
        SelectX2w:=CurrentXw;SelectY2w:=CurrentYw;
        DrawRubber;
        LastXs:=SelectX2s;LastYs:=SelectY2s;
        LastXw:=SelectX2w;LastYw:=SelectY2w;
    end;
  end;
  DisplayDebug;

End;

procedure MM_Callout(Shift: TShiftState; X, Y: Integer);
Var I:Longint;
    RubberCmd:String;
Begin
   If Not (Moving or Unit1.Resizing) Then MM_ProcessHint;
    //движение резинового объекта
    MM_ProcessSetCursorType;
    MM_ProcessMoving(Shift,X,Y);
    If MM_ProcessResizing(Shift,X,Y) Then Exit;
    //Handle cursor надо ли менять курсор?
    //если мы в режиме редактирование и рисования - да, в режиме навигации - нет

    If (ssLeft in Shift) Then Begin
      If JustDrawing And (Not ClickNotDrag) And (RubberDisplayList.Count=0) Then Begin
        // самое начало рисования - набираем резину
        RubberDisplayList.Add('SetColor '+ColorToString(Form1.BorderColorButton.ButtonColor));
        RubberDisplayList.Add('SetBGColor '+ColorToString(Form1.BGColorButton.ButtonColor));
        RubberDisplayList.Add('SetWidth '+IntToStr(Form1.WidthButton1.Tag));
        RubberCmd:='Rect '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w)+','+FloatToStr(CurrentXw)+','+FloatToStr(CurrentYw);
        RubberDisplayList.Add(RubberCmd);
        Scene.ExecCommand(RubberDisplayList[0],ZeroAcc,0);
        Form1.CurrentEditingNameEdit.Text:='';
        Drawing:=True;
      End;
      JustDrawing:=False;
      DrawRubber;
      RubberDisplayList.Clear;
      RubberDisplayList.Add('SetColor '+ColorToString(Form1.BorderColorButton.ButtonColor));
      RubberDisplayList.Add('SetBGColor '+ColorToString(Form1.BGColorButton.ButtonColor));
      RubberDisplayList.Add('SetWidth '+IntToStr(Form1.WidthButton1.Tag));
      RubberCmd:='Rect '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w)+','+FloatToStr(CurrentXw)+','+FloatToStr(CurrentYw);
      RubberDisplayList.Add(RubberCmd);
      DrawRubber;
      Form1.XEdit.Value:=SelectX1w;
      Form1.YEdit.Value:=SelectY1w;
      Form1.LX1Edit.Value:=SelectX1w;
      Form1.LX2Edit.Value:=CurrentXw;
      Form1.LY1Edit.Value:=SelectY1w;
      Form1.LY2Edit.Value:=CurrentYw;
    End;
    DisplayDebug;
End;

procedure MM_Curl_Pen(Shift: TShiftState; X, Y: Integer);
Var N:Longint;
    Curl:TVCurl;
    AccObject:TAccObject;
Begin
  If not(ssLeft in Shift) Then MM_ProcessHint;
     If Drawing Then Begin
       Form1.CurlList.Items.Assign(Scene.VCurlList);
       N:=Scene.VCurlList.Count-1;
       LogMessage(4,IntToStr(N));
       Curl:=Scene.VCurlList.Objects[N] As TVCurl;
       If JustDrawing Then Begin //только начали рисовать - надо MoveTo
         If Form1.SnapToGridButton.Down Then Begin
           SelectX1s:=CurrentXGs;SelectY1s:=CurrentYGs;
           SelectX1w:=CurrentXGw;SelectY1w:=CurrentYGw;
         end Else Begin
           SelectX1s:=CurrentXs;SelectY1s:=CurrentYs;
           SelectX1w:=CurrentXw;SelectY1w:=CurrentYw;
         End;
         WCanvas.MoveTo(SelectX1s,SelectY1s);
         AccObject:=TAccObject.Create;
         AccObject.AcceleratedCommand:=AccelerateCommand('SetColor '+ColorToString(Form1.BorderColorButton.ButtonColor));
         Curl.DisplayList.AddObject('SetColor '+ColorToString(Form1.BorderColorButton.ButtonColor),AccObject);
         AccObject:=TAccObject.Create;
         AccObject.AcceleratedCommand:=AccelerateCommand('SetWidth '+IntToStr(Form1.WidthButton1.Tag));
         Curl.DisplayList.AddObject('SetWidth '+IntToStr(Form1.WidthButton1.Tag),AccObject);
         AccObject:=TAccObject.Create;
         AccObject.AcceleratedCommand:=AccelerateCommand('MoveTo '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w));
         Curl.DisplayList.AddObject('MoveTo '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w),AccObject);
         JustDrawing:=False;
       End;
       If Form1.SnapToGridButton.Down Then Begin
         SelectX1s:=CurrentXGs;SelectY1s:=CurrentYGs;
         SelectX1w:=CurrentXGw;SelectY1w:=CurrentYGw;
       end Else Begin
         SelectX1s:=CurrentXs;SelectY1s:=CurrentYs;
         SelectX1w:=CurrentXw;SelectY1w:=CurrentYw;
       End;
       WCanvas.Pen.Color:=Form1.BorderColorButton.ButtonColor;
       WCanvas.Pen.Width:=Form1.WidthButton1.Tag;
       WCanvas.LineTo(SelectX1s,SelectY1s);
       If Curl.DisplayList.Count>0 Then
         If Curl.DisplayList[Curl.DisplayList.Count-1]<>'LineTo '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w) Then Begin
           AccObject:=TAccObject.Create;
           AccObject.AcceleratedCommand:=AccelerateCommand('LineTo '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w));
           Curl.DisplayList.AddObject('LineTo '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w),AccObject);
         End;
     End Else Begin
    //   WCanvas.MoveTo(X,Y);
    //   Drawer.StoW(X,Y,Xw,Yw);
    //   Curl.DisplayList.Add('MoveTo '+FloatToStr(Xw)+','+FloatToStr(Yw));
     End;
End;

procedure MM_Curl_Label(Shift: TShiftState; X, Y: Integer);
Begin

End;

procedure MM_Curl_MultiLine(Shift: TShiftState; X, Y: Integer);
Begin

End;

procedure MM_Curl_Line(Shift: TShiftState; X, Y: Integer);
Var L,Fi,dx,dy:Extended;
Begin
  If (EditMode='curl line') And (Drawing) Then Begin
        WCanvas.MoveTo(SelectX1s,SelectY1s);//удаляем старую резину
        WCanvas.Pen.Mode:=pmnotXOR;
        WCanvas.Pen.Style:=psDot;
        WCanvas.Pen.Color:=Form1.BorderColorButton.ButtonColor;
        WCanvas.Pen.Width:=Form1.WidthButton1.Tag;
        WCanvas.LineTo(LastXs,LastYs);
        UpdateFrom:=updGUI;
        If Form1.SnapToGridButton.Down Then Begin
          SelectX2s:=CurrentXGs;SelectY2s:=CurrentYGs;
          SelectX2w:=CurrentXGw;SelectY2w:=CurrentYGw;
        end Else Begin
          SelectX2s:=CurrentXs;SelectY2s:=CurrentYs;
          SelectX2w:=CurrentXw;SelectY2w:=CurrentYw;
        End;
        Form1.LX2Edit.Value:=SelectX2w;
        Form1.LY2Edit.Value:=SelectY2w;
        dx:=SelectX2w-SelectX1w;dy:=SelectY2w-SelectY1w;
        Form1.LdXEdit.Value:=dX;
        Form1.LdYEdit.Value:=dY;
        If Form1.SnapToGridButton.Down Then Begin
          Form1.LX2GEdit.Value:=Round(SelectX2w/Form1.GridGapEdit.Value);
          Form1.LY2GEdit.Value:=Round(SelectY2w/Form1.GridGapEdit.Value);
          Form1.LdXGEdit.Value:=Round(dX/Form1.GridGapEdit.Value);
          Form1.LdYGEdit.Value:=Round(dY/Form1.GridGapEdit.Value);
        end;
        L:=Sqrt(Sqr(dx)+Sqr(dy));
        Fi:=ComputeFi(dx,dy);
        Form1.LLEdit.Value:=L;
        Form1.LFiEdit.Value:=Fi/pi*180;
        WCanvas.MoveTo(SelectX1s,SelectY1s); //рисуем новую резину
        WCanvas.Pen.Mode:=pmnotXOR;
        WCanvas.Pen.Style:=psDot;
        WCanvas.Pen.Color:=Form1.BorderColorButton.ButtonColor;
        WCanvas.Pen.Width:=Form1.WidthButton1.Tag;
        WCanvas.LineTo(SelectX2s,SelectY2s);
        LastXs:=SelectX2s;LastYs:=SelectY2s;
        LastXw:=SelectX2w;LastYw:=SelectY2w;
//        WCanvas.Pen.Mode:=pmCopy;
//        WCanvas.Pen.Style:=psSolid;
  end;
End;

procedure MM_Curl_Rect(Shift: TShiftState; X, Y: Integer);
Begin
  MM_ProcessHint;
  MM_Common;
End;

procedure MM_Curl_RRect(Shift: TShiftState; X, Y: Integer);
Begin
  MM_ProcessHint;
  MM_Common;
End;

procedure MM_Curl_Ellipse(Shift: TShiftState; X, Y: Integer);
Begin
  MM_ProcessHint;
  MM_Common;
End;

procedure TForm1.Image1MouseMove(Sender: TObject; Shift: TShiftState; X,  Y: Integer);
Var N,I,J,NumObj,NumConn:Longint;
    L,Fi,dx,dy:Extended;
    Curl:TVCurl;Templ:TVTemplate;Obj:TVObject;ObjectName,TName,Selection,ParsedBuf:String;
    SelHandle:TVSelHandle;

    AccObject:TAccObject;
    Delta:Longint;
    ItemsUnder:TStringList;

    StatLine,TemplName:String;
begin

//  If Form1.Active Then DrawingPanel.SetFocus;
  //pentablet style zoom
  If (ssLeft in Shift)And(ssCtrl in Shift)And Not (ssAlt in Shift) Then Begin
    Delta:=InitScalerY-Y;
    BasisChanging:=True;
    ViewScaleEdit.Value:=InitScale*Power(2,Delta/100);
    Drawer.StoW(Drawer.Wx Div 2,Drawer.Wy Div 2,CurrentXw,CurrentYw);
    ViewXEdit.Value:=CurrentXw;
    ViewYEdit.Value:=CurrentYw;
    Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
    BasisChanging:=False;
    Exit;
  end;
  DisplayDebug;
  CurrentXs:=X+Image1.Left;
  CurrentYs:=Y+Image1.Top;
  Drawer.StoW(CurrentXs,CurrentYs,CurrentXw,CurrentYw);
  CurrentXGw:=GridGapEdit.Value*Round(CurrentXw/GridGapEdit.Value);
  CurrentYGw:=GridGapEdit.Value*Round(CurrentYw/GridGapEdit.Value);
  Drawer.WtoS(CurrentXGw,CurrentYGw,CurrentXGs,CurrentYGs);
  CurrentXNGw:=CurrentXw;
  CurrentYNGw:=CurrentYw;
  If SnapToGridButton.Down Then Begin
    XcoordLabel.Caption:=FloatToStrF(CurrentXGw,ffGeneral,12,6)+'('+FloatToStr(CurrentXGw/GridGapEdit.Value)+')';
    YcoordLabel.Caption:=FloatToStrF(CurrentYGw,ffGeneral,12,6)+'('+FloatToStr(CurrentYGw/GridGapEdit.Value)+')';
    CurrentXw:=CurrentXGw;
    CurrentYw:=CurrentYGw;
  end Else Begin
    XcoordLabel.Caption:=FloatToStrF(CurrentXw,ffGeneral,12,6);
    YcoordLabel.Caption:=FloatToStrF(CurrentYw,ffGeneral,12,6);
  end;

//  If Not Moving Then
  If Abs(CurrentXs-SelectX1s)+Abs(CurrentYs-SelectY1s)>SamePlaceZone Then ClickNotDrag:=False Else ClickNotDrag:=True;//Move Not Click
  If Not (Moving Or Unit1.Resizing Or Drawing Or JustDrawing) Then
    If (AutoButton.Down) And Not Drawing Then Begin
      ItemsUnder:=Scene.BuildUnderMouse(CurrentXNGw,CurrentYNGw,SamePlaceZone);
      NumObj:=0;NumConn:=0;
      For I:=0 To ItemsUnder.Count-1 Do
        Case GetTypeByName(Scene,ItemsUnder[I]) Of
        'object':  Inc(NumObj);
        'connection': Inc(NumConn);
        End;
      If (NumObj=0) And (NumConn=0) Then Begin// щелчек над пустым - начинаем рисовать объект
        HintLabel.Hide;
        If EditMode<>'object' Then Begin
          EditMode:='object';
          If ObjStyleRadioGroup.ItemIndex=0 Then Begin
            TemplName:=Copy(ExtractFileName(Form1.LibraryShellTreeView.Path),1,Length(ExtractFileName(Form1.LibraryShellTreeView.Path))-Length(ExtractFileExt(Form1.LibraryShellTreeView.Path)));
            RubberDisplayList.Add('DrawTemplate '+TemplName+' '+Form1.XEdit.Text+','+Form1.YEdit.Text+','+Form1.AEdit.Text+','+Form1.SEdit.Text);
            DrawRubber;
          End;
          If Scene.SelectedList.Count=0 Then PrepareObjectPropEdit(Nil) Else
          If Scene.SelectedList.Objects[0] Is TVObject Then
            PrepareObjectPropEdit(Scene.SelectedList.Objects[0] As TVObject);
        end;
      end;
      If NumObj=1 Then Begin// щелчек над объектом - начинаем рисовать соединение
        If RubberDisplayList.Count>0 Then Begin
          DrawRubber;
          RubberDisplayList.Clear;
        End;
        EditMode:='connection';
        PrepareConnectionPropEdit(Nil);
      end;
      If (NumObj=0) And (NumConn=1) Then begin //щелчёк над соединением - добавляем узел
        EditMode:='connection';
        PrepareConnectionPropEdit(ItemsUnder.Objects[0] As TVConnection);
      End;
      ItemsUnder.Free;
    End;
  DisplayDebug;
  Case EditMode Of
  'navigation': Begin MM_Navigation(Shift,X,Y);End;
  'control':    Begin MM_Control(Shift,X,Y);End;
  'edit':       Begin MM_Edit(Shift,X,Y);End;
  'object':     Begin MM_Object(Shift,X,Y);End;
  'connection': Begin MM_Connection(Shift,X,Y);End;
  'callout':    Begin MM_Callout(Shift,X,Y);End;
  'curl pen':   Begin MM_Curl_Pen(Shift,X,Y);End;
  'curl label': Begin MM_Curl_Label(Shift,X,Y);End;
  'curl multiline': Begin MM_Curl_Multiline(Shift,X,Y);End;
  'curl line':  Begin MM_Curl_Line(Shift,X,Y);End;
  'curl rect':  Begin MM_Curl_Rect(Shift,X,Y);End;
  'curl rrect': Begin MM_Curl_RRect(Shift,X,Y);End;
  'curl ellipse': Begin MM_Curl_Ellipse(Shift,X,Y);End;
  End;
end;


Function UnderMouse(Scene:TVScene;X,Y:Integer):TStringList;
Var I:Longint;R:TStringList;
Begin
  R:=TStringList.Create;

  Result:=R; // free should be in the caller
End;

procedure MU_Navigation(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var I,J,K,ItemsUnderMouseCount:Longint;
    Obj:TVObject;
    Callout:TVCallout;
    PortFound,WasUpdated:Boolean;
    List:TStringList;
    ItemName,AnotherEnd:String;
    Port:TVPort;
    Connection:TVConnection;
    SlideItem:TMenuItem;
Begin
  BasisChanging:=True;
  If Abs(CurrentXs-SelectX1s)+Abs(CurrentYs-SelectY1s)>SamePlaceZone Then Begin
    // был драг - подвинуть сцену
    Form1.ViewXEdit.Value:=Form1.ViewXEdit.Value-CurrentXw+SelectX1NGw;
    Form1.ViewYEdit.Value:=Form1.ViewYEdit.Value-CurrentYw+SelectY1NGw;
    Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  end;
    WasUpdated:=False;
    ItemsUnderMouseCount:=0;
    List:=Scene.BuildUnderMouse(CurrentXw,CurrentYw,SamePlaceZone);
    If List.Count>0 Then Begin
      ItemsUnderMouseCount:=ItemsUnderMouseCount+List.Count;
      For I:=0 To List.Count-1 Do Begin
        If List.Objects[I] Is TVObject Then Begin
          Obj:=List.Objects[I] As TVObject;
          ItemName:=Obj.Name;
          If (Button=mbLeft) Then Begin
            Dispatcher.QueueCommand('self::CAD_ReloadSource:'+ItemName);
            WasUpdated:=True;
          End;
          //Sliding by Links
          //здесь надо уточнить порт или весь объект
          PortFound:=False;
          If Obj.PortList.Count>0 Then
            For J:=0 To Obj.PortList.Count-1 Do Begin
              Port:=Obj.PortList.Objects[J] As TVPort;
              If (Abs(CurrentXw-Port.AX)<=PortHandleZone*Drawer.ViewScale) and (Abs(CurrentYw-Port.AY)<=PortHandleZone*Drawer.ViewScale)
              Then Begin
                PortFound:=True;
                K:=Scene.VConnectionList.IndexOf(Port.Connection);
                If K>=0 Then Begin
                  Connection:=Scene.VConnectionList.Objects[K] As TVConnection;
                  If Connection.EndObj=Obj.Name Then AnotherEnd:=Connection.StartObj;
                  If Connection.StartObj=Obj.Name Then AnotherEnd:=Connection.EndObj;
                  Form1.SearchEdit.Text:=AnotherEnd;
                  Form1.GotoSearchSpeedButtonClick(Nil);
                end;
                Break;
              End;
            End;
          If Not PortFound Then Begin //click on object update it and all related CAs
 //           ReloadSource(Scene,ItemName);
            Dispatcher.QueueCommand('self::CAD_ReloadSource:'+ItemName);
            WasUpdated:=True;
          End;
        End;
        If List.Objects[I] Is TVCallout Then Begin
          Callout:=List.Objects[I] As TVCallout;
          ItemName:=Callout.Name;
        End;
        If List.Objects[I] Is TVConnection Then Begin
          Connection:=List.Objects[I] As TVConnection;
          ItemName:=Connection.Name;
        //  Form1.SlideByLinkMenu.Items.Clear;//должно быть корректное уничтожение пунктов меню
          SlideItem:=TMenuItem.Create(nil);
          SlideItem.Caption:=Connection.StartObj;
          SlideItem.OnClick:=Form1.SlideByLinkSpeedButton.OnClick;
          Form1.SlideByLinkMenu.Items.Add(SlideItem);
          SlideItem:=TMenuItem.Create(nil);
          SlideItem.Caption:=Connection.EndObj;
          SlideItem.OnClick:=Form1.SlideByLinkSpeedButton.OnClick;
          Form1.SlideByLinkMenu.Items.Add(SlideItem);
          Form1.SlideByLinkMenu.Popup;
        End;

      End;
      BasisChanging:=False;
      If (ItemsUnderMouseCount=1) And (Button=mbLeft) Then Begin
        Dispatcher.QueueCommand('self::CAD_ReloadSource:'+ItemName);
        WasUpdated:=True;
      End;
    End;
    If WasUpdated Then Dispatcher.QueueCommand('self::CAD_UpdateDraw');
end;

procedure MU_Control(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var List:TStringList;
    Obj:TVObject;
    Connection:TVConnection;
    Callout:TVCallout;
    Port:TVPort;
    ItemName,AnotherEnd:String;
    MItem:TMenuItem;
    PortFound,WasUpdated:Boolean;
    I,J,K,ItemsUnderMouseCount:Longint;
Begin
  BasisChanging:=True;
  If Abs(CurrentXs-SelectX1s)+Abs(CurrentYs-SelectY1s)>SamePlaceZone Then Begin
    Form1.ViewXEdit.Value:=Form1.ViewXEdit.Value-CurrentXw+SelectX1NGw;
    Form1.ViewYEdit.Value:=Form1.ViewYEdit.Value-CurrentYw+SelectY1NGw;
    Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  end;
 BasisChanging:=False;

    //Actions - generate Context menu
    Form1.ActionMenu.Items.Clear;
    ItemsUnderMouseCount:=0;
    WasUpdated:=False;
    List:=Scene.BuildUnderMouse(CurrentXw,CurrentYw,SamePlaceZone);
    If List.Count>0 Then Begin
      ItemsUnderMouseCount:=ItemsUnderMouseCount+List.Count;
      For I:=0 To List.Count-1 Do Begin
        If List.Objects[I] Is TVObject Then Begin
          Obj:=List.Objects[I] As TVObject;
          ItemName:=Obj.Name;
          Form1.SearchEdit.Text:=ItemName;
         //Sliding by Links  - в режиме управления не нужен, только в навигации?
         //здесь надо уточнить порт или весь объект
     {    PortFound:=False;
         If Obj.PortList.Count>0 Then
           For J:=0 To Obj.PortList.Count-1 Do Begin
             Port:=Obj.PortList.Objects[J] As TVPort;
             If (Abs(CurrentXw-Port.AX)<=PortHandleZone*Drawer.ViewScale) and (Abs(CurrentYw-Port.AY)<=PortHandleZone*Drawer.ViewScale)
             Then Begin
               PortFound:=True;
               K:=Scene.VConnectionList.IndexOf(Port.Connection);
               If K>=0 Then Begin
                 Connection:=Scene.VConnectionList.Objects[K] As TVConnection;
                 If Connection.EndObj=Obj.Name Then AnotherEnd:=Connection.StartObj;
                 If Connection.StartObj=Obj.Name Then AnotherEnd:=Connection.EndObj;
                 Form1.SearchEdit.Text:=AnotherEnd;
                 Form1.GotoSearchSpeedButtonClick(Nil);
               end;
               Break;
             End;
           End;}

          If Obj.ActionList.Count>0 Then
            For J:=0 To Obj.ActionList.Count-1 Do Begin
              MItem:=TMenuItem.Create(Nil);
              MItem.Caption:=Obj.ActionList.Names[J];
              MItem.OnClick:=Form1.ActionMenuButton.OnClick;
              Form1.ActionMenu.Items.Add(MItem);
            end;
          If (Button=mbLeft) Then Begin
            If Form1.ActionMenu.Items.IndexOfCaption(Form1.OpComboBox.Text)>=0 Then Begin
              //выбранная в списке операция есть в контекстном меню объекта
              Dispatcher.QueueCommand(Obj.ActionList.Values[Form1.OpComboBox.Text]);
            End;
          End;

        End;
        If List.Objects[I] Is TVCallout Then Begin
          Callout:=List.Objects[I] As TVCallout;
          ItemName:=Callout.Name;

          If Callout.ActionList.Count>0 Then
            For J:=0 To Callout.ActionList.Count-1 Do Begin
              MItem:=TMenuItem.Create(Nil);
              MItem.Caption:=Callout.ActionList.Names[J];
              MItem.OnClick:=Form1.ActionMenuButton.OnClick;
              Form1.ActionMenu.Items.Add(MItem);
            end;
            If (Button=mbLeft) Then Begin
              If Form1.ActionMenu.Items.IndexOfCaption(Form1.OpComboBox.Text)>=0 Then Begin
              //выбранная в списке операция есть в контекстном меню объекта
              Dispatcher.QueueCommand(Callout.ActionList.Values[Form1.OpComboBox.Text]);
            End;
          End;
        End;
    End;

    List.Free;

{    If (ItemsUnderMouseCount=1)Or(Form1.ActionMenu.Items.Count=1) Then Begin
      // ровно один объект под курсором -
      // автовыполняем обновление по левой кнопке
      // контекстное меню по правой
      Form1.SearchEdit.Text:=ItemName;
    End;}
    If (Form1.ActionMenu.Items.Count>0) And (Button=mbRight) Then
      Form1.ActionMenu.PopUp;
  End;
  If WasUpdated Then Dispatcher.QueueCommand('self::CAD_UpdateDraw');

 End;

procedure MU_Edit(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var Xw,Yw,xw1,xw2,yw1,yw2,NewX,NewY,XB:Extended;
    xws,yws,xw1s,yw1s,xw2s,yw2s:String;
    Cmd,Buf,ParsedBuf,Selection,BIUS:String;
    ModCommandNumber:Longint;
//    CurlName:String;
    PrimitiveName:String;
    Curl,NewCurl:TVCurl;I,J,K,N:Longint;
    Callout:TVCallout;
    SelHandle:TVSelHandle;
    Obj,Obj1:TVObject;  ItemName:String;
    Port,Port1:TVPort;
    PortFound:Boolean;
    Connection:TVConnection;
    ConnPort:TVConnectionPort;
    AccObject:TAccObject;
    NonAccCommand:String;
    ActiveObject:Boolean;
    SomethingToDo:Boolean;
    Flag:Boolean;
    SelectShell:TShell;
Begin
  UnderMouseUP.Free;
  UnderMouseUP:=Scene.BuildUnderMouse(CurrentXw,CurrentYw,SamePlaceZone);
  // clear rubber
  DrawRubber;
 // LockBackUpdate:=True;
  If Button=mbRight Then Begin //Context menu
    Form1.OperationMenu.Popup;
    Exit;
  End;
  If (ssAlt in Shift) Then Begin //Box selection
       Drawing:=False;
       RubberDisplayList.Clear;
       SelectX2s:=CurrentXs;SelectY2s:=CurrentYs;
       SelectX2w:=CurrentXNGw;SelectY2w:=CurrentYNGw;
       SelectShell.X1:=SelectX1w;
       SelectShell.X2:=SelectX2w;
       SelectShell.Y1:=SelectY1w;
       SelectShell.Y2:=SelectY2w;
       If Form1.SearchFilterCurlSpeedButton.Down Then
       If Scene.VCurlList.Count>0 Then Begin
         For I:=Scene.VCurlList.Count-1 DownTo 0 Do Begin
           Curl:=Scene.VCurlList.Objects[I] As TVCurl;
           If ShellsAreCrossed(Curl.Shell,SelectShell) Then
             Case Form1.OpComboBox.Text of
             'Select': AddItemToSelection(Curl.Name);
//             'Delete': Begin Scene.DeleteCurl(Curl);End;
             'Move here': Begin ShowMessage('Not implemented yet');End;
             'Copy here': ShowMessage('Not implemented yet');
             'Add to group': ShowMessage('Not implemented yet');
             'Remove from group': ShowMessage('Not implemented yet');
             End;
         End;
       End;
       If Form1.SearchFilterConnSpeedButton.Down Then
       If Scene.VConnectionList.Count>0 Then Begin
         For I:=Scene.VConnectionList.Count-1 DownTo 0 Do Begin
           Connection:=Scene.VConnectionList.Objects[I] As TVConnection;
           //Dont check objects, belongs to disabled group
           ActiveObject:=True;
           If Connection.GroupList.Count>0 Then
             For K:=Connection.GroupList.Count-1 DownTo 0 Do Begin
               If Not (Connection.GroupList.Objects[K] As TVGroup).Active Then ActiveObject:=False;
             end;
           If Not ActiveObject Then Continue;
           If ShellsAreCrossed(Connection.Shell,SelectShell) Then
             Case Form1.OpComboBox.Text of
             'Select': AddItemToSelection(Connection.Name);
             'Delete': Begin Scene.DeleteConnection(Connection);End;
             'Move here': Begin ShowMessage('Not implemented yet');End;
             'Copy here': ShowMessage('Not implemented yet');
             'Add to group': ShowMessage('Not implemented yet');
             'Remove from group': ShowMessage('Not implemented yet');
             End;
         End;
       End;
       If Form1.SearchFilterCalloutSpeedButton.Down Then
       If Scene.VCalloutList.Count>0 Then Begin
           For I:=Scene.VCalloutList.Count-1 DownTo 0 Do Begin
             Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
             //Dont check objects, belongs to disabled group
             ActiveObject:=True;
             If Callout.GroupList.Count>0 Then
               For K:=0 To Callout.GroupList.Count-1 Do Begin
                 If Not (Callout.GroupList.Objects[K] As TVGroup).Active Then ActiveObject:=False;
               end;
             If Not ActiveObject Then Continue;
             If ShellsAreCrossed(Callout.Shell,SelectShell) Then
               Case Form1.OpComboBox.Text of
               'Select': AddItemToSelection(Callout.Name);
               'Delete': Begin Scene.DeleteCallout(Callout);End;
               'Move here': Begin ShowMessage('Not implemented yet');End;
               'Copy here': ShowMessage('Not implemented yet');
               'Add to group': ShowMessage('Not implemented yet');
               'Remove from group': ShowMessage('Not implemented yet');
               End;
           End;
         End;
       If Form1.SearchFilterObjectSpeedButton.Down Then
       If Scene.VObjectList.Count>0 Then Begin
         For I:=Scene.VObjectList.Count-1 DownTo 0 Do Begin
           Obj:=Scene.VObjectList.Objects[I] As TVObject;
           //Dont check objects, belongs to disabled group
           ActiveObject:=True;
           If Obj.GroupList.Count>0 Then
             For K:=Obj.GroupList.Count-1 DownTo 0 Do Begin
               If Not (Obj.GroupList.Objects[K] As TVGroup).Active Then ActiveObject:=False;
             end;
           If Not ActiveObject Then Continue;
           If ShellsAreCrossed(Obj.Shell,SelectShell) Then Begin
             // click on object - do specified operation
             Case Form1.OpComboBox.Text of
             'Select': AddItemToSelection(Obj.Name);
             'Delete': Begin Scene.DeleteObject(Obj);End;
             'Move here': Begin ShowMessage('Not implemented yet');End;
             'Copy here': ShowMessage('Not implemented yet');
             'Add to group': ShowMessage('Not implemented yet');
             'Remove from group': ShowMessage('Not implemented yet');
             End;
           end;
         End;
       End;

       UpdateMultiSelection;
       Dispatcher.ExecCommand('self::CAD_Scene2GUI');
       RepaintView;

       If Scene.VGroupList.Count>0 Then Begin
       End;
       DisplayDebug;
       LockBackUpdate:=False;
       Exit;
  End;

  RubberDisplayList.Clear;
  JustDrawing:=False;

  If Unit1.Resizing Then Begin
    Unit1.Resizing:=False;
    Moving:=False;
    Drawing:=False;
    JustDrawing:=False;
    RepaintView;
    AllowMove:=False;
    DisplayDebug;
    Case GetTypeByName(Scene,ActiveSelHandle.Name) Of
    'connection': Begin
                 N:=Scene.VConnectionList.IndexOf(ActiveSelHandle.Name);
                 Connection:=Scene.VConnectionList.Objects[N] As TVConnection;
                 If Form1.SnapToGridButton.Down Then Begin
                   NewX:=Form1.GridGapEdit.Value*Round((SelectX2w)/Form1.GridGapEdit.Value);
                   NewY:=Form1.GridGapEdit.Value*Round((SelectY2w)/Form1.GridGapEdit.Value);
                 End Else Begin
                   NewX:=SelectX2w;
                   NewY:=SelectY2w;
                 End;
                 //обновить координаты узла
                   ConnPort:=Connection.PortList.Objects[ActiveNodeNum] As TVConnectionPort;
                   ConnPort.AX:=ActiveSelHandle.Xw;
                   ConnPort.AY:=ActiveSelHandle.Yw;
                   If ConnPort.AX<Connection.Shell.X1 Then Connection.Shell.X1:=ConnPort.AX;
                   If ConnPort.AX>Connection.Shell.X2 Then Connection.Shell.X2:=ConnPort.AX;
                   If ConnPort.AY<Connection.Shell.Y1 Then Connection.Shell.Y1:=ConnPort.AY;
                   If ConnPort.AY>Connection.Shell.Y2 Then Connection.Shell.Y2:=ConnPort.AY;

                   If ConnPort.AR='R' Then Begin
                     ConnPort.X:=(ConnPort.AX-Connection.Shell.X1)/(Connection.Shell.X2-Connection.Shell.X1);
                     ConnPort.Y:=(ConnPort.AY-Connection.Shell.Y1)/(Connection.Shell.Y2-Connection.Shell.Y1);
                   End;
                   Scene.UpdateConnectionDisplayList(Connection);
                   Scene.UpdateSelHandles(Connection.Name);
                   PrepareConnectionPropEdit(Connection);
               End;
    End;
    Exit;
  End;

  If ClickNotDrag Then Begin
    //remove those items from underMouseUP - which are not match filter buttons
    If UnderMouseUP.Count>0 then
      For I:=UnderMouseUP.Count-1 DownTo 0 Do Begin
        Case GetTypeByName(Scene,UnderMouseUp[I]) of
        'object': If not Form1.SearchFilterObjectSpeedButton.Down Then UnderMouseUp.Delete(I);
        'connection': If not Form1.SearchFilterConnSpeedButton.Down Then UnderMouseUp.Delete(I);
        'curl': If not Form1.SearchFilterCurlSpeedButton.Down Then UnderMouseUp.Delete(I);
        'callout': If not Form1.SearchFilterCalloutSpeedButton.Down Then UnderMouseUp.Delete(I);
        End;
      End;

    If UnderMouseUP.Count=0 Then Begin
      // click over empty space unselect everything
      UnselectAllBut('');
      RubberDisplayList.Clear;
      UpdateMultiSelection;
      AllowMove:=False;
      DisplayDebug;
      Exit;
    End;
    Case Form1.OpComboBox.Text of
    'Select': Begin
      If (LowerCase(Config.ConfigFile.Values['SelectionMode'])<>'pen') And Not (ssShift in Shift) Then Begin
        //Select Only this = Unselect Everything but this + Select this

        //first clean up selection from items list of GUI And SelHandles
        For I:=Scene.SelectedList.Count-1 Downto 0 Do Begin
          RemoveItemFromSelection(Scene.SelectedList[I]);
        End;
        Form1.SelectionListEditor.Cells[0,1]:='';
        Form1.SelectionListEditor.Cells[1,1]:='';

        For I:=0 To UnderMouseUP.Count-1 Do Begin
          AddItemToSelection(UnderMouseUP[I]);
        End;
      End Else Begin
        //CAD or Office+Shift=invert Selection
        For I:=0 To UnderMouseUP.Count-1 Do Begin
          N:=Scene.SelectedList.IndexOf(UnderMouseUP[I]);
          If N<0 Then AddItemToSelection(UnderMouseUP[I])
          Else RemoveItemFromSelection(UnderMouseUP[I]);
        End;
      End;
      If Scene.SelectedList.Count>1 Then Begin
        Form1.InspectorPanel.Hide;
        Form1.SelectionListPanel.Show;
        Form1.ToolOptionsPanel.Show;
        Form1.Splitter2.Show;
      end;
      If Scene.SelectedList.Count=1 Then Begin
        //надо показать инспектор соотв
        Form1.SelectionListPanel.Hide;
        Form1.InspectorPanel.Show;
        Form1.ToolOptionsPanel.Show;
        Form1.Splitter2.Show;
        Case GetTypeByName(Scene,Scene.SelectedList[0]) of
        'curl':  ;
        'object':  Begin
                     Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(Scene.SelectedList[0])] As TVObject;
                     PrepareObjectPropEdit(Obj);
                   End;
        'callout': Begin
                     Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(Scene.SelectedList[0])] As TVCallout;
                     PrepareCalloutPropEdit(Callout);
                   End;
        'connection': Begin
                        Connection:=Scene.VConnectionList.Objects[Scene.VConnectionList.IndexOf(Scene.SelectedList[0])] As TVConnection;
                        PrepareConnectionPropEdit(Connection);
                      End;
        End;
      end;
      {$IFDEF LINUX}
      {$ELSE}
      PlaySound('TransA3.wav', 0, SND_ASYNC);
      {$ENDIF};
      If Scene.SelectedList.Count=0 Then Begin
        Form1.ToolOptionsPanel.Hide;
        Form1.Splitter2.Hide;
        Form1.SelectionListPanel.Hide;
        Form1.InspectorPanel.Hide;
      End;
              End;
    'Delete': Begin
                For I:=UnderMouseUP.Count-1 DownTo 0 Do DeleteItem(UnderMouseUP[I]);
                Dispatcher.ExecCommand('self::CAD_UpdateDraw');
              End;
    'Move here': Begin ShowMessage('Not implemented yet');End;
    'Copy here': ShowMessage('Not implemented yet');
    'Add to group': ShowMessage('Not implemented yet');
    'Remove from group': ShowMessage('Not implemented yet');
    End;


  End Else Begin //Drag
//    If Abs(CurrentXs-SelectX1s)+Abs(CurrentYs-SelectY1s)<=SamePlaceZone Then Exit;
    If (Scene.SelectedList.Count>0) And AllowMove Then Begin // Moving selection
       Moving:=False;AllowMove:=False;
       DisplayDebug;
       WCanvas.Pen.Mode:=pmCopy;
       WCanvas.Pen.Style:=psSolid;
       Scene.Drawer.EnforcedPenStyle:=psClear;
     //  LockBackUpdate:=True;
       For I:=0 To Scene.SelectedList.Count-1 Do Begin
         ItemName:=Scene.SelectedList[I];
         Case GetTypeByName(Scene,ItemName) Of
         'object': Begin
             N:=Scene.VObjectList.IndexOf(ItemName);
             Obj:=Scene.VObjectList.Objects[N] As TVObject;
             If Form1.SnapToGridButton.Down Then Begin
               NewX:=Form1.GridGapEdit.Value*Round((Obj.X+SelectX2w-SelectX1w)/Form1.GridGapEdit.Value);
               NewY:=Form1.GridGapEdit.Value*Round((Obj.Y+SelectY2w-SelectY1w)/Form1.GridGapEdit.Value);
             End Else Begin
               NewX:=Obj.X+SelectX2w-SelectX1w;
               NewY:=Obj.Y+SelectY2w-SelectY1w;
             End;
             //обновить координаты связей
             Scene.MoveObjectTo(Obj,newX,newY,'');
             Scene.ObjectAttr2Style(Obj);
             Scene.UpdateSelHandles(Obj.Name);
             PrepareObjectPropEdit(Obj);
           End;
         'callout': Begin
             N:=Scene.VCalloutList.IndexOf(ItemName);
             Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
             If (Callout.RelatedObj<>'') Then K:=Scene.VObjectList.IndexOf(Callout.RelatedObj);
                If (K>=0) And (Scene.SelectedList.IndexOf(Callout.RelatedObj)>=0)
                Then
                  // не двигаем дополнительно выноску, чей базовый объект только что двигали
                Else Begin
                  If Form1.SnapToGridButton.Down Then Begin
                    NewX:=Form1.GridGapEdit.Value*Round((Callout.X+SelectX2w-SelectX1w)/Form1.GridGapEdit.Value);
                    NewY:=Form1.GridGapEdit.Value*Round((Callout.Y+SelectY2w-SelectY1w)/Form1.GridGapEdit.Value);
                  End Else Begin
                    NewX:=Callout.X+SelectX2w-SelectX1w;
                    NewY:=Callout.Y+SelectY2w-SelectY1w;
                  End;
                  //обновить координаты связей
                  Scene.MoveCalloutTo(Callout,newX,newY,'');
                  Scene.CalloutAttr2Style(Callout);
                  Scene.UpdateCalloutDisplayList(Callout);
                end;
                Scene.UpdateSelHandles(Callout.Name);
                //обновить хэндлы выделения
              {  Form1.EditCalloutButtonClick(Nil);}
              End;
         End;
       End;
   //    LockBackUpdate:=False;
       Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
       Exit;
     End;
     // указывали не на объект - передвигаем экран
      BasisChanging:=True;
      If Abs(CurrentXs-SelectX1s)+Abs(CurrentYs-SelectY1s)>SamePlaceZone Then Begin
        Form1.ViewXEdit.Value:=Form1.ViewXEdit.Value-CurrentXw+SelectX1NGw;
        Form1.ViewYEdit.Value:=Form1.ViewYEdit.Value-CurrentYw+SelectY1NGw;
        Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
      end;
     BasisChanging:=False;
   End;
End;

Procedure MU_Common;
Var  Curl:TVCurl;
     PrimitiveName:String;
     dx,dy,L,Fi,Xw1,Xw2,Yw1,Yw2:Extended;
     N:Longint;
     AccObject:TAccObject;
     NonAccCommand:String;
Begin
  If (EditMode='curl rect') Or (EditMode='curl rrect') Or (EditMode='curl ellipse') Then Begin
     Drawing:=False;
     JustDrawing:=False;
     WCanvas.Pen.Mode:=pmnotXOR;
     WCanvas.Pen.Style:=psDot;
     WCanvas.Pen.Color:=Form1.BorderColorButton.ButtonColor;
     WCanvas.Brush.Color:=Form1.BGColorButton.ButtonColor;
     WCanvas.Pen.Width:=Form1.WidthButton1.Tag;
     If EditMode='curl rect' Then WCanvas.Rectangle(SelectX1s,SelectY1s,SelectX2s,SelectY2s);
     If EditMode='curl rrect' Then WCanvas.RoundRect(SelectX1s,SelectY1s,SelectX2s,SelectY2s,20,20);
     If EditMode='curl ellipse' Then WCanvas.Ellipse(SelectX1s,SelectY1s,SelectX2s,SelectY2s);
{     If SnapToGridButton.Down Then Begin //ниасилил
       Drawer.StoW(X+Image1.Left,Y+Image1.Top,Xw,Yw);
       Xw:=GridGapEdit.Value*Round(Xw/GridGapEdit.Value);
       Yw:=GridGapEdit.Value*Round(Yw/GridGapEdit.Value);
       Drawer.WtoS(Xw,Yw,X0,Y0);
     End Else Begin
       X0:=X+Image1.Left;Y0:=Y+Image1.Top;
     End;
     SelectX2:=X0;SelectY2:=Y0;}
     WCanvas.Pen.Mode:=pmCopy;
     WCanvas.Pen.Style:=psSolid;
//     Drawer.Canvas.Rectangle(SelectX1s,SelectY1s,SelectX2s,SelectY2s);
     If EditMode='curl rect' Then Drawer.Canvas.Rectangle(SelectX1s,SelectY1s,SelectX2s,SelectY2s);
     If EditMode='curl rrect' Then Drawer.Canvas.RoundRect(SelectX1s,SelectY1s,SelectX2s,SelectY2s,20,20);
     If EditMode='curl ellipse' Then Drawer.Canvas.Ellipse(SelectX1s,SelectY1s,SelectX2s,SelectY2s);

     If (SelectX1s=SelectX2s) Or (SelectY1s=SelectY2s) Then Exit; //не создаем пустой объект
     Curl:=TVCurl.Create;
     Curl.Saveable:=True;
     PrimitiveName:=GetNewName(Scene,Scene.VCurlList,'rect');
     Scene.VCurlList.AddObject(PrimitiveName,Curl);
     Curl.Name:=PrimitiveName;
     Form1.CurrentEditingNameEdit.Text:=PrimitiveName;
     Form1.CurrentEditingNameEdit.Enabled:=True;
     AccObject:=TAccObject.Create;
     AccObject.AcceleratedCommand:=AccelerateCommand('SetColor '+ColorToString(Form1.BorderColorButton.ButtonColor));
     Curl.DisplayList.AddObject('SetColor '+ColorToString(Form1.BorderColorButton.ButtonColor),AccObject);
     AccObject:=TAccObject.Create;
     AccObject.AcceleratedCommand:=AccelerateCommand('SetBGColor '+ColorToString(Form1.BGColorButton.ButtonColor));
     Curl.DisplayList.AddObject('SetBGColor '+ColorToString(Form1.BGColorButton.ButtonColor),AccObject);
     AccObject:=TAccObject.Create;
     AccObject.AcceleratedCommand:=AccelerateCommand('SetWidth '+IntToStr(Form1.WidthButton1.Tag));
     Curl.DisplayList.AddObject('SetWidth '+IntToStr(Form1.WidthButton1.Tag),AccObject);
     Drawer.StoW(SelectX1s,SelectY1s,Xw1,Yw1);
     Drawer.StoW(SelectX2s,SelectY2s,Xw2,Yw2);
     If Form1.SnapToGridButton.Down Then Begin
       Xw1:=Form1.GridGapEdit.Value*Round(Xw1/Form1.GridGapEdit.Value);
       Yw1:=Form1.GridGapEdit.Value*Round(Yw1/Form1.GridGapEdit.Value);
       Xw2:=Form1.GridGapEdit.Value*Round(Xw2/Form1.GridGapEdit.Value);
       Yw2:=Form1.GridGapEdit.Value*Round(Yw2/Form1.GridGapEdit.Value);
     End;
     AccObject:=TAccObject.Create;
     If EditMode='curl rect' Then NonAccCommand:='Rect '+FloatToStr(Xw1)+','+FloatToStr(Yw1)+','+FloatToStr(Xw2)+','+FloatToStr(Yw2);
     If EditMode='curl rrect' Then NonAccCommand:='RoundRect '+FloatToStr(Xw1)+','+FloatToStr(Yw1)+','+FloatToStr(Xw2)+','+FloatToStr(Yw2);
     If EditMode='curl ellipse' Then NonAccCommand:='Ellipse '+FloatToStr(Xw1)+','+FloatToStr(Yw1)+','+FloatToStr(Xw2)+','+FloatToStr(Yw2);
     AccObject.AcceleratedCommand:=AccelerateCommand(NonAccCommand);
     Curl.DisplayList.AddObject(NonAccCommand,AccObject);
     E:=GenShift(0,0);
     Curl.Shell:=Scene.RenderShell(Curl.DisplayList,E);
     Scene.View.Add('DrawCurl '+Curl.Name);
     Scene.ExecCommand('DrawCurl '+Curl.Name,ZeroAcc,0);
     Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  end;
end;

procedure MU_Object(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var I,N:Longint;
    Obj:TVObject;
    PrimitiveName:String;
Begin
  // erase rubber objects
  DrawRubber;
  RubberDisplayList.Clear;
  If Unit1.Resizing Then Begin Unit1.Resizing:=False;RepaintView;Exit;End;
  If Moving Then Begin Moving:=False;RepaintView;Exit;End;
  Drawing:=False;
  JustDrawing:=False;
  If (Form1.ObjStyleRadioGroup.ItemIndex>=2) And (Form1.ObjStyleRadioGroup.ItemIndex<=6) Then
    If Abs(SelectX1s-SelectX2s)+Abs(SelectY1s-SelectY2s)<=SamePlaceZone Then Exit; //не создаем пустой объект
  If (Form1.ObjStyleRadioGroup.ItemIndex>=2) And (Form1.ObjStyleRadioGroup.ItemIndex<=6) Then
    If (Form1.LX1Edit.Value=Form1.LX2Edit.Value)Or(Form1.LY1Edit.Value=Form1.LY2Edit.Value) Then Exit; //не создаем пустой объект
  If (Form1.ObjStyleRadioGroup.ItemIndex=0) And (Form1.LibraryShellTreeView.SelectionCount=0) Then Exit;//nothing selected
  If (Form1.ObjStyleRadioGroup.ItemIndex=0) And (Pos('.tpg',Form1.LibraryShellTreeView.Path)=0) Then Exit;//nothing selected
  LockBackUpdate:=True;
  Obj:=TVObject.Create;
  PrimitiveName:=GetNewName(Scene,Scene.VObjectList,'');
  Obj.Name:=PrimitiveName;
  Obj.Saveable:=True;
  Scene.VObjectList.AddObject(PrimitiveName,Obj);
  Form1.CurrentEditingNameEdit.Text:=PrimitiveName;
  Form1.CurrentEditingNameEdit.Enabled:=True;
  Form1.XEdit.Value:=SelectX1w;
  Form1.YEdit.Value:=SelectY1w;
  Form1.LX1Edit.Value:=SelectX1w;
  Form1.LX2Edit.Value:=SelectX2w;
  Form1.LY1Edit.Value:=SelectY1w;
  Form1.LY2Edit.Value:=SelectY2w;
  ObjectGUI2Scene;
  Scene.ObjectStyle2Attr(Obj);
  Scene.UpdateObjectDisplayList(Obj);
  Scene.View.Add('DrawObject '+PrimitiveName);
  Scene.VisibleList.AddObject(PrimitiveName,Obj);
  UnselectAllBut(PrimitiveName);
  If Form1.ObjStyleRadioGroup.ItemIndex<>0 Then AddItemToSelection(PrimitiveName);
  RepaintView;
  If Form1.ObjStyleRadioGroup.ItemIndex=0 Then Begin
    DrawRubber;
    //отцепляем объект-шаблон
    Form1.CurrentEditingNameEdit.Text:='';
    Form1.CurrentEditingNameEdit.Enabled:=False;
  End;
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  LockBackUpdate:=False;
  LockSelectionUpdate:=False;
End;

procedure MU_Connection(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var Connection:TVConnection;
    PrimitiveName,ObjName,PortName:String;
    SourcePortName:String;
    Obj:TVObject;
    Port:TVPort;
    I,J,N,ObjCount:Longint;
    PortFound:Boolean;
    ConnPort:TVConnectionPort;
Begin
   If Unit1.Resizing Then Begin Unit1.Resizing:=False;RepaintView;Exit;End;
   If Form1.AutoButton.Down And (UnderMouseUP.Count=1) And (GetTypeByName(Scene,Form1.CurrentEditingNameEdit.Text)='connection') Then Begin
      //добавить создание узлов сюда?
      Connection:=Scene.VConnectionList.Objects[Scene.VConnectionList.IndexOf(Form1.CurrentEditingNameEdit.Text)] As TVConnection;
      AddConnectionNodeAt(Connection,CurrentXs,CurrentYs);
      Exit;
    End;

      If MovingConnectionPort Then Exit;
      DrawRubber;
      RubberDisplayList.Clear;
      Drawing:=False;
      JustDrawing:=False;
      Moving:=False;
      //надо выйти если не начинали рисовать
      If SourceObj=nil Then Exit;
        UnderMouseUP.Free;
        UnderMouseUP:=Scene.BuildUnderMouse(CurrentXw,CurrentYw,SamePlaceZone);
        If UnderMouseUP.Count=0 Then Exit;
        ObjCount:=0;
        For I:=0 To UnderMouseUP.Count-1 Do
          If GetTypeByName(Scene,UnderMouseUP[I])='object' Then Begin
            Inc(ObjCount);
            ObjName:=UnderMouseUP[I];
          End;
        If ObjCount<>1 Then Exit;
        N:=Scene.VObjectList.IndexOf(ObjName);
        Obj:=Scene.VObjectList.Objects[N] As TVObject;

        If (Form1.AutoButton.Down) Or (Form1.AutoCreatePortSpeedButton.Down) Then Begin
          //авторежим - создаем порты автоматом
          If SourcePort=Nil Then Begin
            SourcePortName:=CreateObjectPort(SourceObj.Name,
                'X='+FloatToStr((SelectX1w-SourceObj.Shell.X1)/(SourceObj.Shell.X2-SourceObj.Shell.X1))+
                ' Y='+FloatToStr((SelectY1w-SourceObj.Shell.Y1)/(SourceObj.Shell.Y2-SourceObj.Shell.Y1)));
            SourcePort:=SourceObj.PortList.Objects[SourceObj.PortList.IndexOf(SourcePortName)] As TVPort;
          End;
          PortFound:=False;
          If Obj.PortList.Count>0 Then
            For J:=0 To Obj.PortList.Count-1 Do Begin
              Port:=Obj.PortList.Objects[J] As TVPort;
              If (Abs(CurrentXNGw-Port.AX)<=PortHandleZone*Drawer.ViewScale) and (Abs(CurrentYNGw-Port.AY)<=PortHandleZone*Drawer.ViewScale)
              Then Begin
                PortFound:=True; Break;
              End;
            End;
          If Not PortFound Then Begin
            PortName:=CreateObjectPort(Obj.Name, 'X='+FloatToStr((SelectX2w-Obj.Shell.X1)/(Obj.Shell.X2-Obj.Shell.X1))+
                                       ' Y='+FloatToStr((SelectY2w-Obj.Shell.Y1)/(Obj.Shell.Y2-Obj.Shell.Y1)));
            N:=Obj.PortList.IndexOf(PortName);
            If N>=0 Then Port:=Obj.PortList.Objects[N] As TVPort;
            PortFound:=True;
          End;

        End;
          //здесь надо уточнить порт или весь объект
        If Not((Form1.AutoButton.Down) Or (Form1.AutoCreatePortSpeedButton.Down)) Then Begin
          PortFound:=False;
          If Obj.PortList.Count>0 Then
            For J:=0 To Obj.PortList.Count-1 Do Begin
              Port:=Obj.PortList.Objects[J] As TVPort;
              If (Abs(CurrentXNGw-Port.AX)<=PortHandleZone*Drawer.ViewScale) and (Abs(CurrentYNGw-Port.AY)<=PortHandleZone*Drawer.ViewScale)
              Then Begin
                PortFound:=True; Break;
              End;
            End;
        End;
        If PortFound Then Begin
          SelectX2w:=Port.AX;SelectY2w:=Port.AY;
        End Else Begin
          SelectX2w:=Obj.X;SelectY2w:=Obj.Y;
        End;
        Drawer.WtoS(SelectX2w,SelectY2w,SelectX2s,SelectY2s);
        WCanvas.MoveTo(SelectX1s,SelectY1s);
        WCanvas.LineTo(SelectX2s,SelectY2s);
        Drawing:=False;

        //был поиск перебором - теперь есть запомненный объект-начало
        {For I:=0 To Scene.VObjectList.Count-1 Do Begin
          Obj1:=Scene.VObjectList.Objects[I] As TVObject;
          If PointInWRect(SelectX1w,SelectY1w,Obj1.Shell.X1,Obj1.Shell.Y1,Obj1.Shell.X2,Obj1.Shell.Y2) Then Begin
            Selection:=Obj1.Name;
            N:=ObjectList.Items.IndexOf(Obj1.Name);
          End;
        end;
        Obj1:=Scene.VObjectList.Objects[N] As TVObject;}
      With Form1 Do Begin
        LockBackUpdate:=True;
        Connection:=TVConnection.Create;
        PrimitiveName:=GetNewName(Scene,Scene.VConnectionList,'');
        Connection.Name:=PrimitiveName;
        Connection.Saveable:=True;
        Scene.VConnectionList.AddObject(PrimitiveName,Connection);

        CurrentEditingNameEdit.Text:=PrimitiveName;
        CurrentEditingNameEdit.Enabled:=True;
        Connection.StartObj:=SourceObj.Name;
        N:=Scene.VObjectList.IndexOf(ObjName);
        Obj:=Scene.VObjectList.Objects[N] As TVObject;
        Connection.EndObj:=Obj.Name;
        Connection.Color:=ColorToString(BorderColorButton.ButtonColor);
        Connection.BGColor:=ColorToString(BGColorButton.ButtonColor);
        Connection.Width:=IntToStr(WidthButton1.Tag);
        Connection.StartStyle:=Form1.StartStyleComboBox.Text;
        Connection.EndStyle:=Form1.EndStyleComboBox.Text;
        Scene.ConnectionAttr2Style(Connection);
        ConnPort:=TVConnectionPort.Create;
        ConnPort.PortType:='Start';
        ConnPort.X:=0;
        ConnPort.Y:=0;
        ConnPort.AR:='R';
        ConnPort.ConnectedObject:=SourceObj.Name;
{        If AutoCreatePortSpeedButton.Down Then Begin
          SourcePortName:=CreateObjectPort(SourceObj.Name,
                        'X='+FloatToStr((SelectX1w-SourceObj.Shell.X1)/(SourceObj.Shell.X2-SourceObj.Shell.X1))+
                        ' Y='+FloatToStr((SelectY1w-SourceObj.Shell.Y1)/(SourceObj.Shell.Y2-SourceObj.Shell.Y1)));
          SourcePort:=SourceObj.PortList.Objects[SourceObj.PortList.IndexOf(SourcePortName)] As TVPort;
        End;}

        If SourcePort=Nil Then Begin
          Connection.StartPort:='';
          ConnPort.ConnectedPort:='';
          SourceObj.NonPortConnectionList.Add(Connection.Name)
        End Else Begin
          ConnPort.ConnectedPort:=SourcePort.Name;
          SourcePort.Connection:=Connection.Name;
          SourcePort.ConnectionPort:='Start';
          Connection.StartPort:=SourcePort.Name;
        end;
        Connection.PortList.AddObject('Start',ConnPort);
        ConnPort:=TVConnectionPort.Create;
        ConnPort.PortType:='End';
        ConnPort.X:=100;
        ConnPort.Y:=100;
        ConnPort.AR:='R';
        ConnPort.ConnectedObject:=Obj.Name;
        Connection.PortList.AddObject('End',ConnPort);
        If PortFound Then Begin
          Connection.EndPort:=Port.Name;
          ConnPort.ConnectedPort:=Port.Name;
          Port.Connection:=Connection.Name;
          Port.ConnectionPort:='End';
        End Else Begin
          Connection.EndPort:='';
          ConnPort.ConnectedPort:='';
          Obj.NonPortConnectionList.Add(Connection.Name)
        End;
        Form1.XEdit.Value:=SelectX1w;
        Form1.YEdit.Value:=SelectY1w;
        Form1.LX1Edit.Value:=SelectX1w;
        Form1.LX2Edit.Value:=SelectX2w;
        Form1.LY1Edit.Value:=SelectY1w;
        Form1.LY2Edit.Value:=SelectY2w;
       // ConnectionGUI2Scene;
        Scene.ConnectionAttr2Style(Connection);
        Scene.UpdateConnectionDisplayList(Connection);
        Scene.VisibleList.AddObject(PrimitiveName,Connection);
        Scene.ExecCommand('DrawConnection '+Connection.Name,ZeroAcc,0);
        UnselectAllBut(PrimitiveName);
        RepaintView;
        Dispatcher.ExecCommand('self::CAD_Scene2GUI');
      end;
      LockBackUpdate:=False;
      LockSelectionUpdate:=False;
      If Form1.AutoButton.Down Then EditMode:='';
      DisplayDebug;
End;

procedure MU_Callout(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var I,N:Longint;
    Callout:TVCallout;
    PrimitiveName:String;
Begin
  DrawRubber;
  RubberDisplayList.Clear;
  If Unit1.Resizing Then Begin Unit1.Resizing:=False;RepaintView;Exit;End;
  If Moving Then Begin Moving:=False;RepaintView;Exit;End;
  Drawing:=False;
  JustDrawing:=False;
  If Abs(SelectX1s-SelectX2s)+Abs(SelectY1s-SelectY2s)<=SamePlaceZone Then Exit; //не создаем пустой объект
  If (Form1.LX1Edit.Value=Form1.LX2Edit.Value)Or(Form1.LY1Edit.Value=Form1.LY2Edit.Value) Then Exit; //не создаем пустой объект
  LockBackUpdate:=True;
  Callout:=TVCallout.Create;
  PrimitiveName:=GetNewName(Scene,Scene.VCalloutList,'');
  Callout.Saveable:=True;
  Scene.VCalloutList.AddObject(PrimitiveName,Callout);
  Callout.Name:=PrimitiveName;
  Form1.CurrentEditingNameEdit.Text:=PrimitiveName;
  Form1.CurrentEditingNameEdit.Enabled:=True;
  Form1.XEdit.Value:=SelectX1w;
  Form1.YEdit.Value:=SelectY1w;
  Form1.LX1Edit.Value:=SelectX1w;
  Form1.LX2Edit.Value:=SelectX2w;
  Form1.LY1Edit.Value:=SelectY1w;
  Form1.LY2Edit.Value:=SelectY2w;
  Form1.BaseObjectEdit.Text:='';
  Form1.BindModeRadioGroup.ItemIndex:=6;
  CalloutGUI2Scene;
  Scene.CalloutStyle2Attr(Callout);
  Scene.UpdateCalloutDisplayList(Callout);
  Scene.VisibleList.AddObject(PrimitiveName,Callout);
 // Scene.ExecCommand('DrawCallout '+Callout.Name,ZeroAcc,0);
  UnselectAllBut(PrimitiveName);
  If Scene.SelectedList.IndexOf(PrimitiveName)<0Then AddItemToSelection(PrimitiveName);
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  RepaintView;
  LockBackUpdate:=False;
  LockSelectionUpdate:=False;
  If Form1.AutoButton.Down Then EditMode:='';
  DisplayDebug;
End;

procedure MU_Curl_Pen(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var Curl,NewCurl:TVCurl;
Begin
  If Form1.AutoButton.Down Then EditMode:='';
    Drawing:=False;
    If Form1.AutoSimplifyButton.Down Then Begin
      If Form1.CurlList.Count>0 Then Begin
        Curl:=Scene.VCurlList.Objects[Scene.VCurlList.Count-1] As TVCurl;
        NewCurl:=SimplifyCurl(Curl);
        Curl.Free;
        Scene.VCurlList.Objects[Scene.VCurlList.Count-1]:=NewCurl;
      end;
      Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
      Dispatcher.ExecCommand('self::CAD_Scene2GUI');
    end;
    If Form1.CurlList.Count>0 Then Begin // а здесь Form1.CurlList или Scene.VcurlList?
      Curl:=Scene.VCurlList.Objects[Scene.VCurlList.Count-1] As TVCurl;
      E:=GenShift(0,0);
      Curl.Shell:=Scene.RenderShell(Curl.DisplayList,E);
    End;
End;

procedure MU_Curl_Label(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin
  If Form1.AutoButton.Down Then EditMode:='';
End;

procedure MU_Curl_MultiLine(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin
  If Form1.AutoButton.Down Then EditMode:='';
End;

procedure MU_Curl_Line(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var Curl:TVCurl;
    PrimitiveName:String;
    AccObject:TAccObject;
    N:Longint;
Begin
  If Form1.AutoButton.Down Then EditMode:='';
    If Form1.SnapToGridButton.Down Then Begin
      SelectX2s:=CurrentXGs;SelectY2s:=CurrentYGs;
      SelectX2w:=CurrentXGw;SelectY2w:=CurrentYGw;
    end Else Begin
      SelectX2s:=CurrentXs;SelectY2s:=CurrentYs;
      SelectX2w:=CurrentXw;SelectY2w:=CurrentYw;
    End;
    If (Button=mbRight) Then Begin    //стереть огрызок
      JustDrawing:=True;
      Drawing:=False;
      WCanvas.MoveTo(LastXs,LastYs);//удаляем старую резину
      WCanvas.Pen.Mode:=pmnotXOR;
      WCanvas.Pen.Style:=psDot;
      WCanvas.Pen.Color:=Form1.BorderColorButton.ButtonColor;
      WCanvas.Pen.Width:=Form1.WidthButton1.Tag;
      WCanvas.LineTo(SelectX2s,SelectY2s);
      WCanvas.Pen.Mode:=pmCopy;
      WCanvas.Pen.Style:=psSolid;
      Exit;
    End;

    WCanvas.Pen.Color:=Form1.BorderColorButton.ButtonColor;
    If JustDrawing Then Begin  //начало рисования
      WCanvas.MoveTo(SelectX2s,SelectY2s);
      SelectX1s:=SelectX2s;SelectY1s:=SelectY2s;
      SelectX1w:=SelectX2w;SelectY1w:=SelectY2w;
      Form1.LX1Edit.Value:=SelectX1w;Form1.LX2Edit.Value:=SelectX1w;
      Form1.LY1Edit.Value:=SelectY1w;Form1.LY2Edit.Value:=SelectY1w;
      Form1.LdXEdit.Value:=0;Form1.LdYEdit.Value:=0;
      If Form1.SnapToGridButton.Down Then Begin
          Form1.LX1GEdit.Value:=Round(SelectX2w/Form1.GridGapEdit.Value);
          Form1.LY1GEdit.Value:=Round(SelectY2w/Form1.GridGapEdit.Value);
          Form1.LX2GEdit.Value:=Round(SelectX2w/Form1.GridGapEdit.Value);
          Form1.LY2GEdit.Value:=Round(SelectY2w/Form1.GridGapEdit.Value);
          Form1.LdXGEdit.Value:=0;
          Form1.LdYGEdit.Value:=0;
      End;
      LastXs:=SelectX1s;LastYs:=SelectY1s;
      LastXw:=SelectX1w;LastYw:=SelectY1w;
      Curl:=TVCurl.Create;
      Curl.Saveable:=True;
      PrimitiveName:=GetNewName(Scene,Scene.VCurlList,'pen');
      Scene.VCurlList.AddObject(PrimitiveName,Curl);
      Curl.Name:=PrimitiveName;
      Form1.CurrentEditingNameEdit.Text:=PrimitiveName;
      Form1.CurrentEditingNameEdit.Enabled:=True;
      AccObject:=TAccObject.Create;
      AccObject.AcceleratedCommand:=AccelerateCommand('SetColor '+ColorToString(Form1.BorderColorButton.ButtonColor));
      Curl.DisplayList.AddObject('SetColor '+ColorToString(Form1.BorderColorButton.ButtonColor),AccObject);
      AccObject:=TAccObject.Create;
      AccObject.AcceleratedCommand:=AccelerateCommand('SetWidth '+IntToStr(Form1.WidthButton1.Tag));
      Curl.DisplayList.AddObject('SetWidth '+IntToStr(Form1.WidthButton1.Tag),AccObject);
      Scene.View.Add('DrawCurl '+PrimitiveName);
      AccObject:=TAccObject.Create;
      AccObject.AcceleratedCommand:=AccelerateCommand('MoveTo '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w));
      Curl.DisplayList.AddObject('MoveTo '+FloatToStr(SelectX1w)+','+FloatToStr(SelectY1w),AccObject);
      JustDrawing:=False;
      Drawing:=True;
    End Else Begin
      N:=Scene.VCurlList.Count-1;
      Curl:=Scene.VCurlList.Objects[N] As TVCurl;
      AccObject:=TAccObject.Create;
      AccObject.AcceleratedCommand:=AccelerateCommand('LineTo '+FloatToStr(SelectX2w)+','+FloatToStr(SelectY2w));
      Curl.DisplayList.AddObject('LineTo '+FloatToStr(SelectX2w)+','+FloatToStr(SelectY2w),AccObject);
      WCanvas.Pen.Mode:=pmCopy;
      WCanvas.Pen.Style:=psSolid;
      Scene.ExecCommand('DrawCurl '+Curl.Name,ZeroAcc,0);
      E:=GenShift(0,0);
      Curl.Shell:=Scene.RenderShell(Curl.DisplayList,E);
      SelectX1s:=SelectX2s;SelectY1s:=SelectY2s;
      SelectX1w:=SelectX2w;SelectY1w:=SelectY2w;
      Form1.LX1Edit.Value:=SelectX1w;Form1.LX2Edit.Value:=SelectX1w;
      Form1.LY1Edit.Value:=SelectY1w;Form1.LY2Edit.Value:=SelectY1w;
      Form1.LdXEdit.Value:=0;Form1.LdYEdit.Value:=0;
      If Form1.SnapToGridButton.Down Then Begin
               Form1.LX1GEdit.Value:=Round(SelectX1w/Form1.GridGapEdit.Value);
               Form1.LY1GEdit.Value:=Round(SelectY1w/Form1.GridGapEdit.Value);
               Form1.LX2GEdit.Value:=Round(SelectX1w/Form1.GridGapEdit.Value);
               Form1.LY2GEdit.Value:=Round(SelectY1w/Form1.GridGapEdit.Value);
               Form1.LdXGEdit.Value:=0;
               Form1.LdYGEdit.Value:=0;
      End;
      LastXs:=SelectX2s;LastYs:=SelectY2s;
      LastXw:=SelectX2w;LastYw:=SelectY2w;
    end;
    Dispatcher.ExecCommand('self::CAD_Scene2GUI');

End;

procedure MU_Curl_Rect(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin
  If Form1.AutoButton.Down Then EditMode:='';
  MU_Common;
End;

procedure MU_Curl_RRect(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin
  If Form1.AutoButton.Down Then EditMode:='';
  MU_Common;
End;

procedure MU_Curl_Ellipse(Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Begin
  If Form1.AutoButton.Down Then EditMode:='';
  MU_Common;
End;


procedure TForm1.Image1MouseUp(Sender: TObject; Button: TMouseButton;  Shift: TShiftState; X, Y: Integer);
Var Xw,Yw,xw1,xw2,yw1,yw2,NewX,NewY:Extended;
    xws,yws:String;
    Cmd,Buf,ParsedBuf,Selection,BIUS:String;
//    CurlName:String;
    PrimitiveName:String;
    Curl,NewCurl:TVCurl;I,J,K,N:Longint;
    Callout:TVCallout;
    SelHandle:TVSelHandle;
    Obj,Obj1:TVObject;  AnotherEnd,ObjectName:String;
    Port,Port1:TVPort;
    PortFound:Boolean;
    Connection:TVConnection;
    ConnPort:TVConnectionPort;
    AccObject:TAccObject;
    NonAccCommand:String;
    ActiveObject:Boolean;
    List:TStringList;
    MItem:TMenuItem;
    ItemsUnderMouseCount:Longint;
    ItemName:String;
begin
  CurrentXs:=X+Image1.Left;
  CurrentYs:=Y+Image1.Top;
  Drawer.StoW(CurrentXs,CurrentYs,CurrentXw,CurrentYw);
  CurrentXGw:=GridGapEdit.Value*Round(CurrentXw/GridGapEdit.Value);
  CurrentYGw:=GridGapEdit.Value*Round(CurrentYw/GridGapEdit.Value);
  Drawer.WtoS(CurrentXGw,CurrentYGw,CurrentXGs,CurrentYGs);
  If SnapToGridButton.Down Then Begin
    XcoordLabel.Caption:=FloatToStrF(CurrentXGw,ffGeneral,12,6)+'('+FloatToStr(CurrentXGw/GridGapEdit.Value)+')';
    YcoordLabel.Caption:=FloatToStrF(CurrentYGw,ffGeneral,12,6)+'('+FloatToStr(CurrentYGw/GridGapEdit.Value)+')';
    SelectX2w:=CurrentXGw;
    SelectY2w:=CurrentYGw;
    SelectX2s:=CurrentXGs;SelectY2s:=CurrentYGs;
    SelectX2w:=CurrentXGw;SelectY2w:=CurrentYGw;
  end Else Begin
    XcoordLabel.Caption:=FloatToStrF(CurrentXw,ffGeneral,12,6);
    YcoordLabel.Caption:=FloatToStrF(CurrentYw,ffGeneral,12,6);
    SelectX2w:=CurrentXw;
    SelectY2w:=CurrentYw;
    SelectX2s:=CurrentXs;SelectY2s:=CurrentYs;
    SelectX2w:=CurrentXw;SelectY2w:=CurrentYw;
  end;

  If GettingPoint Then Begin
    SelectX1s:=CurrentXs;SelectY1s:=CurrentYs;
    GettingPoint:=False;
    Exit;
  End;

  If (ssCtrl in Shift)And Not(ssAlt in Shift) Then Exit; //Pen style zoom control
  DisplayDebug;
  //showMessage('mouseup');
  Case EditMode Of
  'navigation': Begin MU_Navigation(Button,Shift,X,Y);End;
  'control':    Begin MU_Control(Button,Shift,X,Y);End;
  'edit':       Begin MU_Edit(Button,Shift,X,Y);End;
  'object': Begin MU_Object(Button,Shift,X,Y);End;
  'connection': Begin MU_Connection(Button,Shift,X,Y);End;
  'callout': Begin MU_Callout(Button,Shift,X,Y);End;
  'curl pen': Begin MU_Curl_Pen(Button,Shift,X,Y);End;
  'curl label': Begin MU_Curl_Label(Button,Shift,X,Y);End;
  'curl multiline': Begin MU_Curl_Multiline(Button,Shift,X,Y);End;
  'curl line': Begin MU_Curl_Line(Button,Shift,X,Y);End;
  'curl rect': Begin MU_Curl_Rect(Button,Shift,X,Y);End;
  'curl rrect': Begin MU_Curl_RRect(Button,Shift,X,Y);End;
  'curl ellipse': Begin MU_Curl_Ellipse(Button,Shift,X,Y);End;
  End;


end;

procedure TForm1.Image1MouseWheel(Sender: TObject; Shift: TShiftState;  WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
Var Xw,Yw,S1,S2,Xc1,Xc2,Yc1,Yc2:Extended;
    TName:String; Templ:TVTemplate;
    N:Longint;
begin
  LastWheelTime:=Now;
  WheelTimer.Enabled:=False;
  DrawRubber;
  BasisChanging:=True;
  S1:=ViewScaleEdit.Value;
  If LowerCase(Config.ConfigFile.Values['ZoomMode'])='cad' then
    ViewScaleEdit.Value:=ViewScaleEdit.Value*Power(2,WheelDelta/120*(StrToFloat(Config.ConfigFile.Values['ZoomStep'])))
  Else
    ViewScaleEdit.Value:=ViewScaleEdit.Value/Power(2,WheelDelta/120*(StrToFloat(Config.ConfigFile.Values['ZoomStep'])));
  S2:=ViewScaleEdit.Value;
  If Not TryStrToFloat(ViewXEdit.Text,Xc1) Then Xc1:=0;
  If Not TryStrToFloat(ViewYEdit.Text,Yc1) Then Yc1:=0;
  Xc2:=CurrentXNGw+(Xc1-CurrentXNGw)*S2/S1;
  Yc2:=CurrentYNGw+(Yc1-CurrentYNGw)*S2/S1;
  ViewXEdit.Text:=FloatToStr(Xc2);
  ViewYEdit.Text:=FloatToStr(Yc2);

  //обновляем масштаб текста в выноске

  If InspectorPanel.Visible Then Begin
    LockBackUpdate:=True;
    FontSizeEdit.Value:=Round(FontSizeEdit.Value*S1/S2);
    LockBackUpdate:=False;
  end;
  If RefreshRate>75 Then // если рендер дольше 75мс - ждём ещё событий, если нет - рисуем прямо так
    WheelTimer.Enabled:=True
  Else
    WheelTimer.OnTimer(Nil);
  Handled:=True;
end;

procedure TForm1.AxisButtonClick(Sender: TObject);
begin
  Dispatcher.ExecCommand('self::CAD_UpdateDraw');
end;

procedure TForm1.AddToGroupSpeedButtonClick(Sender: TObject);
Var I,N:Longint;GroupName:String;
    Obj:TVObject;Conn:TVConnection;
    Callout:TVCallout;
    Group:TVGroup;
begin
  If (GroupStringGrid.Row<1) Or (GroupStringGrid.RowCount<2) Then Exit;
  GroupName:=GroupStringGrid.Cells[0,GroupStringGrid.Row];
  N:=Scene.VgroupList.IndexOf(GroupName);
  If N<0 Then Exit; //Error
  Group:=Scene.VGroupList.Objects[N] As TVGroup;
  If ObjectList.Items.Count>0 Then
    For I:=0 To ObjectList.Items.Count-1 Do Begin
      If Not ObjectList.Selected[I] Then Continue;
      N:=Scene.VObjectList.IndexOf(ObjectList.Items[I]);
      Obj:=Scene.VObjectList.Objects[N] As TVObject;
      If Obj.GroupList.IndexOf(GroupName)<0 Then
        Obj.GroupList.AddObject(GroupName,Group);
      If Group.DisplayList.IndexOf(Obj.Name)<0 Then Group.DisplayList.Add(Obj.Name);
    end;
  If ConnectionList.Items.Count>0 Then
    For I:=0 To ConnectionList.Items.Count-1 Do Begin
      If Not ConnectionList.Selected[I] Then Continue;
      N:=Scene.VConnectionList.IndexOf(ConnectionList.Items[I]);
      Conn:=Scene.VConnectionList.Objects[N] As TVConnection;
      If Conn.GroupList.IndexOf(GroupName)<0 Then
        Conn.GroupList.AddObject(GroupName,Group);
      If Group.DisplayList.IndexOf(Conn.Name)<0 Then Group.DisplayList.Add(Conn.Name);
    end;
  If CalloutList.Items.Count>0 Then
    For I:=0 To CalloutList.Items.Count-1 Do Begin
      If Not CalloutList.Selected[I] Then Continue;
      N:=Scene.VCalloutList.IndexOf(CalloutList.Items[I]);
      Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
      If Callout.GroupList.IndexOf(GroupName)<0 Then
        Callout.GroupList.AddObject(GroupName,Group);
      If Group.DisplayList.IndexOf(Callout.Name)<0 Then Group.DisplayList.Add(Callout.Name);
    end;
  Form1.GroupStringGridSelection(GroupStringGrid,GroupStringGrid.Col,GroupStringGrid.Row);
end;

procedure TForm1.AutoButtonClick(Sender: TObject);
begin
  UnselectAllBut('');
  PrepareObjectPropEdit(Nil);
  OpComboBox.Items.Clear;
  OpComboBox.ItemIndex:=-1;
  EditMode:='';
end;

procedure TForm1.ActionListEditorEditingDone(Sender: TObject);
Var Callout:TVCallout;Obj:TVObject;
    I,N:Longint;Buf,ParsedBuf,TemplateName:String;
    Sm,Rm,Scm,tmpm,TransM:TMatrix2D;
begin
  If LockBackUpdate Then Exit;
  If GetTypeByName(Scene,CurrentEditingNameEdit.Text)='callout' Then Begin
    N:=Scene.VCalloutList.IndexOf(CurrentEditingNameEdit.Text);
    If N>=0 Then Begin
      Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
      Callout.ActionList.Clear;
      If ActionListEditor.Strings.Count>0 Then
        For I:=0 To ActionListEditor.Strings.Count-1 Do Begin
          Callout.ActionList.Add(ActionListEditor.Strings[I]);
        end;
    End;
  End;
  If GetTypeByName(Scene,CurrentEditingNameEdit.Text)='object' Then Begin
    N:=Scene.VObjectList.IndexOf(CurrentEditingNameEdit.Text);
    If N>=0 Then Begin
      Obj:=Scene.VObjectList.Objects[N] As TVObject;
      Obj.ActionList.Clear;
      If ActionListEditor.Strings.Count>0 Then
        For I:=0 To ActionListEditor.Strings.Count-1 Do Begin
          Obj.ActionList.Add(ActionListEditor.Strings[I]);
        end;
    End;
  End;

end;

procedure TForm1.ActionMenuButtonClick(Sender: TObject);
Var I,J:Longint;
    Mode,Cmd,ParsedCmd,Buf,ParsedBuf:String;
    Obj:TVObject;
    Conn:TVConnection;
    Callout:TVCallout;
    MItem:TMenuItem;

Begin
  If Sender Is TSpeedButton Then Begin
    ActionMenu.Items.Clear;
    Case GetTypeByName(Scene,SearchEdit.Text) Of
    'object': Begin
                Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(SearchEdit.Text)] As TVObject;
                If Obj.ActionList.Count>0 Then
                  For J:=0 To Obj.ActionList.Count-1 Do Begin
                    MItem:=TMenuItem.Create(Nil);
                    MItem.Caption:=Obj.ActionList.Names[J];
                    MItem.OnClick:=Form1.ActionMenuButton.OnClick;
                    Form1.ActionMenu.Items.Add(MItem);
                  end;
                ActionMenu.Popup;
              End;
    'callout': Begin
                 Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(SearchEdit.Text)] As TVCallout;
                 If Callout.ActionList.Count>0 Then
                   For J:=0 To Callout.ActionList.Count-1 Do Begin
                     MItem:=TMenuItem.Create(Nil);
                     MItem.Caption:=Callout.ActionList.Names[J];
                     MItem.OnClick:=Form1.ActionMenuButton.OnClick;
                     Form1.ActionMenu.Items.Add(MItem);
                   end;
                 ActionMenu.Popup;
               End;
    end;
  End Else Begin
    Case GetTypeByName(Scene,SearchEdit.Text) Of
    'object': Begin
                Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(SearchEdit.Text)] As TVObject;
                Cmd:=(Sender As TMenuItem).Caption;
                J:=Obj.ActionList.IndexOfName(Cmd);
                If J>=0 Then Begin
                  QueueCommand(Obj.ActionList.ValueFromIndex[J]);
                  ActionMenu.Items.Clear;
                end;
              End;
    'callout': Begin
                 Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(SearchEdit.Text)] As TVCallout;
                 J:=Callout.ActionList.IndexOfName((Sender As TMenuItem).Caption);
                 If J>=0 Then Begin
                   QueueCommand(Callout.ActionList.ValueFromIndex[J]);
                   ActionMenu.Items.Clear;
                 end;
               End;
    end;
  End;
End;


procedure TForm1.AddNodeSpeedButtonClick(Sender: TObject);
Var Conn:TVConnection;Port,Port1,Port2:TVConnectionPort;AccObject:TAccObject;
    ObjName:String;
    I,J,N,X1s,Y1s,X2s,Y2s:Longint;
    ProceedWithNewNode:Boolean;
begin
//  If ObjectList.SelCount<>1 Then Exit;
  N:=Scene.VConnectionList.IndexOf(CurrentEditingNameEdit.Text);
  If N<0 Then Exit;
//  ObjName:=ObjectList.Items[ObjectList.ItemIndex];
//  N:=Scene.VObjectList.IndexOf(ObjName);
  Conn:=Scene.VConnectionList.Objects[N] As TVConnection;
//  ConnPortStringGrid.InsertColRow(false,ConnPortStringGrid.Row+1);
//  ConnPortStringGrid.RowCount:=ConnPortStringGrid.RowCount+1;

  GettingPoint:=True;//добавить желтое
  Repeat Application.ProcessMessages Until Not GettingPoint;
  Drawing:=False;JustDrawing:=False;

  AddConnectionNodeAt(Conn,CurrentXs,CurrentYs);

end;

Procedure TForm1.ArrangeDialogMenuItemClick(Sender: TObject);
Begin
{  RenameForm.Caption:='Renaming '+ItemType+' from '+OldName;
  RenameForm.Scene:=Scene;
  RenameForm.NewNameEdit.Text:=OldName;
  RenameForm.ShowModal;   }
  ArrangeForm.Show;
end;

Procedure TForm1.ArrangePlanetMenuItemClick(Sender: TObject);
Var W,H,dx,dy,X,Y,GX,GY,R,dR,Fi,dFi,X0,Y0:Extended;
    I,J,K,M,N,RoundCount:Longint;
    Obj:TVObject;
    Callout:TVCallout;
    Port:TVPort;
    NewShell,SmallShell:TShell;
    ObjName:String;
    List:TStringList;
  Procedure UpdateScreenShell(Drawer:TDrawer);
  Var x1,x2,x3,x4,y1,y2,y3,y4,lx,ly,rx,ry:Extended;
  Begin
    Drawer.StoW(Form1.DrawingPanel.Left+Splitter2.Left,Drawer.Wy+Form1.DrawingPanel.Top,x1,y1);
    Drawer.StoW(Form1.DrawingPanel.Left+Splitter2.Left,0+Form1.DrawingPanel.Top,x2,y2);
    Drawer.StoW(Drawer.Wx+Form1.DrawingPanel.Left,Drawer.Wy+Form1.DrawingPanel.Top,x3,y3);
    Drawer.StoW(Drawer.Wx+Form1.DrawingPanel.Left,0+Form1.DrawingPanel.Top,x4,y4);
    With Scene Do Begin
      ScreenShell.X1:=Math.maxExtended;
      ScreenShell.X2:=-Math.maxExtended+Math.minExtended;
      ScreenShell.Y1:=Math.MaxExtended;
      ScreenShell.Y2:=-Math.maxExtended+Math.minExtended;
      If x1<ScreenShell.X1 Then ScreenShell.X1:=x1;
      If x2<ScreenShell.X1 Then ScreenShell.X1:=x2;
      If x3<ScreenShell.X1 Then ScreenShell.X1:=x3;
      If x4<ScreenShell.X1 Then ScreenShell.X1:=x4;
      If x1>ScreenShell.X2 Then ScreenShell.X2:=x1;
      If x2>ScreenShell.X2 Then ScreenShell.X2:=x2;
      If x3>ScreenShell.X2 Then ScreenShell.X2:=x3;
      If x4>ScreenShell.X2 Then ScreenShell.X2:=x4;
      If y1<ScreenShell.Y1 Then ScreenShell.Y1:=y1;
      If y2<ScreenShell.Y1 Then ScreenShell.Y1:=y2;
      If y3<ScreenShell.Y1 Then ScreenShell.Y1:=y3;
      If y4<ScreenShell.Y1 Then ScreenShell.Y1:=y4;
      If y1>ScreenShell.Y2 Then ScreenShell.Y2:=y1;
      If y2>ScreenShell.Y2 Then ScreenShell.Y2:=y2;
      If y3>ScreenShell.Y2 Then ScreenShell.Y2:=y3;
      If y4>ScreenShell.Y2 Then ScreenShell.Y2:=y4;
    end;
  End;
Begin
  List:=TStringList.Create;
  For I:=1 To Form1.SelectionListEditor.RowCount-1 Do
    If Form1.SelectionListEditor.Cells[0,I]='object' Then
      List.Add(Form1.SelectionListEditor.Cells[1,I]);
  If List.Count>0 Then Begin
    UpdateScreenShell(Scene.Drawer);
    NewShell:=Scene.ScreenShell;
    SmallShell.X1:=(NewShell.X1+NewShell.X2)/2-(NewShell.X2-NewShell.X1)*0.8/2;
    SmallShell.X2:=(NewShell.X1+NewShell.X2)/2+(NewShell.X2-NewShell.X1)*0.8/2;
    SmallShell.Y1:=(NewShell.Y1+NewShell.Y2)/2-(NewShell.Y2-NewShell.Y1)*0.8/2;
    SmallShell.Y2:=(NewShell.Y1+NewShell.Y2)/2+(NewShell.Y2-NewShell.Y1)*0.8/2;
    W:=SmallShell.X2-SmallShell.X1;
    H:=SmallShell.Y2-SmallShell.Y1;
//    ArrangeObjectsByRect(List,'0','0');

   Fi:=0;R:=Min(W,H)/2;
   dFi:=360/List.Count;
   dR:=0;
   X0:=(NewShell.X1+NewShell.X2)/2;
   Y0:=(NewShell.Y1+NewShell.Y2)/2;
   RoundCount:=0;
   For I:=0 To List.Count-1 Do Begin
     X:=X0+R*cos(Fi/180*Pi);
     Y:=Y0+R*Sin(Fi/180*Pi);
     If True {PlaceAtGridCheckBox.Checked} Then Begin
       Gx:=Form1.GridGapEdit.Value*Round(X/Form1.GridGapEdit.Value);
       Gy:=Form1.GridGapEdit.Value*Round(Y/Form1.GridGapEdit.Value);
     End Else Begin
       GX:=X;GY:=Y;
     End;
     ObjName:=List[I];
     If Scene.VObjectList.IndexOf(ObjName)>=0 Then Begin
       Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(ObjName)] As TVObject;
       Scene.MoveObjectTo(Obj,GX,GY,'');
       Scene.UpdateSelHandles(List[I]);
     end Else
       If Scene.VCalloutList.IndexOf(ObjName)>=0 Then Begin
         Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(ObjName)] As TVCallout;
         Scene.MoveCalloutTo(Callout,GX,GY,'');
         Scene.UpdateSelHandles(List[I]);
       end;
      Fi:=Fi+dFi;
//      If SpireRadioButton.Checked Then R:=R+dr
//      Else If Trunc(Fi/360)>RoundCount Then Begin Inc(RoundCount); R:=R+dR;End;
   End;
  End;
  List.Free;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
end;

Procedure TForm1.ArrangeSpeedButtonClick(Sender: TObject);
Begin
   ArrangeForm.Show;
end;

Procedure TForm1.AutoUpdateDelaySpinEditChange(Sender: TObject);
Begin
  If AutoUpdateDelaySpinEdit.Value=0 Then Begin
    UpdateAllSpeedButton.AllowAllUp:=True;
    UpdateAllSpeedButton.Down:=False;
    AutoUpdateTimer.Enabled:=False;
  End Else Begin
    UpdateAllSpeedButton.AllowAllUp:=True;
 //   UpdateAllSpeedButton.Down:=True;
 //   AutoUpdateTimer.Enabled:=False;
    AutoUpdateTimer.Interval:=AutoUpdateDelaySpinEdit.Value;
 //   AutoUpdateTimer.Enabled:=True;
  End;
end;

Procedure TForm1.AutoUpdateDelaySpinEditEditingDone(Sender: TObject);
Begin


end;

Procedure TForm1.AutoUpdateTimerTimer(Sender: TObject);
Begin
  UpdateAll;
end;


procedure TForm1.BGColorButtonClick(Sender: TObject);
begin

end;

Procedure TForm1.CallFilterEditChange(Sender: TObject);
Var I,N:Longint;
begin
  CalloutList.Items.Clear;
  If CallFilterEdit.Text='' Then CalloutList.Items.Assign(Scene.VCalloutList)
  Else
  If Scene.VCalloutList.Count>0 Then
    For I:=0 To Scene.VCalloutList.Count-1 Do
      If Pos(CallFilterEdit.Text,Scene.VCalloutList[I])<>0 Then
        CalloutList.Items.Add(Scene.VCalloutList[I]);
  //restore selection highlight after rebuild of the list
  LockSelectionUpdate:=True;
  If Scene.SelectedList.Count>0 Then
    For I:=0 To Scene.SelectedList.Count-1 Do Begin
      If Scene.SelectedList.Objects[I] Is TVCallout Then Begin
        N:=CalloutList.Items.IndexOf(Scene.SelectedList[I]);
        If N>=0 Then CalloutList.Selected[N]:=True;
      end;
    end;
  LockSelectionUpdate:=False;

end;

procedure TForm1.CalloutListDblClick(Sender: TObject);
begin
  If CalloutList.ItemIndex<0 Then Exit;
  NavigationDst:=CalloutList.Items[CalloutList.ItemIndex];
  NavigatePopupMenu.Popup;
end;

procedure TForm1.CAStyleRadioGroupSelectionChanged(Sender: TObject);
begin
  If LockBackUpdate Then Exit;
  Case CAStyleRadioGroup.ItemIndex Of
  1,2: TextTabSheet.TabVisible:=False;
  Else TextTabSheet.TabVisible:=True;
  End;
  SourceEdit.Text:='';
  CalloutGUI2Scene;
  RepaintView;
end;

procedure TForm1.ConnectionListDblClick(Sender: TObject);
begin
  If ConnectionList.ItemIndex<0 Then Exit;
  NavigationDst:=ConnectionList.Items[ConnectionList.ItemIndex];
  NavigatePopupMenu.Popup;
end;

Procedure TForm1.ConnFilterEditChange(Sender: TObject);
Var I,N:Longint;
begin
  ConnectionList.Items.Clear;
  If ConnFilterEdit.Text='' Then ConnectionList.Items.Assign(Scene.VConnectionList)
  Else
  If Scene.VConnectionList.Count>0 Then
    For I:=0 To Scene.VConnectionList.Count-1 Do
      If Pos(ConnFilterEdit.Text,Scene.VConnectionList[I])<>0 Then
        ConnectionList.Items.Add(Scene.VConnectionList[I]);
  //restore selection highlight after rebuild of the list
  LockSelectionUpdate:=True;
  If Scene.SelectedList.Count>0 Then
    For I:=0 To Scene.SelectedList.Count-1 Do Begin
      If Scene.SelectedList.Objects[I] Is TVConnection Then Begin
        N:=ConnectionList.Items.IndexOf(Scene.SelectedList[I]);
        If N>=0 Then ConnectionList.Selected[N]:=True;
      end;
    end;
  LockSelectionUpdate:=False;

end;

Procedure TForm1.ConnPortStringGridDblClick(Sender: TObject);
Begin
  If ConnPortStringGrid.Col=0 Then
    If ConnPortStringGrid.Cells[0,ConnPortStringGrid.Row]='Node' Then
       ConnPortStringGrid.Cells[0,ConnPortStringGrid.Row]:='Text'
    Else
      ConnPortStringGrid.Cells[0,ConnPortStringGrid.Row]:='Node';

  If ConnPortStringGrid.Col=1 Then
    If ConnPortStringGrid.Cells[ConnPortStringGrid.Col,ConnPortStringGrid.Row]='R' Then
       ConnPortStringGrid.Cells[ConnPortStringGrid.Col,ConnPortStringGrid.Row]:='A'
    Else
      ConnPortStringGrid.Cells[ConnPortStringGrid.Col,ConnPortStringGrid.Row]:='R';
  If (ConnPortStringGrid.Col=2) Or (ConnPortStringGrid.Col=3) Then
    ConnPortStringGrid.EditorMode:=True;
  If (ConnPortStringGrid.Col=4)And(ConnPortStringGrid.Cells[0,ConnPortStringGrid.Row]='Text') Then Begin
     ConnPortStringGrid.Options:=ConnPortStringGrid.Options+[goEditing];//+[goAlwaysShowEditor];
     ConnPortStringGrid.EditorMode:=True;
   end;
end;

procedure TForm1.ConnPortStringGridEditingDone(Sender: TObject);
begin
   If (ConnPortStringGrid.Col=4)And(ConnPortStringGrid.Cells[0,ConnPortStringGrid.Row]='Text') Then Begin
     ConnPortStringGrid.Options:=ConnPortStringGrid.Options-[goEditing];
     ConnPortStringGrid.EditorMode:=False;
     ConnectionGUI2Scene;
     Drawer.Updated:=True;
     RepaintView;
   end;
end;

procedure TForm1.CurlListDblClick(Sender: TObject);
begin
  If CurlList.ItemIndex<0 Then Exit;
  NavigationDst:=CurlList.Items[CurlList.ItemIndex];
  NavigatePopupMenu.Popup;
end;

Procedure TForm1.DelNodeSpeedButtonClick(Sender: TObject);
Var Conn:TVConnection;Port,Port1,Port2:TVConnectionPort;AccObject:TAccObject;
    ObjName:String;
    I,J,N,X1s,Y1s,X2s,Y2s:Longint;
    ProceedWithNewNode:Boolean;
Begin
  N:=Scene.VConnectionList.IndexOf(CurrentEditingNameEdit.Text);
   If N<0 Then Exit;
 //  ObjName:=ObjectList.Items[ObjectList.ItemIndex];
 //  N:=Scene.VObjectList.IndexOf(ObjName);
   Conn:=Scene.VConnectionList.Objects[N] As TVConnection;
  If ConnPortStringGrid.Cells[0,ConnPortStringGrid.Row]='Node' Then Begin
    Scene.DeleteSelHandles(Conn.Name);
    Port:=Conn.PortList.Objects[ConnPortStringGrid.Row-1] As TVConnectionPort;
    Port.Free;
    Conn.PortList.Delete(ConnPortStringGrid.Row-1);
    PrepareConnectionPropEdit(Conn);
    Scene.UpdateConnectionDisplayList(Conn);
    Scene.CreateSelHandles(Conn.Name);
    Scene.ExecCommand('DrawConnection '+Conn.Name,ZeroAcc,0);
    Drawer.Updated:=True;
    RepaintView;
  End;
end;

procedure TForm1.EndingStyleGroupBoxClick(Sender: TObject);
begin

end;


procedure TForm1.GotoEditorMenuItemClick(Sender: TObject);
Var Obj:TVObject;
    Callout:TVCallout;
    N:Longint;
begin
  Case Scene.GetTypeByName(NavigationDst) of
  'object': Begin
              N:=Scene.VObjectList.IndexOf(NavigationDst);
              Obj:=Scene.VObjectList.Objects[N] As TVObject;
              PrepareObjectPropEdit(Obj);
            End;
  'callout': Begin
              N:=Scene.VCalloutList.IndexOf(NavigationDst);
              Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
              PrepareCalloutPropEdit(Callout);
            End;
  End;
end;

Procedure TForm1.GotoFullScreenMenuItemClick(Sender: TObject);
Begin
  NavigateToItemZoom(NavigationDst);
end;

procedure TForm1.GotoKeepScaleMenuItemClick(Sender: TObject);
begin
  NavigateToItem(NavigationDst);
end;

Procedure TForm1.GoToStyleComboBoxChange(Sender: TObject);
Begin

end;

Procedure TForm1.Image1MouseEnter(Sender: TObject);
Begin
  If (EditMode='object') And (ObjStyleRadioGroup.ItemIndex=0) Then JustDrawing:=True;
end;

procedure TForm1.ArrangeRectMenuItemClick(Sender: TObject);
Var I:Longint;
    List:TStringList;
  Procedure UpdateScreenShell(Drawer:TDrawer);
  Var x1,x2,x3,x4,y1,y2,y3,y4,lx,ly,rx,ry:Extended;
  Begin
    Drawer.StoW(Form1.DrawingPanel.Left+Splitter2.Left,Drawer.Wy+Form1.DrawingPanel.Top,x1,y1);
    Drawer.StoW(Form1.DrawingPanel.Left+Splitter2.Left,0+Form1.DrawingPanel.Top,x2,y2);
    Drawer.StoW(Drawer.Wx+Form1.DrawingPanel.Left,Drawer.Wy+Form1.DrawingPanel.Top,x3,y3);
    Drawer.StoW(Drawer.Wx+Form1.DrawingPanel.Left,0+Form1.DrawingPanel.Top,x4,y4);
    With Scene Do Begin
      ScreenShell.X1:=Math.maxExtended;
      ScreenShell.X2:=-Math.maxExtended+Math.minExtended;
      ScreenShell.Y1:=Math.MaxExtended;
      ScreenShell.Y2:=-Math.maxExtended+Math.minExtended;
      If x1<ScreenShell.X1 Then ScreenShell.X1:=x1;
      If x2<ScreenShell.X1 Then ScreenShell.X1:=x2;
      If x3<ScreenShell.X1 Then ScreenShell.X1:=x3;
      If x4<ScreenShell.X1 Then ScreenShell.X1:=x4;
      If x1>ScreenShell.X2 Then ScreenShell.X2:=x1;
      If x2>ScreenShell.X2 Then ScreenShell.X2:=x2;
      If x3>ScreenShell.X2 Then ScreenShell.X2:=x3;
      If x4>ScreenShell.X2 Then ScreenShell.X2:=x4;
      If y1<ScreenShell.Y1 Then ScreenShell.Y1:=y1;
      If y2<ScreenShell.Y1 Then ScreenShell.Y1:=y2;
      If y3<ScreenShell.Y1 Then ScreenShell.Y1:=y3;
      If y4<ScreenShell.Y1 Then ScreenShell.Y1:=y4;
      If y1>ScreenShell.Y2 Then ScreenShell.Y2:=y1;
      If y2>ScreenShell.Y2 Then ScreenShell.Y2:=y2;
      If y3>ScreenShell.Y2 Then ScreenShell.Y2:=y3;
      If y4>ScreenShell.Y2 Then ScreenShell.Y2:=y4;
    end;
  End;
begin
  List:=TStringList.Create;
  For I:=1 To Form1.SelectionListEditor.RowCount-1 Do
    If Form1.SelectionListEditor.Cells[0,I]='object' Then
      List.Add(Form1.SelectionListEditor.Cells[1,I]);
  If List.Count>0 Then Begin
    UpdateScreenShell(Scene.Drawer);
    ArrangeObjectsByRect(List,'0','0');
    For I:=0 To List.Count-1 Do
      Scene.UpdateSelHandles(List[I]);
  End;
  List.Free;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
end;

procedure TForm1.ImportCommandFileMenuItemClick(Sender: TObject);
Var I:Longint;
    F:Text;
    Cmd:String;
begin
   If Not OpenSceneDialog.Execute Then Exit;
   AssignFile(F,OpenSceneDialog.FileName);
   Reset(F);
   While Not(EOF(F)) Do Begin
     Readln(F,Cmd);
     Dispatcher.ExecCommand(Cmd);
   end;
   CloseFile(F);
end;

Procedure TForm1.Label15MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
Begin
  If BaseObjectEdit.Text='' Then Exit;
  If Button=mbRight Then Begin
    NavigationDst:=BaseObjectEdit.Text;
    NavigatePopupMenu.Popup;
  End;
  If Button=mbLeft Then Begin
    NavigationDst:=BaseObjectEdit.Text;
    GotoEditorMenuItemClick(Sender);
  End;

end;

Procedure TForm1.LoadFromWebMenuItemClick(Sender: TObject);
Begin
  HTTPURLForm.ShowModal;
  If HTTPURLForm.ModalResult=mrOk Then Begin
    LoadDocument(HTTPURLForm.URLEdit.Text);
    Form1.Caption:=TitleString+' '+HTTPURLForm.URLEdit.Text;
    GroupStringGridSelection(GroupStringGrid,GroupStringGrid.Col,GroupStringGrid.Row);
    ZoomToScene;
  End;
end;

Procedure TForm1.OpComboBoxChange(Sender: TObject);
Begin
  If EditMode='navigation' Then NavigationMode:=OpComboBox.Text;
end;


Procedure TForm1.OperationMenuSpeedButtonClick(Sender: TObject);
Begin
  OperationMenuInvokedFromButton:=True;
  OperationMenu.Popup;
end;

Procedure TForm1.LX1EditClick(Sender: TObject);
Begin
  UpdateFrom:=updX1;
end;

Procedure TForm1.LX1EditKeyPress(Sender: TObject; Var Key: char);
Begin
  UpdateFrom:=updX1;
end;

Procedure TForm1.LX1EditMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
Begin
  UpdateFrom:=updX1;
  LX1EditChange(Sender);
end;

procedure TForm1.LX1EditMouseEnter(Sender: TObject);
begin
   UpdateFrom:=updX1;
end;

Procedure TForm1.LX2EditClick(Sender: TObject);
Begin
  UpdateFrom:=updX2;
end;

Procedure TForm1.LX2EditKeyPress(Sender: TObject; Var Key: char);
Begin
  UpdateFrom:=updX2;
end;

Procedure TForm1.LX2EditMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
Begin
  UpdateFrom:=updX2;
  LX2EditChange(Sender);
end;

Procedure TForm1.LY1EditClick(Sender: TObject);
Begin
   UpdateFrom:=updY1;
end;

Procedure TForm1.LY1EditKeyPress(Sender: TObject; Var Key: char);
Begin
  UpdateFrom:=updY1;
end;

Procedure TForm1.LY1EditMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
Begin
  UpdateFrom:=updY1;
  LY1EditChange(Sender);
end;

Procedure TForm1.LY2EditClick(Sender: TObject);
Begin
  UpdateFrom:=updY2;
end;

Procedure TForm1.LY2EditKeyPress(Sender: TObject; Var Key: char);
Begin
  UpdateFrom:=updY2;
end;

Procedure TForm1.LY2EditMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
Begin
  UpdateFrom:=updY2;
  LY2EditChange(Sender);
end;

Procedure TForm1.BookmarkOpenButtonClick(Sender: TObject);
Var I:Longint;
Begin
  If Not BookMarkOpenDialog.Execute Then Exit;
  Try
    BookMarks.LoadFromFile(BookMarkOpenDialog.FileName);
    BookMarkListBox.Items.Clear;
    For I:=0 To Bookmarks.Count-1 Do Begin
      BookMarkListBox.Items.Add(BookMarks.Names[I]);
    end;
  Except
    ShowMessage('can''t read file: '+BookMarkOpenDialog.FileName);
  End;
end;

Procedure TForm1.BookMarkSaveButtonClick(Sender: TObject);
Begin
  If not BookmarkSaveDialog.Execute Then exit;
  Try
    BookMarks.SaveToFile(BookmarkSaveDialog.FileName);
  Except
    ShowMessage('Can''t write file: '+BookmarkSaveDialog.FileName);
  End;
end;

procedure TForm1.BookmarkSpeedButtonClick(Sender: TObject);
begin
  BookmarkPanel.Visible:=BookmarkSpeedButton.Down;
  If Not BookmarkSpeedButton.Down Then Begin
    BookmarkForm.Hide;
    DetachBookmarkSpeedButton.Down:=False;
    DetachBookmarkSpeedButtonClick(Sender);
  end;
end;

procedure TForm1.CalloutListKeyPress(Sender: TObject; var Key: char);
begin
    If Not NavigateButton.Down Then
    If CalloutList.SelCount=1 Then Begin
      CurrentEditingNameEdit.Text:=CalloutList.Items[CalloutList.ItemIndex];
      EditButton.Down:=True;
      EditCalloutButtonClick(Sender);
    end Else Begin
      EditButton.Down:=True;
     // XYASPanel.Hide;
    End;
end;

procedure TForm1.CalloutListMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
 {   If Not NavigateButton.Down Then
    If CalloutList.SelCount=1 Then Begin
      CurrentEditingNameEdit.Text:=CalloutList.Items[CalloutList.ItemIndex];
      EditButton.Down:=True;
      EditCalloutButtonClick(Sender);
    end Else Begin
      EditButton.Down:=True;
     // XYASPanel.Hide;
    End;}
end;

Procedure TForm1.CalloutListSelectionChange(Sender: TObject; User: boolean);
Var CalloutName:String;
    Callout:TVCallout;I,J,N:Longint;
    Sm,Rm,Scm,tmpm,OldTransM:TMatrix2D;
    Buf,ParsedBuf:String;
begin
  If LockSelectionUpdate Then Exit;
  If Not CalloutButton.Down Then Begin
    For I:=0 To CalloutList.Items.Count-1 Do Begin
      If (Scene.SelectedList.IndexOf(CalloutList.Items[I])<0)And(CalloutList.Selected[I]) Then Begin
       //свежевыбранный
       AddItemToSelection(CalloutList.Items[I]);
       Continue;
      End;
      If (Scene.SelectedList.IndexOf(CalloutList.Items[I])>=0)And(Not CalloutList.Selected[I]) Then Begin
        //свежеудаленный
        RemoveItemFromSelection(CalloutList.Items[I]);
        Continue;
      End;
    End;
  End;

  TPGEditMemo.Clear;
  TPGEditForm.Caption:='TPG edit: ';
  If CalloutList.Count>0 Then
    For I:=0 To CalloutList.Count-1 Do Begin
      CalloutName:=CalloutList.Items[I];
      N:=Scene.VCalloutList.IndexOf(CalloutName);
      Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
      If CalloutList.Selected[I] Then Begin
          TPGEditForm.Caption:=TPGEditForm.Caption+CalloutName+' ';
          TPGEditMemo.Lines.AddStrings(Callout.DisplayList);
//        End;
        If DrawingPanel.Color=clBlack Then Scene.Drawer.Canvas.Pen.Mode:=pmWhite//pmNotCopy;
        Else Scene.Drawer.Canvas.Pen.Mode:=pmNotCopy;//pmNotCopy;
   ////////     Scene.ExecCommand('DrawCallout '+CalloutName,ZeroAcc,0);
      end Else Begin
        Scene.Drawer.Canvas.Pen.Mode:=pmCopy;
   ///////     Scene.ExecCommand('DrawCallout '+CalloutName,ZeroAcc,0);
      end;
    end;
  Scene.Drawer.Canvas.Pen.Mode:=pmCopy;
  If Not NavigateButton.Down Then
      If CurlList.SelCount+ObjectList.SelCount+CalloutList.SelCount=0 Then Begin
        ToolOptionsPanel.Hide;
        Form1.Splitter2.Hide;
      end;

      If CurlList.SelCount+ObjectList.SelCount+CalloutList.SelCount=1 Then Begin
        ToolOptionsPanel.Show;
        Form1.Splitter2.Show;
        InspectorPanel.Show;
        N:=Scene.VCalloutList.IndexOf(CalloutList.Items[CalloutList.ItemIndex]);
        Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
        PrepareCalloutPropEdit(Callout);
      end;
      If CurlList.SelCount+ObjectList.SelCount+CalloutList.SelCount>1 Then Begin
        ToolOptionsPanel.Show;
        Form1.Splitter2.Show;
        InspectorPanel.Hide;
        SelectionListPanel.Show;
      end;
end;

procedure TForm1.CurrentEditingNameEditClick(Sender: TObject);
Var N,I,J,K:Longint;
    Curl:TVCurl;
    Conn:TVConnection;
    Obj,Obj1,Obj2:TVObject;
    Callout:TVCallout;
    Group:TVGroup;
    Port:TVPort;
    ConnPort:TVConnectionPort;
    SelHandle:TVSelHandle;
    OldName,ItemType:String;
begin
  If CurrentEditingNameEdit.Text='' Then Exit;
  OldName:=CurrentEditingNameEdit.Text;
  ItemType:=GetTypeByName(Scene,OldName);
  RenameForm.Caption:='Renaming '+ItemType+' from '+OldName;
  RenameForm.Scene:=Scene;
  RenameForm.NewNameEdit.Text:=OldName;
  RenameForm.ShowModal;
  CurrentEditingNameEdit.Text:=RenameForm.NewNameEdit.Text;
  Case ItemType Of
  'curl': If RenameForm.ModalResult=mrOk Then Begin
            N:=Scene.VCurlList.IndexOf(OldName);
            Curl:=Scene.VCurlList.Objects[N] As TVCurl;
            Curl.Name:=RenameForm.NewNameEdit.Text;
            Scene.VCurlList[N]:=RenameForm.NewNameEdit.Text;
            N:=CurlList.Items.IndexOf(OldName);
            CurlList.Items[N]:=RenameForm.NewNameEdit.Text;
          End;
  'object': If RenameForm.ModalResult=mrOk Then Begin
              N:=Scene.VObjectList.IndexOf(OldName);
              Obj:=Scene.VObjectList.Objects[N] As TVObject;
              Scene.VObjectList[N]:=RenameForm.NewNameEdit.Text;
              Obj.Name:=RenameForm.NewNameEdit.Text;
              N:=ObjectList.Items.IndexOf(OldName);
              ObjectList.Items[N]:=RenameForm.NewNameEdit.Text;
              If Scene.View.Count>0 Then
                For N:=0 To Scene.View.Count-1 Do Begin
                  If Scene.View[N]=('DrawObject '+OldName) Then Scene.View[N]:='DrawObject '+Obj.Name;
                end;
               //Добавить обновление имени в подключенных связях
               If Obj.PortList.Count>0 Then
                 For I:=0 To Obj.PortList.Count-1 Do Begin
                   Port:=Obj.PortList.Objects[I] As TVPort;
                   N:=Scene.VConnectionList.IndexOf(Port.Connection);
                   If N>=0 Then Begin
                     Conn:=Scene.VConnectionList.Objects[N] As TVConnection;
                     If Conn.StartObj=OldName Then Conn.StartObj:=Obj.Name;
                     If Conn.EndObj=OldName Then Conn.EndObj:=Obj.Name;
                     If Conn.PortList.Count>0 Then
                       For J:=0 To Conn.PortList.Count-1 Do Begin
                         ConnPort:=Conn.PortList.Objects[J] As TVConnectionPort;
                         If ConnPort.ConnectedObject=OldName Then ConnPort.ConnectedObject:=Obj.Name;
                       end;
                   end;
                 end;
               //обновление имени в группах
               If Obj.GroupList.Count>0 Then
                 For I:=0 To Obj.GroupList.Count-1 Do Begin
                   N:=Scene.VGroupList.IndexOf(Obj.GroupList[I]);
                   If N>=0 Then Group:=Scene.VGroupList.Objects[N] As TVGroup;
                   K:=Group.DisplayList.IndexOf(OldName);
                   Group.DisplayList[K]:=Obj.Name;
                 end;
               //обновление имени в выносках
               If Obj.RelatedCAList.Count>0 Then
                 For I:=0 To Obj.RelatedCAList.Count-1 Do Begin
                   Callout:=Obj.RelatedCAList.Objects[I] As TVCallout;
                   Callout.RelatedObj:=Obj.Name;
                 end;
            End;
  'connection': If RenameForm.ModalResult=mrOk Then Begin
                  N:=Scene.VConnectionList.IndexOf(OldName);
                  Conn:=Scene.VConnectionList.Objects[N] As TVConnection;
                  Conn.Name:=RenameForm.NewNameEdit.Text;
                  Scene.VConnectionList[N]:=RenameForm.NewNameEdit.Text;
                  N:=ConnectionList.Items.IndexOf(OldName);
                  ConnectionList.Items[N]:=RenameForm.NewNameEdit.Text;
                 //обновить имя у связанных объектов
             End;
  'callout': If RenameForm.ModalResult=mrOk Then Begin
               N:=Scene.VCalloutList.IndexOf(OldName);
               Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
               Callout.Name:=RenameForm.NewNameEdit.Text;
               Scene.VCalloutList[N]:=RenameForm.NewNameEdit.Text;
               N:=CalloutList.Items.IndexOf(OldName);
               CalloutList.Items[N]:=RenameForm.NewNameEdit.Text;
               //обновление имени в RelatedCA
               If Callout.RelatedObj<>'' Then Begin
                 N:=Scene.VObjectList.IndexOf(Callout.RelatedObj);
                 If N>=0 Then Begin
                   Obj:=Scene.VObjectList.Objects[N] As TVObject;
                   If Obj.RelatedCAList.Count>0 Then
                     For I:=0 To Obj.RelatedCAList.Count-1 Do Begin
                       If Obj.RelatedCAList[I]=OldName Then Obj.RelatedCAList[I]:=Callout.Name;
                     end;
                 end;
               end;
             End;
  End;

  If Scene.VHandleList.Count>0 Then
    For I:=0 To Scene.VHandleList.Count-1 Do Begin
      SelHandle:=Scene.VHandleList.Objects[I] As TVSelHandle;
      If SelHandle.Name=OldName Then SelHandle.Name:=RenameForm.NewNameEdit.Text;
    end;

  If Form1.SelectionListEditor.RowCount>1 Then
    For I:=Form1.SelectionListEditor.RowCount-1 DownTo 1 Do
      If Form1.SelectionListEditor.Cells[1,I]=OldName Then
        Form1.SelectionListEditor.Cells[1,I]:=RenameForm.NewNameEdit.Text;
  Form1.SceneMemo.Lines.Assign(Scene.View);
end;


Procedure TForm1.DelItemButtonClick(Sender: TObject);
begin
  DeleteSelection;
end;

procedure TForm1.DetachBookmarkSpeedButtonClick(Sender: TObject);
begin
  If DetachBookmarkSpeedButton.Down Then Begin
    BookmarkSpeedButton.Down:=True;
    BookmarkPanel.Parent:=BookmarkForm;
    BookmarkPanel.Align:=alClient;
    BookmarkPanel.Show;
    BookmarkForm.Show;
  end Else Begin
    BookmarkPanel.Align:=alLeft;
    BookmarkPanel.Parent:=DrawingPanel;
    If BookmarkSpeedButton.Down Then Begin
      BookmarkForm.Hide;
      BookmarkPanel.Show;
    end Else Begin
      BookmarkForm.Hide;
      BookmarkPanel.Hide;
    end;
  end;
end;

procedure TForm1.DisplayStatsCheckBoxChange(Sender: TObject);
begin
  RefreshSpeedLabel.Left:=Splitter2.Left+20;
  RefreshSpeedLabel.Visible:=SettingsForm.DisplayStatsCheckBox.Checked;
end;

Procedure TForm1.EditCalloutButtonClick(Sender: TObject);
Var Callout:TVCallout;Port:TVPort;
    CalloutName:String;
    I,N:Longint;
begin
  If CalloutList.SelCount<>1 Then Exit;
    CalloutName:=CalloutList.Items[CalloutList.ItemIndex];
    N:=Scene.VObjectList.IndexOf(CalloutName);
    Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
    Scene.CalloutAttr2Style(Callout);
    PrepareCalloutPropEdit(Callout);
end;

procedure TForm1.FindObjectSpeedButtonClick(Sender: TObject);
Var ObjectsUnder:TStringList;
    I,K,N,Index,ObjCount:Longint;
    ObjName:String;
    Callout:TVCallout;
begin
  GettingPoint:=True;
  Repeat Application.ProcessMessages Until Not GettingPoint;
  ObjectsUnder:=Scene.BuildUnderMouse(CurrentXw,CurrentYw,SamePlaceZone);
  ObjCount:=0;
  For I:=0 To ObjectsUnder.Count-1 Do
    If GetTypeByName(Scene,ObjectsUnder[I])='object' Then Begin
      Inc(ObjCount);
      ObjName:=ObjectsUnder[I];
    End;
  If ObjCount=1 Then Begin
    BaseObjectEdit.Text:=ObjName;
    BaseObjectEditEditingDone(nil);
  end;
  ObjectsUnder.Free;
end;

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
Var ShortCut,ActionName:String;
    I,J:Longint;
    Handled:Boolean;
    MousePos:TPoint;
    wx1,wy1:Extended;
begin
  ActionName:='';
  ShortCut:=KeyAndShiftStateToKeyString(Key,Shift);
  For J:=1 To SettingsForm.ShortcutStringGrid.ColCount-1 Do
    For I:=1 To SettingsForm.ShortcutStringGrid.RowCount-1 Do
      If SettingsForm.ShortcutStringGrid.Cells[J,I]=ShortCut Then Begin
        ActionName:=SettingsForm.ShortcutStringGrid.Cells[0,I];
        Break; Break;
      end;
  MousePos.x:=Image1.Width Div 2;  MousePos.y:=Image1.Height Div 2;
  Case ActionName Of
  'Redraw': Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
  'Zoom in': //Image1MouseWheel(Sender,Shift,-150,MousePos,Handled);
             Begin
               LockCoordUpdate:=True;
               ViewScaleEdit.Value:=ViewScaleEdit.Value/Power(2,(StrToFloat(Config.ConfigFile.Values['ZoomStep'])));
               FontSizeEdit.Value:=Round(FontSizeEdit.Value*Power(2,(StrToFloat(Config.ConfigFile.Values['ZoomStep']))));
               Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
               LockCoordUpdate:=False;
             end;
  'Zoom out': //Image1MouseWheel(Sender,Shift,150,MousePos,Handled);
              Begin
                LockCoordUpdate:=True;
                ViewScaleEdit.Value:=ViewScaleEdit.Value*Power(2,(StrToFloat(Config.ConfigFile.Values['ZoomStep'])));
                FontSizeEdit.Value:=Round(FontSizeEdit.Value/Power(2,(StrToFloat(Config.ConfigFile.Values['ZoomStep']))));
                Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
                LockCoordUpdate:=False;
              end;
  'Pan left': Begin
                LockCoordUpdate:=True;
                Scene.Drawer.StoW((Drawer.wx div 2)-(Drawer.wx div 10),Drawer.Wy div 2,wx1,wy1);
                ViewXEdit.Value:=wx1;
                ViewYEdit.Value:=wy1;
                Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
                LockCoordUpdate:=False;
              End;
  'Pan right': Begin
                 LockCoordUpdate:=True;
                 Scene.Drawer.StoW((Drawer.wx div 2)+(Drawer.wx div 10),Drawer.Wy div 2,wx1,wy1);
                 ViewXEdit.Value:=wx1;
                 ViewYEdit.Value:=wy1;
                 Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
                 LockCoordUpdate:=False;
               End;
  'Pan up': Begin
              LockCoordUpdate:=True;
              Scene.Drawer.StoW(Drawer.wx div 2,(Drawer.wy div 2)-(Drawer.wy div 10),wx1,wy1);
              ViewXEdit.Value:=wx1;
              ViewYEdit.Value:=wy1;
              Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
              LockCoordUpdate:=False;
            End;
  'Pan down': Begin
                LockCoordUpdate:=True;
                Scene.Drawer.StoW(Drawer.wx div 2,(Drawer.wy div 2)+(Drawer.wy div 10),wx1,wy1);
                ViewXEdit.Value:=wx1;
                ViewYEdit.Value:=wy1;
                Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
                LockCoordUpdate:=False;
              End;
  'Pan screen left': Begin PanLeftButtonClick(nil); End;
  'Pan screen right': Begin PanRightButtonClick(nil);End;
  'Pan screen up': Begin End;
  'Pan screen down': Begin End;
  'Navigation mode': Begin NavigateButton.Down:=True;PenButtonClick(NavigateButton);End;
  'Selection/Edit mode':Begin EditButton.Down:=True;PenButtonClick(EditButton);End;
  'Pen': Begin PenButton.Down:=True;PenButtonClick(PenButton);End;
  'Object': Begin ObjButton.Down:=True;PenButtonClick(ObjButton);End;
  'Link': Begin ConnectorButton.Down:=True;PenButtonClick(ConnectorButton);End;
  'Callout': Begin CalloutButton.Down:=True;PenButtonClick(CalloutButton);End;
  'Copy': Begin If Form1.ActiveControl=DrawingPanel Then CopySelection;End;
  'Paste': Begin If Form1.ActiveControl=DrawingPanel Then PasteSelection;End;
  'Delete': Begin // If (Form1.ActiveControl is TEdit)or(Form1.ActiveControl is TMemo) Then Exit;
      If (Form1.ActiveControl=DrawingPanel) Or
         (Form1.ActiveControl=ObjectList) Or
         (Form1.ActiveControl=CurlList) Or
         (Form1.ActiveControl=CalloutList) Or
         (Form1.ActiveControl=ConnectionList) Or
         (Form1.ActiveControl=ObjectList) Or
         (Form1.ActiveControl=GroupStringGrid) Or
         (Form1.ActiveControl=GroupItemsList) Or
         (Form1.ActiveControl=SceneMemo) Or
         (Form1.ActiveControl=SelectionListEditor)
      Then DelItemButtonClick(Nil);End;
  'Update All': Begin Dispatcher.QueueCommand('self::CAD_UpdateAll');End;
  'Create related callout': Begin
                If GetTypeByName(Scene,CurrentEditingNameEdit.Text)='object' Then Begin
                  LockBackUpdate:=True;
                  CreateRelCASpeedButtonClick(Nil);
                  InspectorPageControl.ActivePage:=TextTabSheet;
                  TextMemo.SetFocus;
                  LockBackUpdate:=False;
                End;
              End;
  end;
 {//что это было? предотвращение случайного зума-скролла заодно с другим действием, если фокус неудачно остановился на контролях?
  If (Form1.ActiveControl=ViewXEdit) Or
     (Form1.ActiveControl=ViewYEdit) Or
     (Form1.ActiveControl=ViewScaleEdit) Or
     (Form1.ActiveControl=ViewAngleEdit)
  Then
    Key:=0;}
end;

procedure TForm1.FullScreenSpeedButtonClick(Sender: TObject);
Var M:TMonitor;
begin
  If FullScreenSpeedButton.Down Then Begin
    M:=Screen.MonitorFromPoint(Point(Form1.Left,Form1.Top));
    Form1.BorderStyle:=bsNone;
    Form1.Left:=M.Left;//  Screen.WorkAreaLeft;
    Form1.Top:=M.Top;//Screen.WorkAreaTop;
    Form1.Width:=M.Width;//.WorkAreaWidth;
    Form1.Height:=M.Height;// .WorkAreaHeight;

  end Else Begin
    Form1.BorderStyle:=bsSizeable;
  end;
end;

procedure TForm1.GotoCallButtonClick(Sender: TObject);
Var CalloutName:String;
    Callout:TVCallout;
    I,J,N:Longint;
    X1,Y1,X2,Y2:Extended;
begin
  X1:=+MaxExtended;X2:=-MaxExtended;
  Y1:=+MaxExtended;Y2:=-MaxExtended;
  If CalloutList.Count=0 Then Exit;
  For I:=0 To CalloutList.Count-1 Do Begin
    If CalloutList.Selected[I] Then Begin
      CalloutName:=CalloutList.Items[I];
      N:=Scene.VCalloutList.IndexOf(CalloutName);
      Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
      X1:=Min(X1,Callout.Shell.X1);Y1:=Min(Y1,Callout.Shell.Y1);
      X2:=Max(X2,Callout.Shell.X2);Y2:=Max(Y2,Callout.Shell.Y2);
    End;
  End;
  N:=Scene.VCalloutList.IndexOf(SearchEdit.Text);
  If N>=0 Then Begin
    Callout:=Scene.VCalloutList.Objects[N] As TVCallout;
    X1:=Min(X1,Callout.Shell.X1);Y1:=Min(Y1,Callout.Shell.Y1);
    X2:=Max(X2,Callout.Shell.X2);Y2:=Max(Y2,Callout.Shell.Y2);
  End;
  BasisChanging:=True;
  ViewXEdit.Value:=(X1+X2)/2;
  ViewYEdit.Value:=(Y1+Y2)/2;
  If (X2-X1)/Scene.Drawer.Wx > (Y2-Y1)/Scene.Drawer.Wy
  Then ViewScaleEdit.Value:=(X2-X1)*1.01001/Scene.Drawer.Wx
  Else ViewScaleEdit.Value:=(Y2-Y1)*1.01001/Scene.Drawer.Wy;
  BasisChanging:=False;
  Dispatcher.ExecCommand('self::CAD_UpdateCoordBase');
end;

procedure TForm1.GotoSearchSpeedButtonClick(Sender: TObject);
Var Obj:TVObject;
    Callout:TVCallout;
    Connection:TVConnection;
    I:Longint;
begin
  If SearchEdit.Text='' Then Exit;
  SearchListBox.Hide;
  Case GotoStyleComboBox.ItemIndex of
  0: If SearchListBox.Count>1 Then Begin
       UnselectAllBut('');
       For I:=0 To SearchListBox.Count-1 Do
         AddItemToSelection(SearchListBox.Items[I]);
       If Pos('zoom',LowerCase(NavigationMode))>0 Then
         NavigateTo(ComputeSelectionZoomDST)
       Else
         NavigateTo(ComputeSelectionDST);
       If EditMode='edit' Then UpdateMultiSelection;
     End Else Begin
       If (Pos('zoom',LowerCase(NavigationMode))>0)Or(NavigationMode='Fly') Then
         NavigateTo(ComputeItemZoomDST(SearchEdit.Text))
       Else
         NavigateTo(ComputeItemDST(SearchEdit.Text));
     end;
  1: If SearchListBox.Count>1 Then Begin
       UnselectAllBut('');
       For I:=0 To SearchListBox.Count-1 Do
         AddItemToSelection(SearchListBox.Items[I]);
       If EditMode='edit' Then UpdateMultiSelection;
     End Else begin
       UnselectAllBut('');
       AddItemToSelection(SearchEdit.Text);
     end;
  2: Case GetTypeByName(Scene,SearchEdit.Text) of
     'object': Begin Obj:=Scene.VObjectList.Objects[Scene.VObjectList.IndexOf(SearchEdit.Text)] As TVObject;
                     PrepareObjectPropEdit(Obj);
               End;
     'callout': Begin Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(SearchEdit.Text)] As TVCallout;
                     PrepareCalloutPropEdit(Callout);
                End;
     'connection': Begin
                     Connection:=Scene.VConnectionList.Objects[Scene.VConnectionList.IndexOf(SearchEdit.Text)] As TVConnection;
                     PrepareConnectionPropEdit(Connection);
                   End;
     end;
  end;
end;

procedure TForm1.Image1Click(Sender: TObject);
begin

end;

procedure TForm1.Image1DblClick(Sender: TObject);
Var I,J:Longint;
    Obj:TVObject;
    Callout:TVCallout;
    ItemName:String;
    ItemsUnderMouseCount:Longint;
    MItem:TMenuItem;
    List:TStringList;
begin
  //doing default action without menu display

    Form1.ActionMenu.Items.Clear;
    ItemsUnderMouseCount:=0;
    List:=Scene.BuildUnderMouse(CurrentXw,CurrentYw,SamePlaceZone);
    If List.Count>0 Then Begin
      ItemsUnderMouseCount:=ItemsUnderMouseCount+List.Count;
      For I:=0 To List.Count-1 Do Begin
        Case GetTypeByName(Scene,List[I]) of
        'object': Begin
                    Obj:=List.Objects[I] As TVObject;
                    ItemName:=Obj.Name;
                    If Obj.ActionList.Count>0 Then
                      For J:=0 To Obj.ActionList.Count-1 Do Begin
                        MItem:=TMenuItem.Create(Nil);
                        MItem.Caption:=Obj.ActionList.Names[J];
                        MItem.OnClick:=Form1.ActionMenuButton.OnClick;
                        Form1.ActionMenu.Items.Add(MItem);
                      end;
                  End;
        'callout':Begin
                    Callout:=List.Objects[I] As TVCallout;
                    ItemName:=Callout.Name;
                    If Callout.ActionList.Count>0 Then
                      For J:=0 To Callout.ActionList.Count-1 Do Begin
                        MItem:=TMenuItem.Create(Nil);
                        MItem.Caption:=Callout.ActionList.Names[J];
                        MItem.OnClick:=Form1.ActionMenuButton.OnClick;
                        Form1.ActionMenu.Items.Add(MItem);
                      end;
                  End;
        End;
      End;
    End;
    List.Free;
    If Form1.ActionMenu.Items.Count=0 Then Exit;
    showMessage('dblclick');
    If (ItemsUnderMouseCount=1)Or(Form1.ActionMenu.Items.Count=1) Then Begin
      // ровно один объект под курсором -
      // автовыполняем обновление или единственное действие по левой кнопке
      // контекстное меню по правой
      SearchEdit.Text:=ItemName;
      ActionMenuButtonClick(MItem);
    End;
end;


procedure TForm1.Label15Click(Sender: TObject);
begin
  If BaseObjectEdit.Text='' Then Exit;
  NavigationDst:=BaseObjectEdit.Text;
  NavigatePopupMenu.Popup;
end;

Procedure TForm1.LdXEditClick(Sender: TObject);
Begin
  UpdateFrom:=upddX;
end;

Procedure TForm1.LdXEditKeyPress(Sender: TObject; Var Key: char);
Begin
  UpdateFrom:=upddX;
end;

Procedure TForm1.LdXEditMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
Begin
  UpdateFrom:=upddX;
  LdXEditChange(Sender);
end;

Procedure TForm1.LdYEditClick(Sender: TObject);
Begin
  UpdateFrom:=upddY;
end;

Procedure TForm1.LdYEditKeyPress(Sender: TObject; Var Key: char);
Begin
  UpdateFrom:=upddY;
end;

Procedure TForm1.LdYEditMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
Begin
  UpdateFrom:=upddY;
  LdYEditChange(Sender);
end;

Procedure TForm1.LFiEditMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
Begin
   UpdateFrom:=updFi;
  LFiEditChange(Sender);
end;

procedure TForm1.LibraryShellTreeViewMouseMove(Sender: TObject;
  Shift: TShiftState; X, Y: Integer);
begin
  TemplateGroupBox.Height:=(InspectorScrollBox.Height-ObjStyleRadioGroup.Height-InsPointGroupBox.Height)*3 div 5;
end;

Procedure TForm1.LLEditClick(Sender: TObject);
Begin
  UpdateFrom:=updL;
end;

Procedure TForm1.LLEditKeyPress(Sender: TObject; Var Key: char);
Begin
  UpdateFrom:=updL;
end;

Procedure TForm1.LLEditMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
Begin
  UpdateFrom:=updL;
  LLEditChange(Sender);
end;

Function FilterEnter(S:String):String;
Var p:Longint;S1:String;
Begin
  S1:=S;
  While Pos(#10,S1)<>0 Do
    Delete(S1,Pos(#10,S1),1);
  While Pos(#13,S1)<>0 Do
    Delete(S1,Pos(#13,S1),1);
  Result:=S1;
End;


procedure TForm1.LoadFromDirMenuItemClick(Sender: TObject);
Var I,J,N:Longint;
    FileList,FileBuf,RenList:TStringList;
    Cmd,TemplateName,TemplateFileName,Buf,ParsedBuf:String;
    NumTemplatesBefore,NumTemplatesAfter:Longint;
    E,Sm,Rm,Scm,tmpm,TransM:TMatrix2D;
    Obj:TVObject;Template:TVTemplate;
    Port:TVPort;AccObject:TAccObject;
    Conn:TVConnection;Callout:TVCallout;
begin
  If OpenSceneDialog.Execute Then SceneFileName:=OpenSceneDialog.FileName Else Exit;
  FileBuf:=TStringList.Create;
  FileList:=TStringList.Create;
  RenList:=TStringList.Create;
  Scene.View.LoadFromFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_displaylist_'));
  FileList.LoadFromFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_curllist_'));
  If FileList.Count>0 Then
    For I:=0 To FileList.Count-1 Do Begin
      FileBuf.LoadFromFile(OSPath(ExtractFilePath(SceneFileName)+'/'+FileList[I]));
//      Scene.LoadCurl();
    end;
  FileList.LoadFromFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_objectlist_'));
  If FileList.Count>0 Then
    For I:=0 To FileList.Count-1 Do Begin
      FileBuf.LoadFromFile(OSPath(ExtractFilePath(SceneFileName)+'/'+FileList[I]));
      Scene.LoadObject(0,False,0,0,FileBuf,RenList);
    end;
  FileList.LoadFromFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_calloutlist_'));
  If FileList.Count>0 Then
    For I:=0 To FileList.Count-1 Do Begin
      FileBuf.LoadFromFile(OSPath(ExtractFilePath(SceneFileName)+'/'+FileList[I]));
      Scene.LoadCallout(0,False,0,0,FileBuf,RenList);
    end;
  FileList.LoadFromFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_connectionlist_'));
  If FileList.Count>0 Then
    For I:=0 To FileList.Count-1 Do Begin
      FileBuf.LoadFromFile(OSPath(ExtractFilePath(SceneFileName)+'/'+FileList[I]));
      Scene.LoadConnection(0,False,0,0,FileBuf,RenList);
    end;

  {Scene.VObjectList.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_objectlist_'));
  Scene.VCalloutList.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_calloutlist_'));
  Scene.VConnectionList.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_connectionlist_'));
  Scene.VGroupList.SaveToFile(OSPath(ExtractFilePath(SceneFileName)+'/_scene_grouplist_'));}


    If Scene.VObjectList.Count>0 Then
      For I:=0 To Scene.VObjectList.Count-1 Do Begin
        Obj:=Scene.VObjectList.Objects[I] As TVObject;
        If Obj.DisplayList.Count>0 Then
          For J:=0 To Obj.DisplayList.Count-1 Do Begin
            //look for DrawTemplate
            Buf:=Obj.DisplayList[J];
            Cmd:=GetNextToken(Buf,ParsedBuf,' ');
            Buf:=ParsedBuf;
            If LowerCase(Cmd)='drawtemplate' Then Begin
              TemplateName:=GetNextToken(Buf,ParsedBuf,' ');
              If Form1.TemplateList.Items.IndexOf(TemplateName)<0 Then Begin
                TemplateFileName:=FindInSubDir(OSPath(ConfigFile.Values['TemplateDir']),TemplateName);
                If TemplateFileName<>'' Then LoadTemplate(OSPath(TemplateFileName)) Else ShowMessage('Can''t find template file for '+TemplateName);// search
              end;
            End;
          End;
      End;
    Repeat //парсим темплейты пока не перестанут загружаться новые
      NumTemplatesBefore:=Form1.TemplateList.Count;
      If Scene.VTemplateList.Count>0 Then
        For I:=0 To Scene.VTemplateList.Count-1 Do Begin
        Template:=Scene.VTemplateList.Objects[I] As TVTemplate;
        If Template.DisplayList.Count>0 Then
          For J:=0 To Template.DisplayList.Count-1 Do Begin
            //look for DrawTemplate
            Buf:=Template.DisplayList[J];
            Cmd:=GetNextToken(Buf,ParsedBuf,' ');
            Buf:=ParsedBuf;
            If LowerCase(Cmd)='drawtemplate' Then Begin
              TemplateName:=GetNextToken(Buf,ParsedBuf,' ');
              If Form1.TemplateList.Items.IndexOf(TemplateName)<0 Then Begin
                TemplateFileName:=FindInSubDir(OSPath(ConfigFile.Values['TemplateDir']),TemplateName);
                If TemplateFileName<>'' Then LoadTemplate(OSPath(TemplateFileName))  Else ShowMessage('Can''t find template file for '+TemplateName);// search
              end;
            End;
          End;
      End;
      NumTemplatesAfter:=Form1.TemplateList.Count;
    Until NumTemplatesBefore=NumTemplatesAfter;
    //пересчитать оболочки и добавить отрисовку портов в дисплейные списки
    If Scene.VObjectList.Count>0 Then
      For I:=0 To Scene.VObjectList.Count-1 Do Begin
        Obj:=Scene.VObjectList.Objects[I] As TVObject;
        If Obj.DisplayList.Count=0 Then Begin
          //Shell пустого объекта = точке вставки?
          Obj.Shell.X1:=Obj.X;
          Obj.Shell.X2:=Obj.X;
          Obj.Shell.Y1:=Obj.Y;
          Obj.Shell.Y2:=Obj.Y;
        End Else Begin
          If Obj.A<700 Then Begin
            Sm:=GenShift(Obj.X,Obj.Y);
            Rm:=GenRotate(Obj.X,Obj.Y,Obj.A/180*pi);
            Scm:=GenScale(Obj.X,Obj.Y,Obj.S,Obj.S);
          end Else Begin
            Sm:=GenShift(0,0);
            Rm:=GenRotate(0,0,0);
            Scm:=GenScale(0,0,1,1);
          End;
          tmpm:=MulMat2D(Sm,Rm);
          TransM:=MulMat2D(Tmpm,Scm);
          Obj.Shell:=Scene.RenderShell(Obj.DisplayList,TransM);
          If Obj.PortList.Count>0 Then
            For J:=0 To Obj.PortList.Count-1 Do Begin
              Port:=Obj.PortList.Objects[J] As TVPort;
              If Port.AR='A' Then Begin
                Port.X:=(Port.AX-Obj.Shell.X1)/(Obj.Shell.X2-Obj.Shell.X1);
                Port.Y:=(Port.AY-Obj.Shell.Y1)/(Obj.Shell.Y2-Obj.Shell.Y1);
              End Else Begin
                Port.AX:=Obj.Shell.X1+Port.X*(Obj.Shell.X2-Obj.Shell.X1);
                Port.AY:=Obj.Shell.Y1+Port.Y*(Obj.Shell.Y2-Obj.Shell.Y1);
              End;
              //Добавление портов в DisplayList
              AccObject:=TAccObject.Create;
              AccObject.AcceleratedCommand:=AccelerateCommand('UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone));
              Obj.DisplayList.AddObject('UnScaled '+FloatToStr(Port.Ax)+','+FloatToStr(Port.Ay)+',portbox,'+IntToStr(PortHandleZone),AccObject);
            end;
        End;
      end;
    //после пересчета координат портов можно пересчитывать координаты связей
    If Scene.VConnectionList.Count>0 Then
      For I:=0 To Scene.VConnectionList.Count-1 Do Begin
        Conn:=Scene.VConnectionList.Objects[I] As TVConnection;
        Conn.DisplayList.Clear;
        Scene.UpdateConnectionDisplayList(Conn);
      end;
    //после пересчета оболочек объектов можно пересчитывать координаты выносов и создавать списки связанных
    If Scene.VCalloutList.Count>0 Then
      For I:=0 To Scene.VCalloutList.Count-1 Do Begin
        Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
        If Callout.RelatedObj<>'' Then Begin
          N:=Scene.VObjectList.IndexOf(Callout.RelatedObj);
          If N>=0 Then Begin
            Obj:=Scene.VObjectList.Objects[N] As TVObject;
            Obj.RelatedCAList.AddObject(Callout.Name,Callout);
          End;
        End;
        Scene.UpdateCalloutDisplayList(Callout);
      end;
    //Если есть источник, но нет текста - надо перечитать источники
    If Scene.VCalloutList.Count>0 Then
          For I:=0 To Scene.VCalloutList.Count-1 Do Begin
            Callout:=Scene.VCalloutList.Objects[I] As TVCallout;
            If (Callout.Text='') And (Callout.Source<>'') Then Begin
              ReloadSource(Scene,Callout.Name);
            End;
            Scene.UpdateCalloutDisplayList(Callout);
          end;
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  ZoomToScene;
  Form1.Caption:=TitleString+' '+SceneFileName;
end;

procedure TForm1.LoadFromFileMenuItemClick(Sender: TObject);
Var I,J:Longint;
    Obj:TVObject;Template:TVTemplate;
    Cmd,TemplateName,TemplateFileName,Buf,ParsedBuf:String;
    NumTemplatesBefore,NumTemplatesAfter:Longint;
    E,Sm,Rm,Scm,tmpm,TransM:TMatrix2D;
begin
  Scene.Clear;
  SelectionListEditor.Clear;
  Dispatcher.ExecCommand('self::CAD_Scene2GUI');
  If Not OpenSceneDialog.Execute Then Exit;
  DocumentURL:='file://'+OpenSceneDialog.FileName;
  SceneFileName:=OpenSceneDialog.FileName;
  LoadDocument(DocumentURL);
  Form1.Caption:=TitleString+' '+OpenSceneDialog.FileName;
  GroupStringGridSelection(GroupStringGrid,GroupStringGrid.Col,GroupStringGrid.Row);
  ZoomToScene;
 end;



procedure TForm1.BookMarkListBoxDblClick(Sender: TObject);
Var N,A:String;
    I:Longint;
begin
  If BookMarkListBox.ItemIndex>=0 Then Begin
    I:=BookMarks.IndexOfName(BookMarkListBox.Items[BookMarkListBox.ItemIndex]);
    If I>=0 Then
      A:=BookMarks.ValueFromIndex[I];
    GotoBookMark(A);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
var
   TextStyle:TTextStyle;
   SPath,Buf:String;
   SearchRec:TSearchRec;SResult,N,Count:Longint;
   val:Extended;
begin
  DecimalSeparator:='.';
  ToolOptionsPanel.Height:=105;
  WCanvas:=Form1.DrawingPanel.Canvas;
  BufBitMap:=TBitMap.Create;
  TextStyle:=WCanvas.TextStyle;
  TextStyle.Opaque:=False;
  WCanvas.TextStyle:=TextStyle;
  Drawer:=TDrawer.Create(WCanvas);
  Drawer.PrintMultiplier:=1;

  vFileName:=''; DocumentName:=''; SceneFileName:='';
  DocumentProto:='file://';
  Form1.DrawingPanel.OnPaint:=Form1.Image1.OnPaint;
  Form1.PageControl2.Hide;
  InspectorScrollBox.Parent:=PropTabSheet;
  PrimitivesPageControl.TabIndex:=0;

  Scene:=TVScene.Create;
  Scene.Drawer:=Drawer;
  Drawer.Resolver:=Scene.VCurlList;
  RubberDisplayList:=TStringList.Create;
  FontComboBox.Items.Assign(Screen.Fonts);
  FontComboBox.ItemIndex:=FontComboBox.Items.IndexOf(Screen.SystemFont.Name);
  FontSizeEdit.Value:=10;//Screen.SystemFont.Size;
  FontDialog.Font.Size:=FontSizeEdit.Value;
  FontDialog.Font.Name:=Screen.SystemFont.Name;
  LockBackUpdate:=False;
  LockSelectionUpdate:=False;
  LockRepaint:=False;
  BookMarks:=TStringList.Create;
  OriginalList:=TStringList.Create;
  UnderMouseDOWN:=TStringList.Create;
  UnderMouseUP:=TStringList.Create;
  LX1Edit.Increment:=GridGapEdit.Value;
  LY1Edit.Increment:=GridGapEdit.Value;
  LX2Edit.Increment:=GridGapEdit.Value;
  LY2Edit.Increment:=GridGapEdit.Value;
  LdXEdit.Increment:=GridGapEdit.Value;
  LdYEdit.Increment:=GridGapEdit.Value;
  If Not TryStrToFloat(Config.ConfigFile.Values['ZoomStep'],val) Then Config.ConfigFile.Add('ZoomStep=0.20');

  //зачитать библиотеку шаблонов
  If DirectoryExists(OSPath(ConfigFile.Values['TemplateDir'])) Then LibraryShellTreeView.Root:=OSPath(ConfigFile.Values['TemplateDir']);
  DrawingPanel.Color:=StringToColor(Config.ConfigFile.Values['SceneBGColor']);
  //axiscolor skipped - drawscene uses Config.ConfigFile.Values['AxisColor'] not variable
  RefreshSpeedLabel.Visible:=(LowerCase(ConfigFile.Values['DisplayStats'])='yes')Or
                    (LowerCase(ConfigFile.Values['DisplayStats'])='on') Or
                    (LowerCase(ConfigFile.Values['DisplayStats'])='y') Or
                    (LowerCase(ConfigFile.Values['DisplayStats'])='1');

  BufferDrawing:=(LowerCase(ConfigFile.Values['BufferedDraw'])='yes') Or
                 (LowerCase(ConfigFile.Values['BufferedDraw'])='on') Or
                 (LowerCase(ConfigFile.Values['BufferedDraw'])='y') Or
                 (LowerCase(ConfigFile.Values['BufferedDraw'])='1');

  Scene.MaxDisplayedDepth:=StrToInt(ConfigFile.Values['LoD']);

  Unit1.Scene.Clip:=(LowerCase(ConfigFile.Values['Clip'])='yes') Or
                    (LowerCase(ConfigFile.Values['Clip'])='on') Or
                    (LowerCase(ConfigFile.Values['Clip'])='y') Or
                    (LowerCase(ConfigFile.Values['Clip'])='1');

  Unit1.Scene.ClipMax:=(LowerCase(ConfigFile.Values['ClipMax'])='yes') Or
                       (LowerCase(ConfigFile.Values['ClipMax'])='on') Or
                       (LowerCase(ConfigFile.Values['ClipMax'])='y') Or
                       (LowerCase(ConfigFile.Values['ClipMax'])='1');

  Unit1.Scene.ClipSize:=StrToInt(ConfigFile.Values['ClipSize']);

  Scene.ShowShells:=(LowerCase(ConfigFile.Values['ShowShells'])='yes') Or
                       (LowerCase(ConfigFile.Values['ShowShells'])='on') Or
                       (LowerCase(ConfigFile.Values['ShowShells'])='y') Or
                       (LowerCase(ConfigFile.Values['ShowShells'])='1');

  Scene.ShowObjectNames:=(LowerCase(ConfigFile.Values['ShowNames'])='yes') Or
                         (LowerCase(ConfigFile.Values['ShowNames'])='on') Or
                         (LowerCase(ConfigFile.Values['ShowNames'])='y') Or
                         (LowerCase(ConfigFile.Values['ShowNames'])='1');
  //objectname font name and BIUS skipped
  //ONameFontDialog.Font.Color skipped: drawscene uses ConfigFile.Values['ObjectNameColor'] directly

  //ONameBGColorButton.ButtonColor skipped: drawscene uses ConfigFile.Values['ObjectNameBGColor'] directly

  Scene.ShowPortNames:=(LowerCase(ConfigFile.Values['ShowPortNames'])='yes') Or
                              (LowerCase(ConfigFile.Values['ShowPortNames'])='on') Or
                              (LowerCase(ConfigFile.Values['ShowPortNames'])='y') Or
                              (LowerCase(ConfigFile.Values['ShowPortNames'])='1');
  //sel label font color
  HintLabel.Font.Color:=StringToColor(Config.ConfigFile.Values['SelectionColor']);

  //mouse
  //zoom mode
  //zoom step
  //sel mode
  SamePlaceZone:=StrToInt(Config.ConfigFile.Values['SamePlaceZone']);
  SelHandleZone:=StrToInt(Config.ConfigFile.Values['SelHandleZone']);
  PortHandleZone:=StrToInt(Config.ConfigFile.Values['PortHandleZone']);
  Scene.SelHandleSize:=SelHandleZone;
  Scene.PortSize:=PortHandleZone;

  NavigationMode:='teleport';
  Form1.DrawingPanel.DoubleBuffered:=True;
  EditMode:='navigation';
  If ParamCount>0 Then Begin
    If Pos('://',ParamStr(1))=0 Then
      LoadDocument('file://'+ParamStr(1))
    Else LoadDocument(ParamStr(1));
    GroupStringGridSelection(GroupStringGrid,GroupStringGrid.Col,GroupStringGrid.Row);
    Form1.Caption:=TitleString+' '+ParamStr(1);
    ZoomToScene;
  end Else Form1.Caption:=TitleString;
  Dispatcher.QueueCommand('self::CAD_UpdateCoordBase');
  PenButtonClick(NavigateButton);
  Form1.ActiveControl:=DrawingPanel;
end;


Function ExecCommand(Command:String):String;
var B,PB,Obj,Cmd,Attr,AttrType,AttrName,AttrValue,ItemName:String;
    ox,oy,X,Y:Extended;   I:Longint;   Group:TVgroup;
    Xs,Ys,Ms,Ns,IXPos,IYPos,OXPos,OYPos:String;
Begin
  Obj:=GetNextToken(Command,PB,':');
  B:=PB;
  Cmd:=GetNextToken(B,PB,':');
  Attr:=PB;
  If Obj='' Then Begin
// UpdateDraw
    If LowerCase(Cmd)='cad_updatedraw' Then Begin
      RepaintView;
      Result:='';
    end;
// UpdateCoordBase
    If LowerCase(Cmd)='cad_updatecoordbase' Then Begin
      Drawer.ViewX:=Form1.ViewXEdit.Value;
      Drawer.ViewY:=Form1.ViewYEdit.Value;
      Drawer.ViewScale:=Form1.ViewScaleEdit.Value;
      Drawer.ViewAngle:=Form1.ViewAngleEdit.Value/180*pi;
      Drawer.Wx:=Form1.DrawingPanel.Width;
      Drawer.Wy:=Form1.DrawingPanel.Height;
      Drawer.RecalcMatrix;
      UpdateScreenShell(Drawer);
      Scene.UpdateVisibility;
      RepaintView;
      Result:='';
    End;
// UpdateScale
    If LowerCase(Cmd)='cad_updatescale' Then Begin
      Drawer.Wx:=Form1.DrawingPanel.Width;
      Drawer.Wy:=Form1.DrawingPanel.Height;
      Drawer.SToW(Drawer.Wx div 2, Drawer.Wy div 2,Ox,Oy);
      Drawer.ViewScale:=Form1.ViewScaleEdit.Value;
      Drawer.RecalcMatrix;
      UpdateScreenShell(Drawer);
      Scene.UpdateVisibility;
      RepaintView;
      Result:='';
    end;

// PeekViewPosition
    If LowerCase(Cmd)='cad_peekviewposition' Then Begin
      Result:='file://'+DocumentName+'?X='+Form1.ViewXEdit.Text+'&Y='+Form1.ViewYEdit.Text+'&A='+Form1.ViewAngleEdit.Text+'&S='+Form1.ViewScaleEdit.Text;
      Clipboard.AsText:=Result;
    end;

// UpdateAll
    If LowerCase(Cmd)='cad_updateall' Then Begin
      UpdateAll;
      Result:='';
    end;
// FixAll
    If LowerCase(Cmd)='cad_fixall' Then Begin
      FixAll;
      RepaintView;
      Result:='';
    end;
// Scene2GUI
    If LowerCase(Cmd)='cad_scene2gui' Then Begin
//      Form1.CurlList.Items.Clear;
      Form1.CurlList.Items.Assign(Scene.VCurlList);
      Form1.NumCurlsLabel.Caption:=IntToStr(Form1.CurlList.Items.Count);
//      Form1.ObjectList.Items.Clear;
      Form1.ObjectList.Items.Assign(Scene.VObjectList);
      Form1.NumObjectsLabel.Caption:=IntToStr(Form1.ObjectList.Items.Count);
//      Form1.TemplateList.Items.Clear;
      Form1.TemplateList.Items.Assign(Scene.VTemplateList);
      Form1.NumTemplatesLabel.Caption:=IntToStr(Form1.TemplateList.Items.Count);
//      Form1.ConnectionList.Items.Clear;
      Form1.ConnectionList.Items.Assign(Scene.VConnectionList);
      Form1.NumConnectionsLabel.Caption:=IntToStr(Form1.ConnectionList.Items.Count);
//      Form1.CalloutList.Items.Clear;
      Form1.CalloutList.Items.Assign(Scene.VCalloutList);
      Form1.NumCalloutsLabel.Caption:=IntToStr(Form1.CalloutList.Items.Count);

      Form1.GroupStringGrid.RowCount:=Scene.VGroupList.Count+1;
      If Scene.VGroupList.Count>0 Then
        For I:=0 To Scene.VGroupList.Count-1 Do Begin
          Group:=Scene.VGroupList.Objects[I] As TVGroup;
          Form1.GroupStringGrid.Cells[0,I+1]:=Group.Name;
          If Group.Glue Then Form1.GroupStringGrid.Cells[1,I+1]:='1' Else Form1.GroupStringGrid.Cells[1,I+1]:='0';
          If Group.Active Then Form1.GroupStringGrid.Cells[2,I+1]:='1' Else Form1.GroupStringGrid.Cells[2,I+1]:='0';
          If Group.Visible Then Form1.GroupStringGrid.Cells[3,I+1]:='1' Else Form1.GroupStringGrid.Cells[3,I+1]:='0';
        end;
      Form1.NumGroupsLabel.Caption:=IntToStr(Scene.VGroupList.Count);
//      Form1.SceneMemo.Lines.Clear;
      Form1.SceneMemo.Lines.Assign(Scene.View);
      Form1.NumSceneLabel.Caption:=IntToStr(Form1.SceneMemo.Lines.Count);
      Result:='';
    End;
    If LowerCase(cmd)='cad_reloadsource' Then Begin
      ReloadSource(Scene,PB);
      Result:='';
    End;
    If LowerCase(Cmd)='cad_gui2scene' Then Begin
      Scene.VCurlList.Assign(Form1.CurlList.Items);
      Scene.VObjectList.Assign(Form1.ObjectList.Items);
      Scene.View.Assign(Form1.SceneMemo.Lines);
      RepaintView;
      Result:='';
    End;
    If LowerCase(Cmd)='cad_loadscenefile' Then Begin
//      Scene.LoadFile(PB); надо починить на URL
      RepaintView;
      Result:='';
    End;
    If LowerCase(Cmd)='cad_savescenefile' Then Begin
      Scene.SaveFile(PB);
      Result:='';
    End;
    // Teleport
    If LowerCase(Cmd)='cad_teleport' Then Begin
      GoToBookMark(PB);
      Result:='';
    end;
    // Hover
    If LowerCase(Cmd)='cad_hover' Then Begin
      B:=PB;
      Ns:=GetNextToken(B,PB,':');
      I:=StrToInt(Ns);
      HoverToBookMark(I,PB);
      Result:='';
    end;
    // Fly
    If LowerCase(Cmd)='cad_fly' Then Begin
      B:=PB;
      Ns:=GetNextToken(B,PB,':');
      I:=StrToInt(Ns);
      FlyToBookMark(I,PB);
      Result:='';
    end;

    // CreateObject
    If LowerCase(Cmd)='cad_createobject' Then Begin
      CreateObject(PB);
      Result:='';
    end;
    // CreateObjectPort
    If LowerCase(Cmd)='cad_createobjectport' Then Begin
      B:=PB;
      B:=GetNextToken(B,PB,':');
      CreateObjectPort(B,PB);
      Result:='';
    end;
    // ArrangePortsByRect
    If LowerCase(Cmd)='cad_arrangeportsbyrect' Then Begin
      B:=PB;
      Obj:=GetNextToken(B,PB,':');
      B:=PB;
      Ms:=GetNextToken(B,Ns,':');
      ArrangePortsByRect(Obj,Ms,Ns);
      Result:='';
    end;
    If LowerCase(Cmd)='cad_arrangeportsbyrectall' Then Begin
      B:=PB;
      Ms:=GetNextToken(B,Ns,':');
      ArrangePortsByRectAll(Ms,Ns);
      Result:='';
    end;
    // ArrangePortsByLines
    If LowerCase(Cmd)='cad_arrangeportsbylines' Then Begin
      B:=PB;
      Obj:=GetNextToken(B,PB,':');
      B:=PB;
      IXPos:=GetNextToken(B,PB,':');
      B:=PB;
      IYPos:=GetNextToken(B,PB,':');
      B:=PB;
      OXPos:=GetNextToken(B,OYPos,':');
      ArrangePortsByLines(Obj,IXPos,IYPos,OXPos,OYPos);
      Result:='';
    end;

    // CreateCallout
    If LowerCase(Cmd)='cad_createcallout' Then Begin
      CreateCallout(PB);
      Result:='';
    end;
    // CreateConnection
    If LowerCase(Cmd)='cad_createconnection' Then Begin
      CreateConnection(PB);
      Result:='';
    end;
    // CreateNPConnection
    If LowerCase(Cmd)='cad_createnpconnection' Then Begin
      CreateNPConnection(PB);
      Result:='';
    end;
    // SetSource
    If LowerCase(Cmd)='cad_setsource' Then Begin
      B:=PB;
      GetNextToken(B,PB,':');
      SetSource(B,PB);
      Result:='';
    End;
    // SetText
    If LowerCase(Cmd)='cad_settext' Then Begin
      B:=PB;
      B:=GetNextToken(B,PB,':');
      SetText(B,PB);
      Result:='';
    End;
    //  GetAttr
    If LowerCase(Cmd)='cad_getattr' Then Begin
      B:=PB;
      ItemName:=GetNextToken(B,PB,':');
      Result:=GetAttr(ItemName,PB);
    End;
    //  SetAttr
    If LowerCase(Cmd)='cad_setattr' Then Begin
      B:=PB;
      ItemName:=GetNextToken(B,PB,':');
      B:=PB;
      AttrName:=GetNextToken(B,PB,':');
      Result:=SetAttr(ItemName,AttrName,PB);
    End;
    //  ModAttr
    If LowerCase(Cmd)='cad_modattr' Then Begin
      B:=PB;
      ItemName:=GetNextToken(B,PB,':');
      B:=PB;
      AttrName:=GetNextToken(B,PB,':');
      Result:=ModAttr(ItemName,AttrName,PB);
    End;
    // FixItem
    If LowerCase(Cmd)='cad_fixitem' Then Begin
      FixItem(PB);
      Result:='';
    end;

    // Select
    If LowerCase(Cmd)='cad_select' Then Begin
      AddItemToSelection(PB);
      Result:='';
    end;
    // UnSelect
    If LowerCase(Cmd)='cad_unselect' Then Begin
      RemoveItemFromSelection(PB);
      Result:='';
    end;
    // UnSelectAll
    If LowerCase(Cmd)='cad_unselectall' Then Begin
      UnselectAllBut('');
      Result:='';
    end;
    // Copy
    If LowerCase(Cmd)='cad_copy' Then Begin
      CopySelection;
      Result:='';
    end;
    // Paste
    If LowerCase(Cmd)='cad_paste' Then Begin
      PasteSelection;
      Result:='';
    end;
    // Delete
    If LowerCase(Cmd)='cad_deleteselection' Then Begin
      DeleteSelection;
      Result:='';
    end;
    // Delete
     If LowerCase(Cmd)='cad_deleteitem' Then Begin
       DeleteItem(PB);
       Result:='';
     end;
    // MoveTo
    If LowerCase(Cmd)='cad_moveto' Then Begin
      B:=PB;
      Xs:=GetNextToken(B,PB,':');
      Ys:=Pb;
      If Not TryStrToFloat(Xs,X) Then X:=0;
      If Not TryStrToFloat(Ys,Y) Then Y:=0;
      MoveSelectionTo(X,Y);
      Result:='';
    end;
  End;
End;

procedure TForm1.CreateRelCASpeedButtonClick(Sender: TObject);
Var Callout:TVCallout; Obj:TVObject;
    Style,CalloutName,BIUS,ObjName:String;
    K:Longint;
begin
    If CurrentEditingNameEdit.Text='' Then     //
      ObjName:=ObjectList.Items[ObjectList.Items.Count-1]
    Else ObjName:=CurrentEditingNameEdit.Text;
    BaseObjectEdit.Text:=ObjName;
    //заменить бы на GUI2Scene
    BIUS:='';
    If fsBold in FontDialog.Font.Style Then BIUS:=BIUS+'b';
    If fsItalic in FontDialog.Font.Style Then BIUS:=BIUS+'i';
    If fsUnderline in FontDialog.Font.Style Then BIUS:=BIUS+'u';
    If fsStrikeOut in FontDialog.Font.Style Then BIUS:=BIUS+'s';
    Style:=
        'RelatedObj='+ObjName+
        ' Color='+ColorToString(BorderColorButton.ButtonColor)+
        ' BGColor='+ColorToString(PeekBGColorButton.ButtonColor)+
        ' Width='+IntToStr(WidthButton1.Tag)+
        ' FontName='+(FontDialog.Font.Name)+
        ' FontColor='+ColorToString(FontDialog.Font.Color)+
        ' FontHeight='+FloatToStr(FontDialog.Font.Height*ViewScaleEdit.Value)+
        ' BIUS='+BIUS;
    If TransparentBGCheckBox.Checked Then
      Style:=Style+' Transparent=Yes'
    Else
      Style:=Style+' Transparent=No';
    Style:=Style+' BindMode=Shell';
    BindModeRadioGroup.ItemIndex:=0;
    CalloutName:=CreateCallout(Style);
    Callout:=Scene.VCalloutList.Objects[Scene.VCalloutList.IndexOf(CalloutName)] As TVCallout;
    Callout.Saveable:=True;
    Scene.ExecCommand('DrawCallout '+CalloutName,ZeroAcc,0);
    Dispatcher.ExecCommand('self::CAD_Scene2GUI');
    CurrentEditingNameEdit.Text:=CalloutName;
    Scene.CreateSelHandles(CalloutName);
    PrepareCalloutPropEdit(Callout);
end;

Procedure TForm1.DeleteMenuItemClick(Sender: TObject);
Begin
{  If OperationMenuInvokedFromButton Then
    OperationSpeedButton.Caption:=(Sender As TMenuItem).Caption

  Else
  }DeleteSelection;
end;

procedure TForm1.MoveHereMenuItemClick(Sender: TObject);
begin
  MoveSelectionTo(CurrentXGw,CurrentYGw);
end;


initialization
  {$I unit1.lrs}



end.

