internal static UnmaskedView CreateInstanceForGUIView(Type type, IList <GuiControlSelector> unmaskedControls = null)
        {
            if (!GUIViewProxy.IsAssignableFrom(type))
            {
                throw new InvalidOperationException("Type must be assignable to GUIView");
            }

            UnmaskedView result = new UnmaskedView();

            result.m_SelectorType  = SelectorType.GUIView;
            result.m_ViewType.Type = type;
            if (unmaskedControls != null)
            {
                result.m_UnmaskedControls.AddRange(unmaskedControls);
            }
            return(result);
        }
        public static UnmaskedView CreateInstanceForEditorWindow(Type type, IList <GuiControlSelector> unmaskedControls = null)
        {
            if (!typeof(EditorWindow).IsAssignableFrom(type))
            {
                throw new InvalidOperationException("Type must be assignable to EditorWindow");
            }

            UnmaskedView result = new UnmaskedView();

            result.m_SelectorType          = SelectorType.EditorWindow;
            result.m_EditorWindowType.Type = type;
            if (unmaskedControls != null)
            {
                result.m_UnmaskedControls.AddRange(unmaskedControls);
            }
            return(result);
        }
        static IEnumerable <GUIViewProxy> GetMatchingViews(
            UnmaskedView unmaskedView,
            List <GUIViewProxy> allViews,
            Dictionary <GUIViewProxy, HashSet <EditorWindow> > viewsWithWindows)
        {
            var matchingViews = new HashSet <GUIViewProxy>(new GUIViewProxyComparer());

            switch (unmaskedView.m_SelectorType)
            {
            case SelectorType.EditorWindow:
                var targetEditorWindowType = unmaskedView.EditorWindowType;
                if (targetEditorWindowType == null)
                {
                    throw new ArgumentException(
                              $"Specified unmasked view does not refer to a known EditorWindow type:\n{JsonUtility.ToJson(unmaskedView, true)}",
                              "unmaskedView"
                              );
                }
                if (targetEditorWindowType != null)
                {
                    // make sure desired window is in current layout
                    // TODO: allow trainer to specify desired dock area if window doesn't yet exist?
//                        var window = EditorWindow.GetWindow(targetEditorWindowType);
                    var window = Resources.FindObjectsOfTypeAll(targetEditorWindowType).Cast <EditorWindow>().ToArray().FirstOrDefault();
                    if (window == null || window.GetParent() == null)
                    {
                        return(matchingViews);
                    }

                    // Postpone showing window until next editor update
                    // GetMatchingViews could be called in response to window closing
                    s_EditorWindowsToShow.Push(window);

                    if (!allViews.Contains(window.GetParent()))
                    {
                        allViews.Add(window.GetParent());
                    }
                    foreach (var view in allViews)
                    {
                        if (!view.IsActualViewAssignableTo(targetEditorWindowType))
                        {
                            continue;
                        }

                        HashSet <EditorWindow> windows;
                        if (!viewsWithWindows.TryGetValue(view, out windows))
                        {
                            viewsWithWindows[view] = windows = new HashSet <EditorWindow>();
                        }
                        windows.Add(window);

                        matchingViews.Add(view);
                    }
                }
                break;

            case SelectorType.GUIView:
                var targetViewType = unmaskedView.m_ViewType.Type;
                if (targetViewType == null)
                {
                    throw new ArgumentException(
                              $"Specified unmasked view does not refer to a known GUIView type:\n{JsonUtility.ToJson(unmaskedView, true)}",
                              "unmaskedView"
                              );
                }
                if (targetViewType != null)
                {
                    foreach (var view in allViews)
                    {
                        if (view.IsGUIViewAssignableTo(targetViewType))
                        {
                            matchingViews.Add(view);
                        }
                    }
                }
                break;
            }

            // TODO Not necessarily exception worthy. We are using a "delayed masking" occasionally, e.g. when switching
            // to Play mode and we want to unmask Game view which is not yet visible (in the background tab by defaul).
            //if (matchingViews.Count == 0)
            //{
            //    throw new ArgumentException(
            //        $"Specified unmasked view refers to a view that could not be found:\n{JsonUtility.ToJson(unmaskedView, true)}"
            //        , "unmaskedView"
            //    );
            //}

            return(matchingViews);
        }