Przeglądaj źródła

Working Project Window selection dragging

Marko Pintera 10 lat temu
rodzic
commit
d90a800eb0

+ 2 - 0
BansheeEditor/Include/BsBuiltinEditorResources.h

@@ -300,6 +300,8 @@ namespace BansheeEngine
 		static const WString ProgressBarFillTex;
 		static const WString ProgressBarBgTex;
 
+		static const WString SelectionAreaTex;
+
 		static const WString ShaderDockOverlayFile;
 		static const WString ShaderSceneGridFile;
 		static const WString ShaderPickingCullNoneFile;

+ 12 - 0
BansheeEditor/Source/BsBuiltinEditorResources.cpp

@@ -209,6 +209,8 @@ namespace BansheeEngine
 	const WString BuiltinEditorResources::ProgressBarFillTex = L"ProgressBarFill.psd";
 	const WString BuiltinEditorResources::ProgressBarBgTex = L"ProgressBarBg.psd";
 
+	const WString BuiltinEditorResources::SelectionAreaTex = L"SelectionHighlight.psd";
+
 	/************************************************************************/
 	/* 									SHADERS                      		*/
 	/************************************************************************/
@@ -1241,6 +1243,16 @@ namespace BansheeEngine
 
 		skin->setStyle("RightAlignedLabel", rightAlignedLabelStyle);
 
+		// Selection area
+		GUIElementStyle selectionAreaStyle;
+		selectionAreaStyle.normal.texture = getGUITexture(SelectionAreaTex);
+		selectionAreaStyle.border.left = 1;
+		selectionAreaStyle.border.right = 1;
+		selectionAreaStyle.border.top = 1;
+		selectionAreaStyle.border.bottom = 1;
+
+		skin->setStyle("SelectionArea", selectionAreaStyle);
+
 		return skin;
 	}
 

+ 1 - 0
MBansheeEditor/EditorStyles.cs

@@ -17,5 +17,6 @@ namespace BansheeEditor
         public const string ColorSliderHorz = "ColorSliderHorz";
         public const string ColorSliderVert = "ColorSliderVert";
         public const string ColorSlider2DHandle = "ColorSlider2DHandle";
+        public const string SelectionArea = "SelectionArea";
     }
 }

+ 12 - 1
MBansheeEditor/ProjectDropTarget.cs

@@ -14,6 +14,7 @@ namespace BansheeEditor
         public Action<Vector2I> OnEnter;
         public Action OnLeave;
         public Action<Vector2I> OnDrag;
+        public Action<Vector2I> OnEnd;
 
         private readonly EditorWindow parentWindow;
 
@@ -23,6 +24,7 @@ namespace BansheeEditor
         private bool isMouseDown;
         private bool isDragInProgress;
         private bool triggerStartDrag;
+        private bool triggerEndDrag;
         private bool isDragInBounds;
         private bool isOSDragActive;
         private Vector2I mouseDownScreenPos;
@@ -74,6 +76,7 @@ namespace BansheeEditor
             isDragInProgress = false;
             isMouseDown = false;
             isDragInBounds = false;
+            triggerEndDrag = true;
         }
 
         void Input_OnPointerPressed(PointerEvent ev)
@@ -95,10 +98,18 @@ namespace BansheeEditor
                     OnStart(currentWindowPos);
             }
 
+            if (triggerEndDrag)
+            {
+                triggerEndDrag = false;
+
+                if (OnEnd != null)
+                    OnEnd(currentWindowPos);
+            }
+
             if (isOSDragActive)
                 return;
 
