private static void OnDragOver(object sender, DragEventArgs e)
    {
        if (e.Data == null || e.Handled)
        {
            e.Effects = DragDropEffects.None;
            return;
        }
        var element = (FrameworkElement)sender;
        var command = GetDropCommand(element);

        if (command == null)
        {
            return;
        }
        var dataFormats = e.Data.GetFormats();

        if (dataFormats == null)
        {
            return;
        }
        var dragAndDropInfo = new DragAndDropInfo(element.DataContext,
                                                  e.Data.GetData(dataFormats.FirstOrDefault()));
        var canDrop = dragAndDropInfo.DroppedItem != dragAndDropInfo.SourceItem &&
                      command.CanExecute(dragAndDropInfo);

        e.Handled = true;
        e.Effects = canDrop
                        ? e.Effects = DragDropEffects.All
                        : DragDropEffects.None;
    }
        private void TrackDragDrop(WorkerBuildConfiguration configurationForWorker, EventType currentEventType,
                                   SceneAsset item,
                                   DragAndDropInfo dragState, int itemIndex)
        {
            switch (currentEventType)
            {
            case EventType.MouseDrag:
                DragAndDrop.PrepareStartDrag();

                DragAndDrop.objectReferences = new[] { item };
                DragAndDrop.paths            = new[] { AssetDatabase.GetAssetPath(item) };

                DragAndDrop.StartDrag(item.name);

                dragState.SourceItemIndex = itemIndex;
                Event.current.Use();
                Repaint();

                sourceDragState = dragState;

                break;

            case EventType.DragPerform:
                Event.current.Use();
                DragAndDrop.AcceptDrag();
                Repaint();
                break;

            case EventType.MouseUp:     // Fall through.
            case EventType.DragExited:
                sourceDragState           = null;
                dragState.SourceItemIndex = -1;
                Repaint();
                break;

            case EventType.DragUpdated:
                var sceneAssets = DragAndDrop.objectReferences.OfType <SceneAsset>()
                                  .ToList();
                if (sceneAssets.Any())
                {
                    if (dragState.SourceItemIndex == -1 &&
                        sceneAssets.Intersect(configurationForWorker.ScenesForWorker).Any())
                    {
                        DragAndDrop.visualMode = DragAndDropVisualMode.Rejected;
                    }
                    else
                    {
                        DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
                    }

                    Event.current.Use();
                    Repaint();
                }

                break;
            }
        }
        private int?DrawSceneItem(int itemIndex, DragAndDropInfo dragState, SceneAsset item,
                                  EventType currentEventType,
                                  int?indexToRemove)
        {
            using (new GUIColorScope(
                       itemIndex == dragState.SourceItemIndex
                    ? new Color(GUI.color.r, GUI.color.g, GUI.color.b, 0.25f)
                    : GUI.color))
            {
                var rowRect = Rect.zero;
                var content = EditorGUIUtility.ObjectContent(item, typeof(SceneAsset));

                // Reserve space for the handle, draw it later.
                var grabberRect = GUILayoutUtility.GetRect(new GUIContent(content.image),
                                                           EditorStyles.helpBox,
                                                           GUILayout.MinWidth(16), GUILayout.MinHeight(16));

                grabberRect.min = new Vector2(grabberRect.min.x, grabberRect.min.y + 4);
                grabberRect.max = new Vector2(grabberRect.max.x, grabberRect.max.y + 4);

                BuildConfigEditorStyle.DrawGrabber(grabberRect);

                using (new EditorGUIUtility.IconSizeScope(new Vector2(24, 24)))
                {
                    GUILayout.Label(content);
                }

                if (currentEventType == EventType.Repaint)
                {
                    rowRect = BuildConfigEditorStyle.RectUnion(grabberRect, GUILayoutUtility.GetLastRect());
                }

                GUILayout.FlexibleSpace();
                using (new EditorGUIUtility.IconSizeScope(SmallIconSize))
                {
                    if (GUILayout.Button(style.RemoveSceneButtonContents, EditorStyles.miniButton))
                    {
                        indexToRemove = itemIndex;
                    }
                }

                if (currentEventType == EventType.Repaint)
                {
                    rowRect = BuildConfigEditorStyle.RectUnion(rowRect, GUILayoutUtility.GetLastRect());
                    dragState.AllItemsRect = BuildConfigEditorStyle.RectUnion(dragState.AllItemsRect, rowRect);
                    dragState.ItemHeight   = rowRect.height;
                }
            }

            return(indexToRemove);
        }
        public override void OnInspectorGUI()
        {
            if (style == null)
            {
                style = new BuildConfigEditorStyle();
            }

            if (allWorkers == null)
            {
                try
                {
                    var guids    = AssetDatabase.FindAssets("WorkerMenu");
                    var textFile = guids.Select(AssetDatabase.GUIDToAssetPath)
                                   .FirstOrDefault(f => Path.GetExtension(f) == ".txt");
                    if (string.IsNullOrEmpty(textFile))
                    {
                        throw new Exception("Could not find WorkerMenu.txt - you may need to regenerate code.");
                    }

                    allWorkers = File.ReadAllLines(Path.Combine(Application.dataPath, "..", textFile));
                }
                catch (Exception e)
                {
                    allWorkers = new string[0];
                    Debug.LogException(e);
                }
            }

            // Clean up state when drag events end.
            if (sourceDragState != null && Event.current.type == EventType.DragExited)
            {
                sourceDragState.SourceItemIndex = -1;
                sourceDragState = null;
                Repaint();
            }

            var workerConfiguration = (BuildConfig)target;

            BuildConfigEditorStyle.DrawHorizontalLine();

            var configs = workerConfiguration.WorkerBuildConfigurations;

            for (var index = 0; index < configs.Count; index++)
            {
                var workerConfig = configs[index];
                if (!DrawWorkerConfiguration(workerConfig))
                {
                    RecordUndo($"Remove '{workerConfig.WorkerType}'");

                    configs.RemoveAt(index);
                    index--;
                }

                BuildConfigEditorStyle.DrawHorizontalLine();
            }

            using (new EditorGUI.DisabledScope(workerConfiguration.WorkerBuildConfigurations.Count ==
                                               allWorkers.Length))
                using (new GUILayout.HorizontalScope())
                {
                    GUILayout.FlexibleSpace();
                    if (GUILayout.Button("Add new worker type"))
                    {
                        workerChooser = new WorkerChoicePopup(addWorkerButtonRect, workerConfiguration, allWorkers);
                        PopupWindow.Show(addWorkerButtonRect, workerChooser);
                    }

                    if (Event.current.type == EventType.Repaint)
                    {
                        addWorkerButtonRect = GUILayoutUtility.GetLastRect();

                        // Only add the new worker during the Repaint phase - otherwise you'll see errors due to adding new content at the wrong point of the GUI lifecycle.
                        if (workerChooser != null && workerChooser.Choice != -1)
                        {
                            RecordUndo("Add '{Choices[i]}'");

                            var config = new WorkerBuildConfiguration
                            {
                                WorkerType       = workerChooser.Choices[workerChooser.Choice],
                                LocalBuildConfig = new BuildEnvironmentConfig(WorkerBuildData.LocalBuildTargets,
                                                                              WorkerBuildData.GetCurrentBuildTargetConfig()),
                                CloudBuildConfig = new BuildEnvironmentConfig(WorkerBuildData.AllBuildTargets,
                                                                              WorkerBuildData.GetLinuxBuildTargetConfig())
                            };
                            workerConfiguration.WorkerBuildConfigurations.Add(config);
                            workerChooser = null;
                        }
                    }

                    GUILayout.FlexibleSpace();
                }

            if (invalidateCachedContent > 0)
            {
                invalidateCachedContent--;
            }
        }