DocumentUpdater.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. using System.Collections.Immutable;
  2. using ChunkyImageLib;
  3. using ChunkyImageLib.DataHolders;
  4. using PixiEditor.AvaloniaUI.Helpers;
  5. using PixiEditor.AvaloniaUI.Models.DocumentPassthroughActions;
  6. using PixiEditor.AvaloniaUI.Models.Handlers;
  7. using PixiEditor.AvaloniaUI.Models.Layers;
  8. using PixiEditor.AvaloniaUI.ViewModels.Document;
  9. using PixiEditor.AvaloniaUI.ViewModels.Nodes;
  10. using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
  11. using PixiEditor.ChangeableDocument.ChangeInfos;
  12. using PixiEditor.ChangeableDocument.ChangeInfos.Animation;
  13. using PixiEditor.ChangeableDocument.ChangeInfos.Drawing;
  14. using PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph;
  15. using PixiEditor.ChangeableDocument.ChangeInfos.Properties;
  16. using PixiEditor.ChangeableDocument.ChangeInfos.Root;
  17. using PixiEditor.ChangeableDocument.ChangeInfos.Root.ReferenceLayerChangeInfos;
  18. using PixiEditor.ChangeableDocument.ChangeInfos.Structure;
  19. using PixiEditor.ChangeableDocument.Enums;
  20. using PixiEditor.Numerics;
  21. namespace PixiEditor.AvaloniaUI.Models.DocumentModels;
  22. #nullable enable
  23. internal class DocumentUpdater
  24. {
  25. private IDocument doc;
  26. private DocumentInternalParts helper;
  27. public DocumentUpdater(IDocument doc, DocumentInternalParts helper)
  28. {
  29. this.doc = doc;
  30. this.helper = helper;
  31. }
  32. /// <summary>
  33. /// Don't call this outside ActionAccumulator
  34. /// </summary>
  35. public void AfterUndoBoundaryPassed()
  36. {
  37. //TODO: Make sure AllChangesSaved trigger raise property changed itself
  38. doc.UpdateSavedState();
  39. }
  40. /// <summary>
  41. /// Don't call this outside ActionAccumulator
  42. /// </summary>
  43. public void ApplyChangeFromChangeInfo(IChangeInfo arbitraryInfo)
  44. {
  45. if (arbitraryInfo is null)
  46. return;
  47. //TODO: Find a more elegant way to do this
  48. switch (arbitraryInfo)
  49. {
  50. case CreateStructureMember_ChangeInfo info:
  51. if (info is CreateLayer_ChangeInfo layerChangeInfo)
  52. {
  53. ProcessCreateNode<LayerViewModel>(info);
  54. }
  55. else if (info is CreateFolder_ChangeInfo folderChangeInfo)
  56. {
  57. ProcessCreateNode<FolderViewModel>(info);
  58. }
  59. ProcessCreateStructureMember(info);
  60. break;
  61. case DeleteStructureMember_ChangeInfo info:
  62. ProcessDeleteNode(info);
  63. ProcessDeleteStructureMember(info);
  64. break;
  65. case StructureMemberName_ChangeInfo info:
  66. ProcessUpdateStructureMemberName(info);
  67. break;
  68. case StructureMemberIsVisible_ChangeInfo info:
  69. ProcessUpdateStructureMemberIsVisible(info);
  70. break;
  71. case StructureMemberOpacity_ChangeInfo info:
  72. ProcessUpdateStructureMemberOpacity(info);
  73. break;
  74. case MoveStructureMember_ChangeInfo info:
  75. ProcessMoveStructureMember(info);
  76. break;
  77. case Size_ChangeInfo info:
  78. ProcessSize(info);
  79. break;
  80. case RefreshViewport_PassthroughAction info:
  81. ProcessRefreshViewport(info);
  82. break;
  83. case RemoveViewport_PassthroughAction info:
  84. ProcessRemoveViewport(info);
  85. break;
  86. case StructureMemberMask_ChangeInfo info:
  87. ProcessStructureMemberMask(info);
  88. break;
  89. case StructureMemberBlendMode_ChangeInfo info:
  90. ProcessStructureMemberBlendMode(info);
  91. break;
  92. case LayerLockTransparency_ChangeInfo info:
  93. ProcessLayerLockTransparency(info);
  94. break;
  95. case Selection_ChangeInfo info:
  96. ProcessSelection(info);
  97. break;
  98. case SymmetryAxisState_ChangeInfo info:
  99. ProcessSymmetryState(info);
  100. break;
  101. case SymmetryAxisPosition_ChangeInfo info:
  102. ProcessSymmetryPosition(info);
  103. break;
  104. case StructureMemberClipToMemberBelow_ChangeInfo info:
  105. ProcessClipToMemberBelow(info);
  106. break;
  107. case StructureMemberMaskIsVisible_ChangeInfo info:
  108. ProcessMaskIsVisible(info);
  109. break;
  110. case SetReferenceLayer_ChangeInfo info:
  111. ProcessSetReferenceLayer(info);
  112. break;
  113. case DeleteReferenceLayer_ChangeInfo info:
  114. ProcessDeleteReferenceLayer(info);
  115. break;
  116. case TransformReferenceLayer_ChangeInfo info:
  117. ProcessTransformReferenceLayer(info);
  118. break;
  119. case ReferenceLayerIsVisible_ChangeInfo info:
  120. ProcessReferenceLayerIsVisible(info);
  121. break;
  122. case ReferenceLayerTopMost_ChangeInfo info:
  123. ProcessReferenceLayerTopMost(info);
  124. break;
  125. case SetSelectedMember_PassthroughAction info:
  126. ProcessSetSelectedMember(info);
  127. break;
  128. case AddSoftSelectedMember_PassthroughAction info:
  129. ProcessAddSoftSelectedMember(info);
  130. break;
  131. case RemoveSoftSelectedMember_PassthroughAction info:
  132. ProcessRemoveSoftSelectedMember(info);
  133. break;
  134. case ClearSoftSelectedMembers_PassthroughAction info:
  135. ProcessClearSoftSelectedMembers(info);
  136. break;
  137. case CreateRasterKeyFrame_ChangeInfo info:
  138. ProcessCreateRasterKeyFrame(info);
  139. break;
  140. case DeleteKeyFrame_ChangeInfo info:
  141. ProcessDeleteKeyFrame(info);
  142. break;
  143. case SetActiveFrame_PassthroughAction info:
  144. ProcessActiveFrame(info);
  145. break;
  146. case KeyFrameLength_ChangeInfo info:
  147. ProcessKeyFrameLength(info);
  148. break;
  149. case KeyFrameVisibility_ChangeInfo info:
  150. ProcessKeyFrameVisibility(info);
  151. break;
  152. case AddSelectedKeyFrame_PassthroughAction info:
  153. ProcessAddSelectedKeyFrame(info);
  154. break;
  155. case RemoveSelectedKeyFrame_PassthroughAction info:
  156. ProcessRemoveSelectedKeyFrame(info);
  157. break;
  158. case ClearSelectedKeyFrames_PassthroughAction info:
  159. ClearSelectedKeyFrames(info);
  160. break;
  161. case CreateNode_ChangeInfo info:
  162. ProcessCreateNode<NodeViewModel>(info);
  163. break;
  164. case DeleteNode_ChangeInfo info:
  165. ProcessDeleteNode(info);
  166. break;
  167. case ConnectProperty_ChangeInfo info:
  168. ProcessConnectProperty(info);
  169. break;
  170. case NodePosition_ChangeInfo info:
  171. ProcessNodePosition(info);
  172. break;
  173. }
  174. }
  175. private void ProcessReferenceLayerIsVisible(ReferenceLayerIsVisible_ChangeInfo info)
  176. {
  177. doc.ReferenceLayerHandler.SetReferenceLayerIsVisible(info.IsVisible);
  178. }
  179. private void ProcessTransformReferenceLayer(TransformReferenceLayer_ChangeInfo info)
  180. {
  181. doc.ReferenceLayerHandler.TransformReferenceLayer(info.Corners);
  182. }
  183. private void ProcessDeleteReferenceLayer(DeleteReferenceLayer_ChangeInfo info)
  184. {
  185. doc.ReferenceLayerHandler.DeleteReferenceLayer();
  186. }
  187. private void ProcessSetReferenceLayer(SetReferenceLayer_ChangeInfo info)
  188. {
  189. doc.ReferenceLayerHandler.SetReferenceLayer(info.ImagePbgra8888Bytes, info.ImageSize, info.Shape);
  190. }
  191. private void ProcessReferenceLayerTopMost(ReferenceLayerTopMost_ChangeInfo info)
  192. {
  193. doc.ReferenceLayerHandler.SetReferenceLayerTopMost(info.IsTopMost);
  194. }
  195. private void ProcessRemoveSoftSelectedMember(RemoveSoftSelectedMember_PassthroughAction info)
  196. {
  197. IStructureMemberHandler? member = doc.StructureHelper.Find(info.Id);
  198. if (member is null || member.Selection == StructureMemberSelectionType.Hard)
  199. return;
  200. if (member.Selection != StructureMemberSelectionType.Soft)
  201. return;
  202. member.Selection = StructureMemberSelectionType.None;
  203. // TODO: Make sure Selection raises property changed internally
  204. //member.OnPropertyChanged(nameof(member.Selection));
  205. doc.RemoveSoftSelectedMember(member);
  206. }
  207. private void ProcessClearSoftSelectedMembers(ClearSoftSelectedMembers_PassthroughAction info)
  208. {
  209. foreach (IStructureMemberHandler? oldMember in doc.SoftSelectedStructureMembers)
  210. {
  211. if (oldMember.Selection == StructureMemberSelectionType.Hard)
  212. continue;
  213. oldMember.Selection = StructureMemberSelectionType.None;
  214. //oldMember.OnPropertyChanged(nameof(oldMember.Selection));
  215. }
  216. doc.ClearSoftSelectedMembers();
  217. }
  218. private void ProcessAddSoftSelectedMember(AddSoftSelectedMember_PassthroughAction info)
  219. {
  220. IStructureMemberHandler? member = doc.StructureHelper.Find(info.Id);
  221. if (member is null || member.Selection == StructureMemberSelectionType.Hard)
  222. return;
  223. member.Selection = StructureMemberSelectionType.Soft;
  224. //member.OnPropertyChanged(nameof(member.Selection));
  225. doc.AddSoftSelectedMember(member);
  226. }
  227. private void ProcessSetSelectedMember(SetSelectedMember_PassthroughAction info)
  228. {
  229. IStructureMemberHandler? member = doc.StructureHelper.Find(info.Id);
  230. if (member is null || member.Selection == StructureMemberSelectionType.Hard)
  231. return;
  232. if (doc.SelectedStructureMember is { } oldMember)
  233. {
  234. oldMember.Selection = StructureMemberSelectionType.None;
  235. //oldMember.OnPropertyChanged(nameof(oldMember.Selection));
  236. }
  237. member.Selection = StructureMemberSelectionType.Hard;
  238. //member.OnPropertyChanged(nameof(member.Selection));
  239. doc.SetSelectedMember(member);
  240. }
  241. private void ProcessMaskIsVisible(StructureMemberMaskIsVisible_ChangeInfo info)
  242. {
  243. IStructureMemberHandler? member = doc.StructureHelper.FindOrThrow(info.Id);
  244. member.SetMaskIsVisible(info.IsVisible);
  245. }
  246. private void ProcessClipToMemberBelow(StructureMemberClipToMemberBelow_ChangeInfo info)
  247. {
  248. IStructureMemberHandler? member = doc.StructureHelper.FindOrThrow(info.Id);
  249. member.SetClipToMemberBelowEnabled(info.ClipToMemberBelow);
  250. }
  251. private void ProcessSymmetryPosition(SymmetryAxisPosition_ChangeInfo info)
  252. {
  253. if (info.Direction == SymmetryAxisDirection.Horizontal)
  254. doc.SetHorizontalSymmetryAxisY(info.NewPosition);
  255. else if (info.Direction == SymmetryAxisDirection.Vertical)
  256. doc.SetVerticalSymmetryAxisX(info.NewPosition);
  257. }
  258. private void ProcessSymmetryState(SymmetryAxisState_ChangeInfo info)
  259. {
  260. if (info.Direction == SymmetryAxisDirection.Horizontal)
  261. doc.SetHorizontalSymmetryAxisEnabled(info.State);
  262. else if (info.Direction == SymmetryAxisDirection.Vertical)
  263. doc.SetVerticalSymmetryAxisEnabled(info.State);
  264. }
  265. private void ProcessSelection(Selection_ChangeInfo info)
  266. {
  267. doc.UpdateSelectionPath(info.NewPath);
  268. }
  269. private void ProcessLayerLockTransparency(LayerLockTransparency_ChangeInfo info)
  270. {
  271. ILayerHandler? layer = (ILayerHandler)doc.StructureHelper.FindOrThrow(info.Id);
  272. layer.SetLockTransparency(info.LockTransparency);
  273. }
  274. private void ProcessStructureMemberBlendMode(StructureMemberBlendMode_ChangeInfo info)
  275. {
  276. IStructureMemberHandler? memberVm = doc.StructureHelper.FindOrThrow(info.Id);
  277. memberVm.SetBlendMode(info.BlendMode);
  278. }
  279. private void ProcessStructureMemberMask(StructureMemberMask_ChangeInfo info)
  280. {
  281. IStructureMemberHandler? memberVm = doc.StructureHelper.FindOrThrow(info.Id);
  282. memberVm.SetHasMask(info.HasMask);
  283. // TODO: Make sure HasMask raises property changed internally
  284. //memberVm.OnPropertyChanged(nameof(memberVm.MaskPreviewBitmap));
  285. if (!info.HasMask && memberVm is ILayerHandler layer)
  286. layer.ShouldDrawOnMask = false;
  287. }
  288. private void ProcessRefreshViewport(RefreshViewport_PassthroughAction info)
  289. {
  290. helper.State.Viewports[info.Info.Id] = info.Info;
  291. }
  292. private void ProcessRemoveViewport(RemoveViewport_PassthroughAction info)
  293. {
  294. helper.State.Viewports.Remove(info.Id);
  295. }
  296. private void ProcessSize(Size_ChangeInfo info)
  297. {
  298. VecI oldSize = doc.SizeBindable;
  299. foreach ((ChunkResolution res, Surface surf) in doc.Surfaces)
  300. {
  301. surf.Dispose();
  302. VecI size = (VecI)(info.Size * res.Multiplier());
  303. doc.Surfaces[res] = new Surface(new VecI(Math.Max(size.X, 1), Math.Max(size.Y, 1))); //TODO: Bgra8888 was here
  304. }
  305. doc.SetSize(info.Size);
  306. doc.SetVerticalSymmetryAxisX(info.VerticalSymmetryAxisX);
  307. doc.SetHorizontalSymmetryAxisY(info.HorizontalSymmetryAxisY);
  308. VecI documentPreviewSize = StructureHelpers.CalculatePreviewSize(info.Size);
  309. doc.PreviewSurface.Dispose();
  310. doc.PreviewSurface = new Surface(documentPreviewSize); //TODO: Bgra8888 was here
  311. // TODO: Make sure property changed events are raised internally
  312. // UPDATE: I think I did, but I'll leave it commented out for now
  313. /*doc.OnPropertyChanged(nameof(doc.LazyBitmaps));
  314. doc.OnPropertyChanged(nameof(doc.PreviewBitmap));
  315. doc.InternalRaiseSizeChanged(new DocumentSizeChangedEventArgs(doc, oldSize, info.Size));*/
  316. }
  317. private void ProcessCreateStructureMember(CreateStructureMember_ChangeInfo info)
  318. {
  319. IStructureMemberHandler memberVM;
  320. if (info is CreateLayer_ChangeInfo layerInfo)
  321. {
  322. memberVM = doc.NodeGraphHandler.AllNodes.FirstOrDefault(x => x.Id == info.Id) as ILayerHandler;
  323. ((ILayerHandler)memberVM).SetLockTransparency(layerInfo.LockTransparency);
  324. }
  325. else if (info is CreateFolder_ChangeInfo)
  326. {
  327. memberVM = doc.NodeGraphHandler.AllNodes.FirstOrDefault(x => x.Id == info.Id) as IFolderHandler;
  328. }
  329. else
  330. {
  331. throw new NotSupportedException();
  332. }
  333. memberVM.SetOpacity(info.Opacity);
  334. memberVM.SetIsVisible(info.IsVisible);
  335. memberVM.SetClipToMemberBelowEnabled(info.ClipToMemberBelow);
  336. memberVM.SetName(info.Name);
  337. memberVM.SetHasMask(info.HasMask);
  338. memberVM.SetMaskIsVisible(info.MaskIsVisible);
  339. memberVM.SetBlendMode(info.BlendMode);
  340. //parentFolderVM.Children.Insert(info.Index, memberVM);
  341. /*if (info is CreateFolder_ChangeInfo folderInfo)
  342. {
  343. foreach (CreateStructureMember_ChangeInfo childInfo in folderInfo.Children)
  344. {
  345. ProcessCreateStructureMember(childInfo);
  346. }
  347. }
  348. */
  349. if (doc.SelectedStructureMember is not null)
  350. {
  351. doc.SelectedStructureMember.Selection = StructureMemberSelectionType.None;
  352. // TODO: Make sure property changed events are raised internally
  353. //doc.SelectedStructureMember.OnPropertyChanged(nameof(doc.SelectedStructureMember.Selection));
  354. }
  355. doc.SetSelectedMember(memberVM);
  356. memberVM.Selection = StructureMemberSelectionType.Hard;
  357. // TODO: Make sure property changed events are raised internally
  358. /*doc.OnPropertyChanged(nameof(doc.SelectedStructureMember));
  359. doc.OnPropertyChanged(nameof(memberVM.Selection));*/
  360. //doc.InternalRaiseLayersChanged(new LayersChangedEventArgs(info.Id, LayerAction.Add));
  361. }
  362. private void ProcessDeleteStructureMember(DeleteStructureMember_ChangeInfo info)
  363. {
  364. IStructureMemberHandler memberVM = doc.StructureHelper.Find(info.Id);
  365. //folderVM.Children.Remove(memberVM);
  366. if (doc.SelectedStructureMember == memberVM)
  367. doc.SetSelectedMember(null);
  368. doc.ClearSoftSelectedMembers();
  369. // TODO: Make sure property changed events are raised internally
  370. //doc.InternalRaiseLayersChanged(new LayersChangedEventArgs(info.Id, LayerAction.Remove));
  371. }
  372. private void ProcessUpdateStructureMemberIsVisible(StructureMemberIsVisible_ChangeInfo info)
  373. {
  374. IStructureMemberHandler? memberVM = doc.StructureHelper.FindOrThrow(info.Id);
  375. memberVM.SetIsVisible(info.IsVisible);
  376. }
  377. private void ProcessUpdateStructureMemberName(StructureMemberName_ChangeInfo info)
  378. {
  379. IStructureMemberHandler? memberVM = doc.StructureHelper.FindOrThrow(info.Id);
  380. memberVM.SetName(info.Name);
  381. }
  382. private void ProcessUpdateStructureMemberOpacity(StructureMemberOpacity_ChangeInfo info)
  383. {
  384. IStructureMemberHandler? memberVM = doc.StructureHelper.FindOrThrow(info.Id);
  385. memberVM.SetOpacity(info.Opacity);
  386. }
  387. private void ProcessMoveStructureMember(MoveStructureMember_ChangeInfo info)
  388. {
  389. }
  390. private void ProcessCreateRasterKeyFrame(CreateRasterKeyFrame_ChangeInfo info)
  391. {
  392. doc.AnimationHandler.AddKeyFrame(new RasterKeyFrameViewModel(info.TargetLayerGuid, info.Frame, 1, info.KeyFrameId,
  393. (DocumentViewModel)doc, helper));
  394. }
  395. private void ProcessDeleteKeyFrame(DeleteKeyFrame_ChangeInfo info)
  396. {
  397. doc.AnimationHandler.RemoveKeyFrame(info.DeletedKeyFrameId);
  398. }
  399. private void ProcessActiveFrame(SetActiveFrame_PassthroughAction info)
  400. {
  401. doc.AnimationHandler.SetActiveFrame(info.Frame);
  402. }
  403. private void ProcessKeyFrameLength(KeyFrameLength_ChangeInfo info)
  404. {
  405. doc.AnimationHandler.SetFrameLength(info.KeyFrameGuid, info.StartFrame, info.Duration);
  406. }
  407. private void ProcessKeyFrameVisibility(KeyFrameVisibility_ChangeInfo info)
  408. {
  409. doc.AnimationHandler.SetKeyFrameVisibility(info.KeyFrameId, info.IsVisible);
  410. }
  411. private void ProcessAddSelectedKeyFrame(AddSelectedKeyFrame_PassthroughAction info)
  412. {
  413. doc.AnimationHandler.AddSelectedKeyFrame(info.KeyFrameGuid);
  414. }
  415. private void ProcessRemoveSelectedKeyFrame(RemoveSelectedKeyFrame_PassthroughAction info)
  416. {
  417. doc.AnimationHandler.RemoveSelectedKeyFrame(info.KeyFrameGuid);
  418. }
  419. private void ClearSelectedKeyFrames(ClearSelectedKeyFrames_PassthroughAction info)
  420. {
  421. doc.AnimationHandler.ClearSelectedKeyFrames();
  422. }
  423. private void ProcessCreateNode<T>(CreateNode_ChangeInfo info) where T : NodeViewModel, new()
  424. {
  425. T node = new T() {
  426. NodeName = info.NodeName, Id = info.Id,
  427. Document = (DocumentViewModel)doc, Internals = helper };
  428. node.SetPosition(info.Position);
  429. List<INodePropertyHandler> inputs = CreateProperties(info.Inputs, node, true);
  430. List<INodePropertyHandler> outputs = CreateProperties(info.Outputs, node, false);
  431. node.Inputs.AddRange(inputs);
  432. node.Outputs.AddRange(outputs);
  433. doc.NodeGraphHandler.AddNode(node);
  434. }
  435. private List<INodePropertyHandler> CreateProperties(ImmutableArray<NodePropertyInfo> source, NodeViewModel node, bool isInput)
  436. {
  437. List<INodePropertyHandler> inputs = new();
  438. foreach (var input in source)
  439. {
  440. var prop = NodePropertyViewModel.CreateFromType(input.ValueType, node);
  441. prop.DisplayName = input.DisplayName;
  442. prop.PropertyName = input.PropertyName;
  443. prop.IsInput = isInput;
  444. inputs.Add(prop);
  445. }
  446. return inputs;
  447. }
  448. private void ProcessDeleteNode(DeleteNode_ChangeInfo info)
  449. {
  450. doc.NodeGraphHandler.RemoveConnections(info.Id);
  451. doc.NodeGraphHandler.RemoveNode(info.Id);
  452. }
  453. private void ProcessConnectProperty(ConnectProperty_ChangeInfo info)
  454. {
  455. NodeViewModel outputNode = info.OutputNodeId.HasValue ? doc.StructureHelper.FindNode<NodeViewModel>(info.OutputNodeId.Value) : null;
  456. NodeViewModel inputNode = doc.StructureHelper.FindNode<NodeViewModel>(info.InputNodeId);
  457. if (inputNode != null && outputNode != null)
  458. {
  459. NodeConnectionViewModel connection = new NodeConnectionViewModel()
  460. {
  461. InputNode = inputNode,
  462. OutputNode = outputNode,
  463. InputProperty = inputNode.FindInputProperty(info.InputProperty),
  464. OutputProperty = outputNode.FindOutputProperty(info.OutputProperty)
  465. };
  466. doc.NodeGraphHandler.SetConnection(connection);
  467. }
  468. else
  469. {
  470. doc.NodeGraphHandler.RemoveConnection(info.InputNodeId, info.InputProperty);
  471. }
  472. }
  473. private void ProcessNodePosition(NodePosition_ChangeInfo info)
  474. {
  475. NodeViewModel node = doc.StructureHelper.FindNode<NodeViewModel>(info.NodeId);
  476. node.SetPosition(info.NewPosition);
  477. }
  478. }