-            if (DragDrop.DragInProgress && DragDrop.Type == DragDropType.Resource)
+            if (isDragInProgress)
             {
                 if (lastDragWindowPos != currentWindowPos)
                 {

+ 156 - 21
MBansheeEditor/ProjectWindow.cs

@@ -317,6 +317,7 @@ namespace BansheeEditor
         private GUILayout folderBarLayout;
         private GUILayout folderListLayout;
         private GUITextField searchField;
+        private GUITexture dragSelection;
 
         private ContextMenu entryContextMenu;
         private ProjectDropTarget dropTarget;
@@ -325,6 +326,9 @@ namespace BansheeEditor
         private Dictionary<string, ElementEntry> entryLookup = new Dictionary<string, ElementEntry>();
 
         private int autoScrollAmount;
+        private bool isDraggingSelection;
+        private Vector2I dragSelectionStart;
+        private Vector2I dragSelectionEnd;
 
         // Cut/Copy/Paste
         private List<string> copyPaths = new List<string>();
@@ -390,14 +394,12 @@ namespace BansheeEditor
             dropTarget.OnDrag += DoOnDragMove;
             dropTarget.OnLeave += DoOnDragLeave;
             dropTarget.OnDrop += DoOnDragDropped;
+            dropTarget.OnEnd += DoOnDragEnd;
         }
 
         private ElementEntry FindElementAt(Vector2I windowPos)
         {
-            Rect2I scrollBounds = contentScrollArea.Layout.Bounds;
-            Vector2I scrollPos = windowPos;
-            scrollPos.x -= scrollBounds.x;
-            scrollPos.y -= scrollBounds.y;
+            Vector2I scrollPos = WindowToScrollAreaCoords(windowPos);
 
             foreach (var element in entries)
             {
@@ -408,14 +410,26 @@ namespace BansheeEditor
             return null;
         }
 
+        private ElementEntry[] FindElementsOverlapping(Rect2I scrollBounds)
+        {
+            List<ElementEntry> elements = new List<ElementEntry>();
+            foreach (var element in entries)
+            {
+                if(element.Bounds.Overlaps(scrollBounds))
+                    elements.Add(element);
+            }
+
+            return elements.ToArray();
+        }
+
         private void DoOnDragStart(Vector2I windowPos)
         {
             ElementEntry underCursorElem = FindElementAt(windowPos);
-            if (underCursorElem == null)
+            if (underCursorElem == null || !selectionPaths.Contains(underCursorElem.path))
+            {
+                StartDragSelection(windowPos);
                 return;
-
-            if (!selectionPaths.Contains(underCursorElem.path))
-                Select(underCursorElem.path);
+            }
 
             ResourceDragDropData dragDropData = new ResourceDragDropData(selectionPaths.ToArray());
             DragDrop.StartDrag(dragDropData);
@@ -423,6 +437,23 @@ namespace BansheeEditor
 
         private void DoOnDragMove(Vector2I windowPos)
         {
+            // Auto-scroll
+            Rect2I scrollAreaBounds = contentScrollArea.Bounds;
+            int scrollAreaTop = scrollAreaBounds.y;
+            int scrollAreaBottom = scrollAreaBounds.y + scrollAreaBounds.height;
+
+            if (windowPos.y > scrollAreaTop && windowPos.y <= (scrollAreaTop + DRAG_SCROLL_HEIGHT))
+                autoScrollAmount = -DRAG_SCROLL_AMOUNT_PER_SECOND;
+            else if (windowPos.y >= (scrollAreaBottom - DRAG_SCROLL_HEIGHT) && windowPos.y < scrollAreaBottom)
+                autoScrollAmount = DRAG_SCROLL_AMOUNT_PER_SECOND;
+            else
+                autoScrollAmount = 0;
+
+            // Selection box
+            if (UpdateDragSelection(windowPos))
+                return;
+
+            // Drag and drop (hover element under cursor)
             ElementEntry underCursorElem = FindElementAt(windowPos);
             
             if (underCursorElem == null)
@@ -439,17 +470,6 @@ namespace BansheeEditor
                     underCursorElem.MarkAsHovered(true);
                 }
             }
-
-            Rect2I scrollAreaBounds = contentScrollArea.Bounds;
-            int scrollAreaTop = scrollAreaBounds.y;
-            int scrollAreaBottom = scrollAreaBounds.y + scrollAreaBounds.height;
-
-            if (windowPos.y > scrollAreaTop && windowPos.y <= (scrollAreaTop + DRAG_SCROLL_HEIGHT))
-                autoScrollAmount = -DRAG_SCROLL_AMOUNT_PER_SECOND;
-            else if (windowPos.y >= (scrollAreaBottom - DRAG_SCROLL_HEIGHT) && windowPos.y < scrollAreaBottom)
-                autoScrollAmount = DRAG_SCROLL_AMOUNT_PER_SECOND;
-            else
-                autoScrollAmount = 0;
         }
 
         private void DoOnDragLeave()
@@ -460,6 +480,12 @@ namespace BansheeEditor
 
         private void DoOnDragDropped(Vector2I windowPos, string[] paths)
         {
+            ClearHoverHighlight();
+            autoScrollAmount = 0;
+
+            if (EndDragSelection())
+                return;
+
             string resourceDir = ProjectLibrary.ResourceFolder;
             string destinationFolder = Path.Combine(resourceDir, currentDirectory);
 
@@ -496,9 +522,11 @@ namespace BansheeEditor
                         ProjectLibrary.Copy(path, destination, true);
                 }
             }
+        }
 
-            ClearHoverHighlight();
-            autoScrollAmount = 0;
+        private void DoOnDragEnd(Vector2I windowPos)
+        {
+            EndDragSelection();
         }
 
         private void ClearHoverHighlight()
@@ -1018,6 +1046,113 @@ namespace BansheeEditor
             catchAll.OnFocusChanged += OnContentsFocusChanged;
 
             contentInfo.underlay.AddElement(catchAll);
