From ceecb7d5a66ceddb8851bb71600d6e324d5fed61 Mon Sep 17 00:00:00 2001 From: John Lewin Date: Tue, 19 Sep 2017 17:22:37 -0700 Subject: [PATCH 1/2] Add InsertGroup type to manage adding multiple items to the scene --- .../ContentProviders/MeshContentProvider.cs | 1 - Library/Interfaces/LibraryExtensionMethods.cs | 53 ++++++++++++++ Library/Widgets/InsertionGroup.cs | 73 +++++++++++++++++++ Library/Widgets/PrintLibraryWidget.cs | 41 ++--------- MatterControl.csproj | 2 + 5 files changed, 135 insertions(+), 35 deletions(-) create mode 100644 Library/Interfaces/LibraryExtensionMethods.cs create mode 100644 Library/Widgets/InsertionGroup.cs diff --git a/Library/ContentProviders/MeshContentProvider.cs b/Library/ContentProviders/MeshContentProvider.cs index 3c61e00b4..a731d3f20 100644 --- a/Library/ContentProviders/MeshContentProvider.cs +++ b/Library/ContentProviders/MeshContentProvider.cs @@ -39,7 +39,6 @@ namespace MatterHackers.MatterControl using MatterHackers.Agg.Platform; using MatterHackers.DataConverters3D; using MatterHackers.MatterControl.Library; - using MatterHackers.MatterControl.PrinterCommunication; using MatterHackers.PolygonMesh; using MatterHackers.RayTracer; using MatterHackers.VectorMath; diff --git a/Library/Interfaces/LibraryExtensionMethods.cs b/Library/Interfaces/LibraryExtensionMethods.cs new file mode 100644 index 000000000..b30fc09ed --- /dev/null +++ b/Library/Interfaces/LibraryExtensionMethods.cs @@ -0,0 +1,53 @@ +/* +Copyright (c) 2017, John Lewin +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +using System; + +namespace MatterHackers.MatterControl.Library +{ + public static class LibraryExtensionMethods + { + public static ContentResult CreateContent(this ILibraryItem libraryItem, Action progressReporter) + { + if (ApplicationController.Instance.Library.GetContentProvider(libraryItem) is ISceneContentProvider contentProvider) + { + return contentProvider?.CreateItem(libraryItem, progressReporter); + } + + return null; + } + + public static bool IsContentFileType(this ILibraryItem item) + { + return item is ILibraryItem + || (item is ILibraryContentStream contentStream + && ApplicationController.Instance.Library.IsContentFileType(contentStream.FileName)); + } + } +} diff --git a/Library/Widgets/InsertionGroup.cs b/Library/Widgets/InsertionGroup.cs new file mode 100644 index 000000000..70ba8c5b4 --- /dev/null +++ b/Library/Widgets/InsertionGroup.cs @@ -0,0 +1,73 @@ +/* +Copyright (c) 2017, Kevin Pope, John Lewin +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of the FreeBSD Project. +*/ + +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using MatterHackers.DataConverters3D; +using MatterHackers.MatterControl.Library; +using MatterHackers.VectorMath; + +namespace MatterHackers.MatterControl.PrintLibrary +{ + public class InsertionGroup : Object3D + { + // TODO: Figure out how to collapse the InsertionGroup after the load task completes + public InsertionGroup(IEnumerable items) + { + Task.Run(async () => + { + var newItemOffset = Vector2.Zero; + + // Filter to content file types only + foreach (var item in items.Where(item => item.IsContentFileType())) + { + // Acquire + var contentResult = item.CreateContent(null); + if (contentResult != null) + { + // Add the placeholder + var object3D = contentResult.Object3D; + this.Children.Add(object3D); + + // Position at accumulating offset + object3D.Matrix *= Matrix4X4.CreateTranslation(newItemOffset.x, newItemOffset.y, 0); + + // Wait for content to load + await contentResult.MeshLoaded; + + // Adjust next item position + // TODO: do something more interesting than increment in x + newItemOffset.x += contentResult.Object3D.GetAxisAlignedBoundingBox(Matrix4X4.Identity).XSize; + } + } + }); + } + } +} diff --git a/Library/Widgets/PrintLibraryWidget.cs b/Library/Widgets/PrintLibraryWidget.cs index f4b1a45ac..8c9cda45f 100644 --- a/Library/Widgets/PrintLibraryWidget.cs +++ b/Library/Widgets/PrintLibraryWidget.cs @@ -34,15 +34,12 @@ using System.Linq; using MatterHackers.Agg; using MatterHackers.Agg.Platform; using MatterHackers.Agg.UI; -using MatterHackers.Agg.VertexSource; using MatterHackers.DataConverters3D; using MatterHackers.Localizations; using MatterHackers.MatterControl.CustomWidgets; -using MatterHackers.MatterControl.DataStorage; using MatterHackers.MatterControl.Library; using MatterHackers.MatterControl.PartPreviewWindow; using MatterHackers.MatterControl.PrintQueue; -using MatterHackers.VectorMath; namespace MatterHackers.MatterControl.PrintLibrary { @@ -388,42 +385,18 @@ namespace MatterHackers.MatterControl.PrintLibrary var library = ApplicationController.Instance.Library; - foreach (var item in selectedLibraryItems) - { - if (item is ILibraryContentStream contentModel) - { - var contentProvider = library.GetContentProvider(item) as ISceneContentProvider; - - var result = contentProvider?.CreateItem(item, null); - - // Wait for the content to load - await result.MeshLoaded; - - if (result?.Object3D != null) - { - itemsToAdd.Add(result.Object3D); - } - } - else if (item is ILibraryContentItem contentItem) - { - var content = await contentItem.GetContent(null); - if (content != null) - { - itemsToAdd.Add(content); - } - } - } - ApplicationController.Instance.ActiveView3DWidget.partHasBeenEdited = true; var scene = ApplicationController.Instance.DragDropData.Scene; scene.ModifyChildren(children => { - foreach (var sceneItem in itemsToAdd) - { - PlatingHelper.MoveToOpenPosition(sceneItem, children); - children.Add(sceneItem); - } + children.Add(new InsertionGroup(selectedLibraryItems)); + + //foreach (var sceneItem in itemsToAdd) + //{ + // PlatingHelper.MoveToOpenPosition(sceneItem, children); + // children.Add(sceneItem); + //} }); } }); diff --git a/MatterControl.csproj b/MatterControl.csproj index df2b09d0b..cd2454e95 100644 --- a/MatterControl.csproj +++ b/MatterControl.csproj @@ -144,6 +144,8 @@ + + Form From 74c561f656646812547b10ef41d010f775d2c5f2 Mon Sep 17 00:00:00 2001 From: John Lewin Date: Tue, 19 Sep 2017 19:59:55 -0700 Subject: [PATCH 2/2] Rewrite library/view3D DragDrop for multi-select and clarity --- ApplicationView/ApplicationController.cs | 2 +- Library/Providers/LibraryConfig.cs | 25 +- Library/Widgets/ListView/IconListView.cs | 5 - Library/Widgets/ListView/ListViewItemBase.cs | 72 +--- Library/Widgets/PrintLibraryWidget.cs | 14 +- PartPreviewWindow/View3D/View3DWidget.cs | 349 ++++++------------- 6 files changed, 130 insertions(+), 337 deletions(-) diff --git a/ApplicationView/ApplicationController.cs b/ApplicationView/ApplicationController.cs index fcbf76c37..c41671725 100644 --- a/ApplicationView/ApplicationController.cs +++ b/ApplicationView/ApplicationController.cs @@ -632,7 +632,7 @@ namespace MatterHackers.MatterControl public View3DWidget ActiveView3DWidget { get; internal set; } public string PrintingItemName { get; set; } - + public string CachePath(ILibraryItem libraryItem) { // TODO: Use content SHA diff --git a/Library/Providers/LibraryConfig.cs b/Library/Providers/LibraryConfig.cs index 87ba48ed4..ba7267f27 100644 --- a/Library/Providers/LibraryConfig.cs +++ b/Library/Providers/LibraryConfig.cs @@ -31,7 +31,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using MatterHackers.Agg.Platform; +using MatterHackers.MatterControl.CustomWidgets; namespace MatterHackers.MatterControl.Library { @@ -62,38 +62,21 @@ namespace MatterHackers.MatterControl.Library // TODO: Needed? public event EventHandler LibraryItemsChanged; - /// - /// Storage for plugin 'Creators' added via RegisterCreator - /// - //private CreatorsContainer registeredCreators; - private List libraryProviders; private ILibraryContainer activeContainer; public LibraryConfig() { - //registeredCreators = new CreatorsContainer() - //{ - // Name = "Creators", - // ChildContainers = new List(), - // Items = new List() - //}; - - libraryProviders = new List() - { - /* - new DynamicContainerLink( - registeredCreators.Name, - AggContext.StaticData.LoadIcon("icon_creator.png"), - () => registeredCreators), */ - }; + libraryProviders = new List(); this.RootLibaryContainer = new RootLibraryContainer(libraryProviders); this.ActiveContainer = this.RootLibaryContainer; } + public ListView ActiveViewWidget { get; internal set; } + public ILibraryContainer RootLibaryContainer { get; } public Dictionary ContentProviders = new Dictionary(); diff --git a/Library/Widgets/ListView/IconListView.cs b/Library/Widgets/ListView/IconListView.cs index d0754df43..b77d28a34 100644 --- a/Library/Widgets/ListView/IconListView.cs +++ b/Library/Widgets/ListView/IconListView.cs @@ -172,11 +172,6 @@ namespace MatterHackers.MatterControl.CustomWidgets Margin = 0, }; - imageWidget.Click += (sender, e) => - { - this.OnItemSelect(); - }; - container.AddChild(imageWidget); int maxWidth = thumbWidth - 4; diff --git a/Library/Widgets/ListView/ListViewItemBase.cs b/Library/Widgets/ListView/ListViewItemBase.cs index d0da26986..ec34f1f93 100644 --- a/Library/Widgets/ListView/ListViewItemBase.cs +++ b/Library/Widgets/ListView/ListViewItemBase.cs @@ -246,66 +246,29 @@ namespace MatterHackers.MatterControl.CustomWidgets mouseDownInBounds = true; mouseDownAt = mouseEvent.Position; + // Force selection in mousedown to ensure DragDropOperations see the item in ListView.SelectedItems - no worse than common tab behavior that apply on mousedown + this.OnItemSelect(); + if (IsDoubleClick(mouseEvent)) { listViewItem.OnDoubleClick(); } // On mouse down update the view3DWidget reference that will be used in MouseMove and MouseUp - view3DWidget = ApplicationController.Instance.ActiveView3DWidget; + view3DWidget = ApplicationController.Instance.DragDropData.View3DWidget; base.OnMouseDown(mouseEvent); } - - private bool contentLoadActive = false; - public override void OnMouseMove(MouseEventArgs mouseEvent) { var delta = mouseDownAt - mouseEvent.Position; - // TODO: dragActive in this case is better determined by the mouse being over the View3D control - bool dragActive = mouseDownInBounds && delta.Length > 40; - - // If dragging and the drag threshold has been hit, start a drag operation but loading the drag items - if (dragActive - && (listViewItem.Model is ILibraryContentStream || listViewItem.Model is ILibraryContentItem)) + // If mouseDown on us and we've moved past are drag determination threshold, notify view3DWidget + if (mouseDownInBounds && delta.Length > 40) { - if (view3DWidget != null - && !contentLoadActive - && view3DWidget.DragDropSource == null) - { - contentLoadActive = true; - - if (listViewItem.Model is ILibraryContentStream contentModel) - { - // Update the ListView pointer for the dragging item - listViewItem.ListView.DragSourceRowItem = listViewItem; - - var progressBar = new DragDropLoadProgress(this.view3DWidget, null); - - var contentResult = contentModel.CreateContent(progressBar.ProgressReporter); - - progressBar.TrackingObject = contentResult.Object3D; - - // Assign a new drag source - view3DWidget.DragDropSource = contentResult?.Object3D; - - contentLoadActive = false; - } - else if (listViewItem.Model is ILibraryContentItem contentItem) - { - contentItem.GetContent(null).ContinueWith((task) => - { - view3DWidget.DragDropSource = task.Result; - contentLoadActive = false; - }); - } - } - - // Performs move in View3DWidget and indicates if add occurred - var screenSpaceMousePosition = this.TransformToScreenSpace(mouseEvent.Position); - view3DWidget.AltDragOver(screenSpaceMousePosition); + // Performs move and possible Scene add in View3DWidget + view3DWidget.ExternalDragOver(screenSpaceMousePosition: this.TransformToScreenSpace(mouseEvent.Position)); } base.OnMouseMove(mouseEvent); @@ -314,27 +277,14 @@ namespace MatterHackers.MatterControl.CustomWidgets public override void OnMouseUp(MouseEventArgs mouseEvent) { var dropData = ApplicationController.Instance.DragDropData; - - if (dropData.View3DWidget?.DragDropSource != null && dropData.Scene.Children.Contains(view3DWidget.DragDropSource)) + if (dropData.View3DWidget?.DragOperationActive == true) { // Mouse and widget positions var screenSpaceMousePosition = this.TransformToScreenSpace(mouseEvent.Position); var meshViewerPosition = this.view3DWidget.meshViewerWidget.TransformToScreenSpace(view3DWidget.meshViewerWidget.LocalBounds); - // If the mouse is not within the meshViewer, remove the inserted drag item - if (!meshViewerPosition.Contains(screenSpaceMousePosition)) - { - dropData.Scene.ModifyChildren(children => children.Remove(view3DWidget.DragDropSource)); - dropData.Scene.ClearSelection(); - } - else - { - // Create and push the undo operation - view3DWidget.AddUndoOperation( - new InsertCommand(view3DWidget, dropData.Scene, view3DWidget.DragDropSource)); - } - - view3DWidget.FinishDrop(); + // Notify of drag operation complete + view3DWidget.FinishDrop(mouseUpInBounds: meshViewerPosition.Contains(screenSpaceMousePosition)); } mouseDownInBounds = false; diff --git a/Library/Widgets/PrintLibraryWidget.cs b/Library/Widgets/PrintLibraryWidget.cs index 8c9cda45f..e99d1fd6b 100644 --- a/Library/Widgets/PrintLibraryWidget.cs +++ b/Library/Widgets/PrintLibraryWidget.cs @@ -77,6 +77,8 @@ namespace MatterHackers.MatterControl.PrintLibrary BackgroundColor = ActiveTheme.Instance.TertiaryBackgroundColor, }; + ApplicationController.Instance.Library.ActiveViewWidget = libraryView; + libraryView.SelectedItems.CollectionChanged += SelectedItems_CollectionChanged; ApplicationController.Instance.Library.ContainerChanged += Library_ContainerChanged; @@ -381,22 +383,10 @@ namespace MatterHackers.MatterControl.PrintLibrary AllowContainers = false, Action = async (selectedLibraryItems, listView) => { - var itemsToAdd = new List(); - - var library = ApplicationController.Instance.Library; - - ApplicationController.Instance.ActiveView3DWidget.partHasBeenEdited = true; - var scene = ApplicationController.Instance.DragDropData.Scene; scene.ModifyChildren(children => { children.Add(new InsertionGroup(selectedLibraryItems)); - - //foreach (var sceneItem in itemsToAdd) - //{ - // PlatingHelper.MoveToOpenPosition(sceneItem, children); - // children.Add(sceneItem); - //} }); } }); diff --git a/PartPreviewWindow/View3D/View3DWidget.cs b/PartPreviewWindow/View3D/View3DWidget.cs index 4851fb2ea..b4b619f39 100644 --- a/PartPreviewWindow/View3D/View3DWidget.cs +++ b/PartPreviewWindow/View3D/View3DWidget.cs @@ -50,6 +50,7 @@ using MatterHackers.MatterControl.CustomWidgets; using MatterHackers.MatterControl.DataStorage; using MatterHackers.MatterControl.Library; using MatterHackers.MatterControl.PrinterCommunication; +using MatterHackers.MatterControl.PrintLibrary; using MatterHackers.MatterControl.PrintQueue; using MatterHackers.MatterControl.SlicerConfiguration; using MatterHackers.MeshVisualizer; @@ -583,31 +584,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow } } - public ILibraryContentStream DragSourceModel { get; set; } - - // TODO: Rename to DragDropItem - - private IObject3D dragDropSource; - public IObject3D DragDropSource - { - get - { - return dragDropSource; - } - - set - { - // - dragDropSource = value; - - // Clear the DragSourceModel - - DragSourceModel = null; - - // Suppress ui volumes when dragDropSource is not null - meshViewerWidget.SuppressUiVolumes = (dragDropSource != null); - } - } - private void TrackballTumbleWidget_DrawGlContent(object sender, DrawEventArgs e) { if (CurrentSelectInfo.DownOnPart @@ -851,42 +827,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow base.OnClosed(e); } - public override void OnMouseEnterBounds(MouseEventArgs mouseEvent) - { - if (mouseEvent.DragFiles?.Count > 0) - { - if (AllowDragDrop()) - { - mouseEvent.AcceptDrop = mouseEvent.DragFiles.TrueForAll(filePath => ApplicationController.Instance.IsLoadableFile(filePath)); - - if (mouseEvent.AcceptDrop) - { - string filePath = mouseEvent.DragFiles.FirstOrDefault(); - string extensionWithoutPeriod = Path.GetExtension(filePath).Trim('.'); - - IContentProvider contentProvider; - if (!string.IsNullOrEmpty(filePath) - && ApplicationController.Instance.Library.ContentProviders.TryGetValue(extensionWithoutPeriod, out contentProvider) - && contentProvider is ISceneContentProvider) - { - var sceneProvider = contentProvider as ISceneContentProvider; - this.DragDropSource = sceneProvider.CreateItem(new FileSystemFileItem(filePath), null).Object3D; - } - else - { - this.DragDropSource = new Object3D - { - ItemType = Object3DTypes.Model, - Mesh = PlatonicSolids.CreateCube(10, 10, 10) - }; - } - } - } - } - - base.OnMouseEnterBounds(mouseEvent); - } - public override void OnVisibleChanged(EventArgs e) { var dragDropData = ApplicationController.Instance.DragDropData; @@ -912,89 +852,119 @@ namespace MatterHackers.MatterControl.PartPreviewWindow private PlaneShape bedPlane = new PlaneShape(Vector3.UnitZ, 0, null); + public bool DragOperationActive { get; private set; } + + public IObject3D DragDropObject { get; private set; } + /// /// Provides a View3DWidget specific drag implementation /// /// The screen space mouse position. - /// A value indicating if a new item was generated for the DragDropSource and added to the scene - public bool AltDragOver(Vector2 screenSpaceMousePosition) + public void ExternalDragOver(Vector2 screenSpaceMousePosition) { - if (this.HasBeenClosed || this.DragDropSource == null) + if (this.HasBeenClosed) { - return false; + return; } - bool itemAddedToScene = false; - + // If the mouse is within the MeshViewer process the Drag move var meshViewerPosition = this.meshViewerWidget.TransformToScreenSpace(meshViewerWidget.LocalBounds); - - // If the mouse is within this control - if (meshViewerPosition.Contains(screenSpaceMousePosition) - && this.DragDropSource != null) + if (meshViewerPosition.Contains(screenSpaceMousePosition)) { - var localPosition = this.TransformFromParentSpace(topMostParent, screenSpaceMousePosition); - - // Inject the DragDropSource if it's missing from the scene, using the default "loading" mesh - if (!Scene.Children.Contains(DragDropSource)) + // If already started, process drag move + if (this.DragOperationActive) { - // Set the hitplane to the bed plane - CurrentSelectInfo.HitPlane = bedPlane; + this.DragOver(screenSpaceMousePosition); + } + else + { + // Otherwise begin an externally started DragDropOperation hard-coded to use LibraryView->SelectedItems - // Find intersection position of the mouse with the bed plane - var intersectInfo = GetIntersectPosition(screenSpaceMousePosition); - if (intersectInfo == null) - { - return false; - } - - // Set the initial transform on the inject part to the current transform mouse position - var sourceItemBounds = DragDropSource.GetAxisAlignedBoundingBox(Matrix4X4.Identity); - var center = sourceItemBounds.Center; - - DragDropSource.Matrix *= Matrix4X4.CreateTranslation(-center.x, -center.y, -sourceItemBounds.minXYZ.z); - DragDropSource.Matrix *= Matrix4X4.CreateTranslation(new Vector3(intersectInfo.HitPosition)); - - CurrentSelectInfo.PlaneDownHitPos = intersectInfo.HitPosition; - CurrentSelectInfo.LastMoveDelta = Vector3.Zero; - - this.deferEditorTillMouseUp = true; - - // Add item to scene and select it - Scene.ModifyChildren(children => - { - children.Add(DragDropSource); - }); - Scene.SelectedItem = DragDropSource; - - itemAddedToScene = true; + this.StartDragDrop( + // Project from ListViewItem to ILibraryItem + ApplicationController.Instance.Library.ActiveViewWidget.SelectedItems.Select(l => l.Model), + screenSpaceMousePosition); } - // Move the object being dragged - if (Scene.HasSelection) - { - // Pass the mouse position, transformed to local cords, through to the view3D widget to move the target item - localPosition = meshViewerWidget.TransformFromScreenSpace(screenSpaceMousePosition); - DragSelectedObject(localPosition); - } - - return itemAddedToScene; + } - - return false; } - internal void FinishDrop() + private void DragOver(Vector2 screenSpaceMousePosition) { - this.DragDropSource = null; - this.DragSourceModel = null; + // Move the object being dragged + if (this.DragOperationActive + && this.DragDropObject != null) + { + // Move the DropDropObject the target item + DragSelectedObject(localMousePostion: this.TransformFromParentSpace(topMostParent, screenSpaceMousePosition)); + } + } - this.deferEditorTillMouseUp = false; - Scene_SelectionChanged(null, null); + private void StartDragDrop(IEnumerable items, Vector2 screenSpaceMousePosition) + { + this.DragOperationActive = true; - this.PartHasBeenChanged(); + // Set the hitplane to the bed plane + CurrentSelectInfo.HitPlane = bedPlane; - // Set focus to View3DWidget after drag-drop - UiThread.RunOnIdle(this.Focus); + DragDropObject = new InsertionGroup(items); + + // Find intersection position of the mouse with the bed plane + var intersectInfo = GetIntersectPosition(screenSpaceMousePosition); + if (intersectInfo != null) + { + // Set the initial transform on the inject part to the current transform mouse position + var sourceItemBounds = DragDropObject.GetAxisAlignedBoundingBox(Matrix4X4.Identity); + var center = sourceItemBounds.Center; + + this.DragDropObject.Matrix *= Matrix4X4.CreateTranslation(-center.x, -center.y, -sourceItemBounds.minXYZ.z); + this.DragDropObject.Matrix *= Matrix4X4.CreateTranslation(new Vector3(intersectInfo.HitPosition)); + + CurrentSelectInfo.PlaneDownHitPos = intersectInfo.HitPosition; + CurrentSelectInfo.LastMoveDelta = Vector3.Zero; + } + + this.deferEditorTillMouseUp = true; + + // Add item to scene and select it + this.Scene.ModifyChildren(children => + { + children.Add(this.DragDropObject); + }); + Scene.SelectedItem = this.DragDropObject; + + } + + internal void FinishDrop(bool mouseUpInBounds) + { + if (this.DragOperationActive) + { + this.DragOperationActive = false; + + if (mouseUpInBounds) + { + // Create and push the undo operation + this.AddUndoOperation( + new InsertCommand(this, this.Scene, this.DragDropObject)); + } + else + { + Scene.ModifyChildren(children => children.Remove(this.DragDropObject)); + Scene.ClearSelection(); + } + + this.DragDropObject = null; + + this.deferEditorTillMouseUp = false; + Scene_SelectionChanged(null, null); + + this.PartHasBeenChanged(); + + // Set focus to View3DWidget after drag-drop + UiThread.RunOnIdle(this.Focus); + + } } public override void OnLoad(EventArgs args) @@ -1009,86 +979,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow base.OnLoad(args); } - /// - /// Loads the referenced DragDropSource object. - /// - /// The drag source at the original time of invocation. - /// - public async Task LoadDragSource(ListViewItem sourceListItem) - { - // Hold initial reference - IObject3D dragDropItem = DragDropSource; - if (dragDropItem == null) - { - return; - } - - this.DragSourceModel = sourceListItem?.Model as ILibraryContentStream; - - IObject3D loadedItem = await Task.Run(async () => - { - if (File.Exists(dragDropItem.MeshPath)) - { - string extensionWithoutPeriod = Path.GetExtension(dragDropItem.MeshPath).Trim('.'); - - if (ApplicationController.Instance.Library.ContentProviders.ContainsKey(extensionWithoutPeriod)) - { - return null; - } - else - { - return Object3D.Load(dragDropItem.MeshPath, CancellationToken.None, progress: new DragDropLoadProgress(this, dragDropItem).ProgressReporter); - } - } - else if (DragSourceModel != null) - { - var loadProgress = new DragDropLoadProgress(this, dragDropItem); - - ContentResult contentResult; - - if (sourceListItem == null) - { - contentResult = DragSourceModel.CreateContent(loadProgress.ProgressReporter); - await contentResult.MeshLoaded; - } - else - { - sourceListItem.StartProgress(); - - contentResult = DragSourceModel.CreateContent((double ratio, string state) => - { - sourceListItem.ProgressReporter(ratio, state); - loadProgress.ProgressReporter(ratio, state); - }); - - await contentResult.MeshLoaded; - - sourceListItem.EndProgress(); - - loadProgress.ProgressReporter(1, ""); - } - - return contentResult?.Object3D; - } - - return null; - }); - - if (loadedItem != null) - { - Vector3 meshGroupCenter = loadedItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity).Center; - - dragDropItem.Mesh = loadedItem.Mesh; - dragDropItem.Children = loadedItem.Children; - - // TODO: jlewin - also need to apply the translation to the scale/rotation from the source (loadedItem.Matrix) - dragDropItem.Matrix = loadedItem.Matrix * dragDropItem.Matrix; - dragDropItem.Matrix *= Matrix4X4.CreateTranslation(-meshGroupCenter.x, -meshGroupCenter.y, -dragDropItem.GetAxisAlignedBoundingBox(Matrix4X4.Identity).minXYZ.z); - } - - this.PartHasBeenChanged(); - } - public override void OnDraw(Graphics2D graphics2D) { if (Scene.HasSelection) @@ -1491,29 +1381,28 @@ namespace MatterHackers.MatterControl.PartPreviewWindow public override void OnMouseMove(MouseEventArgs mouseEvent) { - if (AllowDragDrop() && mouseEvent.DragFiles?.Count == 1) + // File system Drop validation + mouseEvent.AcceptDrop = this.AllowDragDrop() + && mouseEvent.DragFiles?.Count > 0 + && mouseEvent.DragFiles.TrueForAll(filePath => ApplicationController.Instance.IsLoadableFile(filePath)); + + // View3DWidgets Filesystem DropDrop handler + if (mouseEvent.AcceptDrop + && this.PositionWithinLocalBounds(mouseEvent.X, mouseEvent.Y)) { - var screenSpaceMousePosition = this.TransformToScreenSpace(new Vector2(mouseEvent.X, mouseEvent.Y)); - - // If the DragDropSource was added to the scene on this DragOver call, we start a task to replace - // the "loading" mesh with the actual file contents - if (AltDragOver(screenSpaceMousePosition)) + if (this.DragOperationActive) { - this.DragDropSource.MeshPath = mouseEvent.DragFiles.FirstOrDefault(); - - // Run the rest of the OnDragOver pipeline since we're starting a new thread and won't finish for an unknown time - base.OnMouseMove(mouseEvent); - - LoadDragSource(null); - - // Don't fall through to the base.OnDragOver because we preemptively invoked it above - return; + DragOver(screenSpaceMousePosition: this.TransformToScreenSpace(mouseEvent.Position)); + } + else + { + // Project DragFiles to IEnumerable + this.StartDragDrop( + mouseEvent.DragFiles.Select(path => new FileSystemFileItem(path)), + screenSpaceMousePosition: this.TransformToScreenSpace(mouseEvent.Position)); } } - // AcceptDrop anytime a DropSource has been queued - mouseEvent.AcceptDrop = this.DragDropSource != null; - if (CurrentSelectInfo.DownOnPart && this.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None) { DragSelectedObject(new Vector2(mouseEvent.X, mouseEvent.Y)); @@ -1563,23 +1452,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow public override void OnMouseUp(MouseEventArgs mouseEvent) { - if (mouseEvent.DragFiles?.Count > 0) + if (this.DragOperationActive) { - if (AllowDragDrop() && mouseEvent.DragFiles.Count == 1) - { - // Item is already in the scene - this.DragDropSource = null; - } - else if (AllowDragDrop()) - { - // Items need to be added to the scene - var partsToAdd = mouseEvent.DragFiles.Where(filePath => ApplicationController.Instance.IsLoadableFile(filePath)).ToArray(); - - if (partsToAdd.Length > 0) - { - loadAndAddPartsToPlate(partsToAdd); - } - } + this.FinishDrop(mouseUpInBounds: true); } if (this.TrackballTumbleWidget.TransformState == TrackBallController.MouseDownType.None)