public void OnGUI()
        {
            Color defaultColor = GUI.color;

            if (PluginsManifest.Instance == null)
            {
                EditorGUILayout.LabelField("PluginsManifest not found.", EditorGUIEx.BoldCenteredLabel);
                if (GUILayout.Button("Create"))
                {
                    PluginsManifest.Create();
                    Repaint();
                }
                return;
            }

            if (PluginsManifest.Instance.CurrentStage != InstallStage.None)
            {
                EditorGUILayout.LabelField(PluginsManifest.GetInstallStageDescription(PluginsManifest.Instance.CurrentStage), EditorGUIEx.BoldCenteredLabel);

                if (GUILayout.Button("Cancel"))
                {
                    PluginsManifest.Instance.CurrentStage = InstallStage.None;
                    Repaint();
                }

                return;
            }

            this.ShowCompileAndPlayModeWarning(out bool canEdit);

            if (canEdit == false)
            {
                return;
            }

            scrollPos = EditorGUILayout.BeginScrollView(scrollPos);

            EditorGUILayout.Separator();

            EditorGUILayout.LabelField("Plugins", EditorGUIEx.BoldCenteredLabel);

            EditorGUILayout.Separator();

            if (pluginsData.Count == 0)
            {
                plugins.Clear();
                plugins.AddRange(Util.GetAssets <PluginInfo>());
                plugins.Sort((p1, p2) => - p1.priority.CompareTo(p2.priority));
                for (int i = 0; i < plugins.Count; i++)
                {
                    var plugin = plugins[i];
                    var data   = PluginsManifest.Instance.GetPluginData(plugins[i]);
                    pluginsData.Add(plugin, data);
                }
            }

            foreach (var item in pluginsData.ToArray())
            {
                PluginInfo plugin     = item.Key;
                PluginData data       = item.Value;
                var        lineHeight = EditorGUIUtility.singleLineHeight;
                Rect       rect       = EditorGUILayout.GetControlRect(false, EditorGUIUtility.singleLineHeight);
                string     desc       = $"{plugin.description} : {plugin.displayVersion}";

                bool isInstallationValid = true;
                PluginInfo.ErrorSummary installationErrors = null;

                if (data == null)
                {
                    Color c = GUI.color;
                    GUI.color = EditorGUIEx.WarningRedColor;
                    EditorGUILayout.LabelField("Plugin data not found: " + plugin.name);
                    GUI.color = c;
                    continue;
                }

                if (data.installed)
                {
                    isInstallationValid = plugin.IsInstallationValid(out installationErrors);
                }

                GUI.color = isInstallationValid ? defaultColor : EditorGUIEx.WarningRedColor;

                plugin.showInfo =
                    EditorGUI.Foldout(new Rect(rect.x, rect.y, rect.width - INSTALL_BTN_WIDTH, lineHeight),
                                      plugin.showInfo, desc, true);

                GUI.color = defaultColor;

                if (plugin.showInfo)
                {
                    EditorGUI.indentLevel++;

                    plugin.showDependencies = EditorGUILayout.Foldout(plugin.showDependencies, "Dependencies", true);

                    if (plugin.showDependencies)
                    {
                        EditorGUI.indentLevel++;
                        if (plugin.HasDependencies)
                        {
                            EditorGUILayout.LabelField("Plugins:");
                            EditorGUI.indentLevel++;
                            foreach (PluginInfo dependency in plugin.GetDependencies())
                            {
                                if (dependency == null)
                                {
                                    Color c = GUI.color;
                                    GUI.color = EditorGUIEx.WarningRedColor;
                                    EditorGUILayout.LabelField("Invalid dependency!");
                                    GUI.color = c;
                                    continue;
                                }
                                Rect labelRect = EditorGUILayout.GetControlRect();
                                EnableDependencyWarning(PluginDependencyType.Plugin, installationErrors, AssetDatabase.GetAssetPath(dependency),
                                                        data.installed, defaultColor, labelRect);

                                EditorGUI.LabelField(labelRect, dependency.description + " : " + dependency.displayVersion);

                                GUI.color = defaultColor;
                            }
                            EditorGUI.indentLevel--;
                        }

                        if (plugin.HasPackageDependencies)
                        {
                            EditorGUILayout.LabelField("Packages:");
                            EditorGUI.indentLevel++;
                            foreach (PluginInfo.PackageDependency dependency in plugin.GetPackages())
                            {
                                Rect labelRect = EditorGUILayout.GetControlRect();
                                EnableDependencyWarning(PluginDependencyType.Package, installationErrors, dependency.FullName,
                                                        data.installed, defaultColor, labelRect);
                                EditorGUI.LabelField(labelRect, dependency.FullName);
                                GUI.color = defaultColor;
                            }
                            EditorGUI.indentLevel--;
                        }

                        if (plugin.HasModules)
                        {
                            EditorGUILayout.LabelField("Modules:");
                            EditorGUI.indentLevel++;
                            foreach (ModuleInstallInfo info in plugin.GetModules())
                            {
                                Type interfaceType = info.GetInterfaceType();


                                Rect labelRect = EditorGUILayout.GetControlRect();
                                EnableDependencyWarning(PluginDependencyType.Module, installationErrors, AssetDatabase.GetAssetPath(info),
                                                        data.installed, defaultColor, labelRect);
                                EditorGUI.LabelField(labelRect,
                                                     $"{interfaceType?.GetDisplayName()} ({info.GetModuleDescription()})");
                                GUI.color = defaultColor;
                            }
                            EditorGUI.indentLevel--;
                        }

                        if (plugin.HasDefineSymbols)
                        {
                            EditorGUILayout.LabelField("Define Symbols:");
                            EditorGUI.indentLevel++;
                            foreach (var symbol in plugin.GetSymbols())
                            {
                                Rect labelRect = EditorGUILayout.GetControlRect();
                                EnableDependencyWarning(PluginDependencyType.DefineSymbol, installationErrors, symbol.symbolName,
                                                        data.installed, defaultColor, labelRect);
                                EditorGUI.LabelField(labelRect, symbol.symbolName);
                                GUI.color = defaultColor;
                            }
                            EditorGUI.indentLevel--;
                        }
                        EditorGUI.indentLevel--;
                    }

                    if (plugin.HasOptions())
                    {
                        plugin.showOptions = EditorGUILayout.Foldout(plugin.showOptions, "Options", true);

                        if (plugin.showOptions)
                        {
                            EditorGUI.indentLevel++;
                            plugin.DrawOptions(Repaint, data);
                            EditorGUI.indentLevel--;
                        }
                    }

                    EditorGUI.indentLevel--;
                }

                Color color = GUI.color;

                if (data.installed)
                {
                    bool canUpdate = data.version != plugin.version && plugin.canBeUpdated;

                    GUI.color = !canUpdate ? EditorGUIEx.GreenColor : EditorGUIEx.YellowColor;

                    var label = canUpdate ? "Update" : "Installed";

                    GUI.enabled = canUpdate;

                    Rect buttonRect = new Rect(rect.x + (rect.width - INSTALL_BTN_WIDTH - DELETE_BTN_WIDTH), rect.y,
                                               INSTALL_BTN_WIDTH, lineHeight);

                    if (GUI.Button(buttonRect, label))
                    {
                        UpdatePlugin(plugin, data);
                    }

                    GUI.color = color;

                    GUI.enabled = plugin.CanRemove();

                    buttonRect = new Rect(rect.x + rect.width - DELETE_BTN_WIDTH, rect.y, DELETE_BTN_WIDTH, lineHeight);

                    if (GUI.Button(buttonRect, "X"))
                    {
                        if (EditorUtility.DisplayDialog("Warning", $"Remove {plugin.description}?", "Yes", "Cancel"))
                        {
                            RemovePlugin(plugin);
                        }
                    }

                    GUI.enabled = true;
                }
                else
                {
                    GUI.color = color;

                    Rect buttonRect = new Rect(rect.x + rect.width - INSTALL_BTN_WIDTH - DELETE_BTN_WIDTH, rect.y,
                                               INSTALL_BTN_WIDTH + DELETE_BTN_WIDTH, lineHeight);

                    if (GUI.Button(buttonRect, "Install"))
                    {
                        Install(plugin);
                        Repaint();
                    }
                }

                if (GUI.changed)
                {
                    EditorUtility.SetDirty(plugin);
                }

                GUI.color = color;
            }

            EditorGUILayout.EndScrollView();

            if (GUILayout.Button("Refresh"))
            {
                Refresh();
            }
        }