private void OnGUI()
        {
            GUILayout.Space(GUISectionOffset);

            // Setup
            int    buttonWidth_Quarter = Screen.width / 4;
            int    buttonWidth_Half    = Screen.width / 2;
            int    buttonWidth_Full    = Screen.width - 25;
            string appName             = PlayerSettings.productName;

            // Build section
            GUILayout.BeginVertical();
            GUILayout.Label("SLN");

            EditorGUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            EditorGUILayout.EndHorizontal();

            // Build directory (and save setting, if it's changed)
            string curBuildDirectory = BuildDeployPrefs.BuildDirectory;
            string newBuildDirectory = EditorGUILayout.TextField(GUIHorizSpacer + "Build directory", curBuildDirectory);

            if (newBuildDirectory != curBuildDirectory)
            {
                BuildDeployPrefs.BuildDirectory = newBuildDirectory;
                curBuildDirectory = newBuildDirectory;
            }

            // Build SLN button
            using (new EditorGUILayout.HorizontalScope())
            {
                GUILayout.FlexibleSpace();
                GUI.enabled = ShouldOpenSLNBeEnabled;
                if (GUILayout.Button("Open SLN", GUILayout.Width(buttonWidth_Quarter)))
                {
                    // Open SLN
                    string slnFilename = Path.Combine(curBuildDirectory, PlayerSettings.productName + ".sln");
                    if (File.Exists(slnFilename))
                    {
                        FileInfo slnFile = new FileInfo(slnFilename);
                        System.Diagnostics.Process.Start(slnFile.FullName);
                    }
                    else if (EditorUtility.DisplayDialog("Solution Not Found", "We couldn't find the solution. Would you like to Build it?", "Yes, Build", "No"))
                    {
                        // Build SLN
                        EditorApplication.delayCall += () => { BuildDeployTools.BuildSLN(curBuildDirectory); };
                    }
                }
                GUI.enabled = ShouldBuildSLNBeEnabled;
                if (GUILayout.Button("Build Visual Studio SLN", GUILayout.Width(buttonWidth_Half)))
                {
                    // Build SLN
                    EditorApplication.delayCall += () => { BuildDeployTools.BuildSLN(curBuildDirectory); };
                }
                GUI.enabled = true;
            }

            // Build & Run button...
            using (new EditorGUILayout.HorizontalScope())
            {
                GUILayout.FlexibleSpace();
                GUI.enabled = ShouldBuildSLNBeEnabled;
                if (GUILayout.Button("Build SLN, Build APPX, then Install", GUILayout.Width(buttonWidth_Half)))
                {
                    // Build SLN
                    EditorApplication.delayCall += () => { BuildAndRun(appName); };
                }
                GUI.enabled = true;
            }

            // Appx sub-section
            GUILayout.BeginVertical();
            GUILayout.Label("APPX");

            // MSBuild Ver (and save setting, if it's changed)
            string curMSBuildVer = BuildDeployPrefs.MsBuildVersion;
            string newMSBuildVer = EditorGUILayout.TextField(GUIHorizSpacer + "MSBuild Version", curMSBuildVer);

            if (newMSBuildVer != curMSBuildVer)
            {
                BuildDeployPrefs.MsBuildVersion = newMSBuildVer;
                curMSBuildVer = newMSBuildVer;
            }

            // Build config (and save setting, if it's changed)
            string curBuildConfig = BuildDeployPrefs.BuildConfig;
            string newBuildConfig = EditorGUILayout.TextField(GUIHorizSpacer + "Build Configuration", curBuildConfig);

            if (newBuildConfig != curBuildConfig)
            {
                BuildDeployPrefs.BuildConfig = newBuildConfig;
                curBuildConfig = newBuildConfig;
            }

            // Build APPX button
            using (new EditorGUILayout.HorizontalScope())
            {
                GUILayout.FlexibleSpace();

                float previousLabelWidth = EditorGUIUtility.labelWidth;

                // Force rebuild
                EditorGUIUtility.labelWidth = 50;
                bool curForceRebuildAppx = BuildDeployPrefs.ForceRebuild;
                bool newForceRebuildAppx = EditorGUILayout.Toggle("Rebuild", curForceRebuildAppx);
                if (newForceRebuildAppx != curForceRebuildAppx)
                {
                    BuildDeployPrefs.ForceRebuild = newForceRebuildAppx;
                    curForceRebuildAppx           = newForceRebuildAppx;
                }

                // Increment version
                EditorGUIUtility.labelWidth = 110;
                bool curIncrementVersion = BuildDeployPrefs.IncrementBuildVersion;
                bool newIncrementVersion = EditorGUILayout.Toggle("Increment version", curIncrementVersion);
                if (newIncrementVersion != curIncrementVersion)
                {
                    BuildDeployPrefs.IncrementBuildVersion = newIncrementVersion;
                    curIncrementVersion = newIncrementVersion;
                }

                // Restore previous label width
                EditorGUIUtility.labelWidth = previousLabelWidth;

                // Build APPX
                GUI.enabled = ShouldBuildAppxBeEnabled;
                if (GUILayout.Button("Build APPX from SLN", GUILayout.Width(buttonWidth_Half)))
                {
                    BuildDeployTools.BuildAppxFromSolution(appName, curMSBuildVer, curForceRebuildAppx, curBuildConfig, curBuildDirectory, curIncrementVersion);
                }
                GUI.enabled = true;
            }
            GUILayout.EndVertical();
            GUILayout.EndVertical();

            GUILayout.Space(GUISectionOffset);

            // Deploy section
            GUILayout.BeginVertical();
            GUILayout.Label("Deploy");

            // Target IPs (and save setting, if it's changed)
            string curTargetIps = BuildDeployPrefs.TargetIPs;

            if (!LocalIPsOnly)
            {
                string newTargetIPs = EditorGUILayout.TextField(
                    new GUIContent(GUIHorizSpacer + "IP Address(es)", "IP(s) of target devices (e.g. 127.0.0.1;10.11.12.13)"),
                    curTargetIps);

                if (newTargetIPs != curTargetIps)
                {
                    BuildDeployPrefs.TargetIPs = newTargetIPs;
                    curTargetIps = newTargetIPs;
                }
            }
            else
            {
                var locatorIsSearching = XdeGuestLocator.IsSearching;
                var locatorHasData     = XdeGuestLocator.HasData;
                var xdeGuestIpAddress  = XdeGuestLocator.GuestIpAddress;

                // Queue up a repaint if we're still busy, or we'll get stuck
                // in a disabled state.

                if (locatorIsSearching)
                {
                    Repaint();
                }

                var addressesToPresent = new List <string>();
                addressesToPresent.Add("127.0.0.1");

                if (!locatorIsSearching && locatorHasData)
                {
                    addressesToPresent.Add(xdeGuestIpAddress.ToString());
                }

                var previouslySavedAddress = addressesToPresent.IndexOf(curTargetIps);
                if (previouslySavedAddress == -1)
                {
                    previouslySavedAddress = 0;
                }

                EditorGUILayout.BeginHorizontal();

                if (locatorIsSearching && !locatorHasData)
                {
                    GUI.enabled = false;
                }

                var selectedAddressIndex = EditorGUILayout.Popup(GUIHorizSpacer + "IP Address", previouslySavedAddress, addressesToPresent.ToArray());

                if (GUILayout.Button(locatorIsSearching ? "Searching" : "Refresh", GUILayout.Width(buttonWidth_Quarter)))
                {
                    UpdateXdeStatus();
                }

                GUI.enabled = true;
                EditorGUILayout.EndHorizontal();

                var selectedAddress = addressesToPresent[selectedAddressIndex];

                if (curTargetIps != selectedAddress && !locatorIsSearching)
                {
                    BuildDeployPrefs.TargetIPs = selectedAddress;
                }
            }

            // Username/Password (and save seeings, if changed)
            string curUsername      = BuildDeployPrefs.DeviceUser;
            string newUsername      = EditorGUILayout.TextField(GUIHorizSpacer + "Username", curUsername);
            string curPassword      = BuildDeployPrefs.DevicePassword;
            string newPassword      = EditorGUILayout.PasswordField(GUIHorizSpacer + "Password", curPassword);
            bool   curFullReinstall = BuildDeployPrefs.FullReinstall;
            bool   newFullReinstall = EditorGUILayout.Toggle(
                new GUIContent(GUIHorizSpacer + "Uninstall first", "Uninstall application before installing"), curFullReinstall);

            if ((newUsername != curUsername) ||
                (newPassword != curPassword) ||
                (newFullReinstall != curFullReinstall))
            {
                BuildDeployPrefs.DeviceUser     = newUsername;
                BuildDeployPrefs.DevicePassword = newPassword;
                BuildDeployPrefs.FullReinstall  = newFullReinstall;

                curUsername      = newUsername;
                curPassword      = newPassword;
                curFullReinstall = newFullReinstall;
            }

            // Build list (with install buttons)
            if (this.builds.Count == 0)
            {
                GUILayout.Label(GUIHorizSpacer + "*** No builds found in build directory", EditorStyles.boldLabel);
            }
            else
            {
                foreach (var fullBuildLocation in this.builds)
                {
                    int lastBackslashIndex = fullBuildLocation.LastIndexOf("\\");

                    var    directoryDate = Directory.GetLastWriteTime(fullBuildLocation).ToString("yyyy/MM/dd HH:mm:ss");
                    string packageName   = fullBuildLocation.Substring(lastBackslashIndex + 1);

                    EditorGUILayout.BeginHorizontal();
                    GUILayout.Space(GUISectionOffset + 15);
                    if (GUILayout.Button("Install", GUILayout.Width(120.0f)))
                    {
                        string   thisBuildLocation = fullBuildLocation;
                        string[] IPlist            = ParseIPList(curTargetIps);
                        EditorApplication.delayCall += () =>
                        {
                            InstallAppOnDevicesList(thisBuildLocation, curFullReinstall, IPlist);
                        };
                    }
                    GUILayout.Space(5);
                    GUILayout.Label(packageName + " (" + directoryDate + ")");
                    EditorGUILayout.EndHorizontal();
                }
                EditorGUILayout.Separator();
            }
            GUILayout.EndVertical();

            GUILayout.Space(GUISectionOffset);

            // Utilities section
            GUILayout.BeginVertical();
            GUILayout.Label("Utilities");

            // Open web portal
            using (new EditorGUILayout.HorizontalScope())
            {
                GUI.enabled = ShouldWebPortalBeEnabled;
                GUILayout.FlexibleSpace();
                if (GUILayout.Button("Open Device Portal", GUILayout.Width(buttonWidth_Full)))
                {
                    OpenWebPortalForIPs(curTargetIps);
                }
                GUI.enabled = true;
            }

            // Launch app..
            using (new EditorGUILayout.HorizontalScope())
            {
                GUI.enabled = ShouldLaunchAppBeEnabled;
                GUILayout.FlexibleSpace();
                if (GUILayout.Button("Launch Application", GUILayout.Width(buttonWidth_Full)))
                {
                    // If already running, kill it (button is a toggle)
                    if (IsAppRunning_FirstIPCheck(appName, curTargetIps))
                    {
                        KillAppOnIPs(curTargetIps);
                    }
                    else
                    {
                        LaunchAppOnIPs(curTargetIps);
                    }
                }
                GUI.enabled = true;
            }

            // Log file
            using (new EditorGUILayout.HorizontalScope())
            {
                GUI.enabled = ShouldLogViewBeEnabled;
                GUILayout.FlexibleSpace();
                if (GUILayout.Button("View Log File", GUILayout.Width(buttonWidth_Full)))
                {
                    OpenLogFileForIPs(curTargetIps);
                }
                GUI.enabled = true;
            }

            // Uninstall...
            using (new EditorGUILayout.HorizontalScope())
            {
                GUI.enabled = ShouldLogViewBeEnabled;
                GUILayout.FlexibleSpace();
                if (GUILayout.Button("Uninstall Application", GUILayout.Width(buttonWidth_Full)))
                {
                    string[] IPlist = ParseIPList(curTargetIps);
                    EditorApplication.delayCall += () =>
                    {
                        UninstallAppOnDevicesList(IPlist);
                    };
                }
                GUI.enabled = true;
            }
            GUILayout.EndVertical();
        }