+
+            UpdateDragSelection(dragSelectionEnd);
+        }
+
+        private Vector2I WindowToScrollAreaCoords(Vector2I windowPos)
+        {
+            Rect2I scrollBounds = contentScrollArea.Layout.Bounds;
+            Vector2I scrollPos = windowPos;
+            scrollPos.x -= scrollBounds.x;
+            scrollPos.y -= scrollBounds.y;
+
+            return scrollPos;
+        }
+
+        private void StartDragSelection(Vector2I windowPos)
+        {
+            isDraggingSelection = true;
+            dragSelectionStart = WindowToScrollAreaCoords(windowPos);
+            dragSelectionEnd = dragSelectionStart;
+        }
+
+        private bool UpdateDragSelection(Vector2I windowPos)
+        {
+            if (!isDraggingSelection)
+                return false;
+
+            if (dragSelection == null)
+            {
+                dragSelection = new GUITexture(null, true, EditorStyles.SelectionArea);
+                contentInfo.overlay.AddElement(dragSelection);
+            }
+
+            dragSelectionEnd = WindowToScrollAreaCoords(windowPos);
+
+            Rect2I selectionArea = CalculateSelectionArea();
+            SelectInArea(selectionArea);
+            dragSelection.Bounds = selectionArea;
+
+            return true;
+        }
+
+        private bool EndDragSelection()
+        {
+            if (!isDraggingSelection)
+                return false;
+
+            if (dragSelection != null)
+            {
+                dragSelection.Destroy();
+                dragSelection = null;
+            }
+
+            Rect2I selectionArea = CalculateSelectionArea();
+            SelectInArea(selectionArea);
+
+            isDraggingSelection = false;
+            return false;
+        }
+
+        private Rect2I CalculateSelectionArea()
+        {
+            Rect2I selectionArea = new Rect2I();
+            if (dragSelectionStart.x < dragSelectionEnd.x)
+            {
+                selectionArea.x = dragSelectionStart.x;
+                selectionArea.width = dragSelectionEnd.x - dragSelectionStart.x;
+            }
+            else
+            {
+                selectionArea.x = dragSelectionEnd.x;
+                selectionArea.width = dragSelectionStart.x - dragSelectionEnd.x;
+            }
+
+            if (dragSelectionStart.y < dragSelectionEnd.y)
+            {
+                selectionArea.y = dragSelectionStart.y;
+                selectionArea.height = dragSelectionEnd.y - dragSelectionStart.y;
+            }
+            else
+            {
+                selectionArea.y = dragSelectionEnd.y;
+                selectionArea.height = dragSelectionStart.y - dragSelectionEnd.y;
+            }
+
+            return selectionArea;
+        }
+
+        private void SelectInArea(Rect2I scrollBounds)
+        {
+            ElementEntry[] foundElements = FindElementsOverlapping(scrollBounds);
+
+            if (foundElements.Length > 0)
+            {
+                selectionAnchorStart = foundElements[0].index;
+                selectionAnchorEnd = foundElements[foundElements.Length - 1].index;
+            }
+            else
+            {
+                selectionAnchorStart = -1;
+                selectionAnchorEnd = -1;
+            }
+
+            List<string> elementPaths = new List<string>();
+            foreach (var elem in foundElements)
+                elementPaths.Add(elem.path);
+
+            SetSelection(elementPaths);
         }
 
         private void RefreshDirectoryBar()

+ 29 - 0
MBansheeEngine/Math/Rect2I.cs

@@ -38,6 +38,35 @@ namespace BansheeEngine
 		    return false;
 	    }
 
+	    public bool Overlaps(Rect2I other)
+	    {
+		    int otherRight = other.x + other.width;
+            int myRight = x + width;
+
+            int otherBottom = other.y + other.height;
+            int myBottom = y + height;
+
+		    if(x < otherRight && myRight > other.x &&
+			    y < otherBottom && myBottom > other.y)
+			    return true;
+
+		    return false;
+	    }
+
+	    public void Clip(Rect2I clipRect)
+	    {
+		    int newLeft = Math.Max(x, clipRect.x);
+		    int newTop = Math.Max(y, clipRect.y);
+
+		    int newRight = Math.Min(x + width, clipRect.x + clipRect.width);
+		    int newBottom = Math.Min(y + height, clipRect.y + clipRect.height);
+
+		    x = newLeft;
+		    y = newTop;
+		    width = Math.Max(0, newRight - newLeft);
+            height = Math.Max(0, newBottom - newTop);
+	    }
+
         public override bool Equals(object other)
         {
             if (!(other is Rect2I))

+ 1 - 0
TODO.txt

@@ -37,6 +37,7 @@ Later:
  - Drag to select multiple entries?
  - Hook up ping effect so it triggers when I select a resource or sceneobject
   - Add ping to SceneTreeView
+ - Consider delaying search until user stops pressing keys
 
 ----------------------------------------------------------------------
 Resources