This commit is contained in:
goat 2023-04-10 19:17:00 +02:00 committed by GitHub
parent 50458444e7
commit 642e8bf6d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 1492 additions and 74 deletions

View file

@ -21,6 +21,7 @@ using Dalamud.Logging.Internal;
using Dalamud.Plugin;
using Dalamud.Plugin.Internal;
using Dalamud.Plugin.Internal.Exceptions;
using Dalamud.Plugin.Internal.Profiles;
using Dalamud.Plugin.Internal.Types;
using Dalamud.Support;
using Dalamud.Utility;
@ -48,6 +49,8 @@ internal class PluginInstallerWindow : Window, IDisposable
private readonly object listLock = new();
private readonly ProfileManagerWidget profileManagerWidget;
private DalamudChangelogManager? dalamudChangelogManager;
private Task? dalamudChangelogRefreshTask;
private CancellationTokenSource? dalamudChangelogRefreshTaskCts;
@ -149,6 +152,8 @@ internal class PluginInstallerWindow : Window, IDisposable
});
this.timeLoaded = DateTime.Now;
this.profileManagerWidget = new(this);
}
private enum OperationStatus
@ -167,6 +172,7 @@ internal class PluginInstallerWindow : Window, IDisposable
UpdatingAll,
Installing,
Manager,
ProfilesLoading,
}
private enum PluginSortKind
@ -213,6 +219,8 @@ internal class PluginInstallerWindow : Window, IDisposable
this.updatePluginCount = 0;
this.updatedPlugins = null;
}
this.profileManagerWidget.Reset();
}
/// <inheritdoc/>
@ -285,17 +293,56 @@ internal class PluginInstallerWindow : Window, IDisposable
this.searchText = text;
}
/// <summary>
/// Start a plugin install and handle errors visually.
/// </summary>
/// <param name="manifest">The manifest to install.</param>
/// <param name="useTesting">Install the testing version.</param>
public void StartInstall(RemotePluginManifest manifest, bool useTesting)
{
var pluginManager = Service<PluginManager>.Get();
var notifications = Service<NotificationManager>.Get();
this.installStatus = OperationStatus.InProgress;
this.loadingIndicatorKind = LoadingIndicatorKind.Installing;
Task.Run(() => pluginManager.InstallPluginAsync(manifest, useTesting || manifest.IsTestingExclusive, PluginLoadReason.Installer))
.ContinueWith(task =>
{
// There is no need to set as Complete for an individual plugin installation
this.installStatus = OperationStatus.Idle;
if (this.DisplayErrorContinuation(task, Locs.ErrorModal_InstallFail(manifest.Name)))
{
// Fine as long as we aren't in an error state
if (task.Result.State is PluginState.Loaded or PluginState.Unloaded)
{
notifications.AddNotification(Locs.Notifications_PluginInstalled(manifest.Name), Locs.Notifications_PluginInstalledTitle, NotificationType.Success);
}
else
{
notifications.AddNotification(Locs.Notifications_PluginNotInstalled(manifest.Name), Locs.Notifications_PluginNotInstalledTitle, NotificationType.Error);
this.ShowErrorModal(Locs.ErrorModal_InstallFail(manifest.Name));
}
}
});
}
private void DrawProgressOverlay()
{
var pluginManager = Service<PluginManager>.Get();
var profileManager = Service<ProfileManager>.Get();
var isWaitingManager = !pluginManager.PluginsReady ||
!pluginManager.ReposReady;
var isWaitingProfiles = profileManager.IsBusy;
var isLoading = this.AnyOperationInProgress ||
isWaitingManager;
isWaitingManager || isWaitingProfiles;
if (isWaitingManager)
this.loadingIndicatorKind = LoadingIndicatorKind.Manager;
else if (isWaitingProfiles)
this.loadingIndicatorKind = LoadingIndicatorKind.ProfilesLoading;
if (!isLoading)
return;
@ -379,6 +426,9 @@ internal class PluginInstallerWindow : Window, IDisposable
}
}
break;
case LoadingIndicatorKind.ProfilesLoading:
ImGuiHelpers.CenteredText("Profiles are being applied...");
break;
default:
throw new ArgumentOutOfRangeException();
@ -387,9 +437,7 @@ internal class PluginInstallerWindow : Window, IDisposable
if (DateTime.Now - this.timeLoaded > TimeSpan.FromSeconds(90) && !pluginManager.PluginsReady)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGuiHelpers.CenteredText("This is embarrassing, but...");
ImGuiHelpers.CenteredText("one of your plugins may be blocking the installer.");
ImGuiHelpers.CenteredText("You should tell us about this, please keep this window open.");
ImGuiHelpers.CenteredText("One of your plugins may be blocking the installer.");
ImGui.PopStyleColor();
}
@ -1111,6 +1159,10 @@ internal class PluginInstallerWindow : Window, IDisposable
if (!Service<DalamudConfiguration>.Get().DoPluginTest)
continue;
break;
case PluginCategoryManager.CategoryInfo.AppearCondition.ProfilesEnabled:
if (!Service<DalamudConfiguration>.Get().ProfilesEnabled)
continue;
break;
default:
throw new ArgumentOutOfRangeException();
}
@ -1216,6 +1268,10 @@ internal class PluginInstallerWindow : Window, IDisposable
case 1:
this.DrawInstalledPluginList(true);
break;
case 2:
this.profileManagerWidget.Draw();
break;
}
break;
@ -1555,7 +1611,7 @@ internal class PluginInstallerWindow : Window, IDisposable
ImGui.SetCursorPos(startCursor);
var pluginDisabled = plugin is { IsDisabled: true };
var pluginDisabled = plugin is { IsWantedByAnyProfile: false };
var iconSize = ImGuiHelpers.ScaledVector2(64, 64);
var cursorBeforeImage = ImGui.GetCursorPos();
@ -1853,27 +1909,7 @@ internal class PluginInstallerWindow : Window, IDisposable
var buttonText = Locs.PluginButton_InstallVersion(versionString);
if (ImGui.Button($"{buttonText}##{buttonText}{index}"))
{
this.installStatus = OperationStatus.InProgress;
this.loadingIndicatorKind = LoadingIndicatorKind.Installing;
Task.Run(() => pluginManager.InstallPluginAsync(manifest, useTesting || manifest.IsTestingExclusive, PluginLoadReason.Installer))
.ContinueWith(task =>
{
// There is no need to set as Complete for an individual plugin installation
this.installStatus = OperationStatus.Idle;
if (this.DisplayErrorContinuation(task, Locs.ErrorModal_InstallFail(manifest.Name)))
{
if (task.Result.State == PluginState.Loaded)
{
notifications.AddNotification(Locs.Notifications_PluginInstalled(manifest.Name), Locs.Notifications_PluginInstalledTitle, NotificationType.Success);
}
else
{
notifications.AddNotification(Locs.Notifications_PluginNotInstalled(manifest.Name), Locs.Notifications_PluginNotInstalledTitle, NotificationType.Error);
this.ShowErrorModal(Locs.ErrorModal_InstallFail(manifest.Name));
}
}
});
this.StartInstall(manifest, useTesting);
}
}
@ -1980,7 +2016,7 @@ internal class PluginInstallerWindow : Window, IDisposable
}
// Disabled
if (plugin.IsDisabled || !plugin.CheckPolicy())
if (!plugin.IsWantedByAnyProfile || !plugin.CheckPolicy())
{
label += Locs.PluginTitleMod_Disabled;
trouble = true;
@ -2262,6 +2298,11 @@ internal class PluginInstallerWindow : Window, IDisposable
{
var notifications = Service<NotificationManager>.Get();
var pluginManager = Service<PluginManager>.Get();
var profileManager = Service<ProfileManager>.Get();
var config = Service<DalamudConfiguration>.Get();
var applicableForProfiles = plugin.Manifest.SupportsProfiles;
var isDefaultPlugin = profileManager.IsInDefaultProfile(plugin.Manifest.InternalName);
// Disable everything if the updater is running or another plugin is operating
var disabled = this.updateStatus == OperationStatus.InProgress || this.installStatus == OperationStatus.InProgress;
@ -2276,15 +2317,70 @@ internal class PluginInstallerWindow : Window, IDisposable
// Disable everything if the plugin failed to load
disabled = disabled || plugin.State == PluginState.LoadError || plugin.State == PluginState.DependencyResolutionFailed;
// Disable everything if we're working
// Disable everything if we're loading plugins
disabled = disabled || plugin.State == PluginState.Loading || plugin.State == PluginState.Unloading;
// Disable everything if we're applying profiles
disabled = disabled || profileManager.IsBusy;
var toggleId = plugin.Manifest.InternalName;
var isLoadedAndUnloadable = plugin.State == PluginState.Loaded ||
plugin.State == PluginState.DependencyResolutionFailed;
StyleModelV1.DalamudStandard.Push();
var profileChooserPopupName = $"###pluginProfileChooser{plugin.Manifest.InternalName}";
if (ImGui.BeginPopup(profileChooserPopupName))
{
var didAny = false;
foreach (var profile in profileManager.Profiles.Where(x => !x.IsDefaultProfile))
{
var inProfile = profile.WantsPlugin(plugin.Manifest.InternalName) != null;
if (ImGui.Checkbox($"###profilePick{profile.Guid}{plugin.Manifest.InternalName}", ref inProfile))
{
if (inProfile)
{
Task.Run(() => profile.AddOrUpdate(plugin.Manifest.InternalName, true))
.ContinueWith(this.DisplayErrorContinuation, "Couldn't add plugin to this profile.");
}
else
{
Task.Run(() => profile.Remove(plugin.Manifest.InternalName))
.ContinueWith(this.DisplayErrorContinuation, "Couldn't remove plugin from this profile.");
}
}
ImGui.SameLine();
ImGui.TextUnformatted(profile.Name);
didAny = true;
}
if (!didAny)
ImGui.TextColored(ImGuiColors.DalamudGrey, "No profiles! Go add some!");
ImGui.Separator();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Times))
{
profileManager.DefaultProfile.AddOrUpdate(plugin.Manifest.InternalName, plugin.IsLoaded, false);
foreach (var profile in profileManager.Profiles.Where(x => !x.IsDefaultProfile && x.Plugins.Any(y => y.InternalName == plugin.Manifest.InternalName)))
{
profile.Remove(plugin.Manifest.InternalName, false);
}
// TODO error handling
Task.Run(() => profileManager.ApplyAllWantStates());
}
ImGui.SameLine();
ImGui.Text("Remove from all profiles");
ImGui.EndPopup();
}
if (plugin.State == PluginState.UnloadError && !plugin.IsDev)
{
ImGuiComponents.DisabledButton(FontAwesomeIcon.Frown);
@ -2292,14 +2388,18 @@ internal class PluginInstallerWindow : Window, IDisposable
if (ImGui.IsItemHovered())
ImGui.SetTooltip(Locs.PluginButtonToolTip_UnloadFailed);
}
else if (disabled)
else if (disabled || !isDefaultPlugin)
{
ImGuiComponents.DisabledToggleButton(toggleId, isLoadedAndUnloadable);
if (!isDefaultPlugin && ImGui.IsItemHovered())
ImGui.SetTooltip(Locs.PluginButtonToolTip_NeedsToBeInDefault);
}
else
{
if (ImGuiComponents.ToggleButton(toggleId, ref isLoadedAndUnloadable))
{
// TODO: We can technically let profile manager take care of unloading/loading the plugin, but we should figure out error handling first.
if (!isLoadedAndUnloadable)
{
this.enableDisableStatus = OperationStatus.InProgress;
@ -2322,15 +2422,9 @@ internal class PluginInstallerWindow : Window, IDisposable
return;
}
var disableTask = Task.Run(() => plugin.Disable())
.ContinueWith(this.DisplayErrorContinuation, Locs.ErrorModal_DisableFail(plugin.Name));
disableTask.Wait();
profileManager.DefaultProfile.AddOrUpdate(plugin.Manifest.InternalName, false, false);
this.enableDisableStatus = OperationStatus.Complete;
if (!disableTask.Result)
return;
notifications.AddNotification(Locs.Notifications_PluginDisabled(plugin.Manifest.Name), Locs.Notifications_PluginDisabledTitle, NotificationType.Success);
});
}
@ -2346,17 +2440,7 @@ internal class PluginInstallerWindow : Window, IDisposable
plugin.ReloadManifest();
}
var enableTask = Task.Run(plugin.Enable)
.ContinueWith(
this.DisplayErrorContinuation,
Locs.ErrorModal_EnableFail(plugin.Name));
enableTask.Wait();
if (!enableTask.Result)
{
this.enableDisableStatus = OperationStatus.Complete;
return;
}
profileManager.DefaultProfile.AddOrUpdate(plugin.Manifest.InternalName, true, false);
var loadTask = Task.Run(() => plugin.LoadAsync(PluginLoadReason.Installer))
.ContinueWith(
@ -2409,6 +2493,29 @@ internal class PluginInstallerWindow : Window, IDisposable
// Only if the plugin isn't broken.
this.DrawOpenPluginSettingsButton(plugin);
}
if (applicableForProfiles && config.ProfilesEnabled)
{
ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Toolbox))
{
ImGui.OpenPopup(profileChooserPopupName);
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip(Locs.PluginButtonToolTip_PickProfiles);
}
else if (!applicableForProfiles && config.ProfilesEnabled)
{
ImGui.SameLine();
ImGui.BeginDisabled();
ImGuiComponents.IconButton(FontAwesomeIcon.Toolbox);
ImGui.EndDisabled();
if (ImGui.IsItemHovered())
ImGui.SetTooltip(Locs.PluginButtonToolTip_ProfilesNotSupported);
}
}
private async Task<bool> UpdateSinglePlugin(AvailablePluginUpdate update)
@ -2827,7 +2934,7 @@ internal class PluginInstallerWindow : Window, IDisposable
/// <param name="task">The previous task.</param>
/// <param name="state">An error message to be displayed.</param>
/// <returns>A value indicating whether to continue with the next task.</returns>
private bool DisplayErrorContinuation(Task task, object state)
public bool DisplayErrorContinuation(Task task, object state)
{
if (task.IsFaulted)
{
@ -2911,7 +3018,7 @@ internal class PluginInstallerWindow : Window, IDisposable
#region Header
public static string Header_Hint => Loc.Localize("InstallerHint", "This window allows you to install and remove in-game plugins.\nThey are made by third-party developers.");
public static string Header_Hint => Loc.Localize("InstallerHint", "This window allows you to install and remove Dalamud plugins.\nThey are made by the community.");
public static string Header_SearchPlaceholder => Loc.Localize("InstallerSearch", "Search");
@ -3068,6 +3175,10 @@ internal class PluginInstallerWindow : Window, IDisposable
public static string PluginButtonToolTip_OpenConfiguration => Loc.Localize("InstallerOpenConfig", "Open Configuration");
public static string PluginButtonToolTip_PickProfiles => Loc.Localize("InstallerPickProfiles", "Pick profiles for this plugin");
public static string PluginButtonToolTip_ProfilesNotSupported => Loc.Localize("InstallerProfilesNotSupported", "This plugin does not support profiles");
public static string PluginButtonToolTip_StartOnBoot => Loc.Localize("InstallerStartOnBoot", "Start on boot");
public static string PluginButtonToolTip_AutomaticReloading => Loc.Localize("InstallerAutomaticReloading", "Automatic reloading");
@ -3088,6 +3199,8 @@ internal class PluginInstallerWindow : Window, IDisposable
public static string PluginButtonToolTip_UnloadFailed => Loc.Localize("InstallerUnloadFailedTooltip", "Plugin unload failed, please restart your game and try again.");
public static string PluginButtonToolTip_NeedsToBeInDefault => Loc.Localize("InstallerUnloadNeedsToBeInDefault", "This plugin is in one or more profiles. If you want to enable or disable it, please do so by enabling or disabling one of the profiles it is in.\nIf you want to manage it manually, remove it from all profiles.");
#endregion
#region Notifications

View file

@ -0,0 +1,399 @@
using System;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Internal.Notifications;
using Dalamud.Interface.Raii;
using Dalamud.Plugin.Internal;
using Dalamud.Plugin.Internal.Profiles;
using ImGuiNET;
using Serilog;
namespace Dalamud.Interface.Internal.Windows.PluginInstaller;
internal class ProfileManagerWidget
{
private readonly PluginInstallerWindow installer;
private Mode mode = Mode.Overview;
private Guid? editingProfileGuid;
private string? pickerSelectedPluginInternalName = null;
private string profileNameEdit = string.Empty;
public ProfileManagerWidget(PluginInstallerWindow installer)
{
this.installer = installer;
}
public void Draw()
{
switch (this.mode)
{
case Mode.Overview:
this.DrawOverview();
break;
case Mode.EditSingleProfile:
this.DrawEdit();
break;
}
}
public void Reset()
{
this.mode = Mode.Overview;
this.editingProfileGuid = null;
this.pickerSelectedPluginInternalName = null;
}
private void DrawOverview()
{
var didAny = false;
var profman = Service<ProfileManager>.Get();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
profman.AddNewProfile();
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Add a new profile");
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(5);
ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.FileImport))
{
try
{
profman.ImportProfile(ImGui.GetClipboardText());
}
catch (Exception ex)
{
Log.Error(ex, "Could not import profile");
}
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Import a shared profile from your clipboard");
ImGui.Separator();
ImGuiHelpers.ScaledDummy(5);
var windowSize = ImGui.GetWindowSize();
if (ImGui.BeginChild("###profileChooserScrolling"))
{
Guid? toCloneGuid = null;
foreach (var profile in profman.Profiles)
{
if (profile.IsDefaultProfile)
continue;
var isEnabled = profile.IsEnabled;
if (ImGuiComponents.ToggleButton($"###toggleButton{profile.Guid}", ref isEnabled))
{
Task.Run(() => profile.SetState(isEnabled))
.ContinueWith(this.installer.DisplayErrorContinuation, "Could not change profile state.");
}
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(3);
ImGui.SameLine();
ImGui.Text(profile.Name);
ImGui.SameLine();
ImGui.SetCursorPosX(windowSize.X - (ImGuiHelpers.GlobalScale * 30));
if (ImGuiComponents.IconButton($"###editButton{profile.Guid}", FontAwesomeIcon.PencilAlt))
{
this.mode = Mode.EditSingleProfile;
this.editingProfileGuid = profile.Guid;
this.profileNameEdit = profile.Name;
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Edit this profile");
ImGui.SameLine();
ImGui.SetCursorPosX(windowSize.X - (ImGuiHelpers.GlobalScale * 30 * 2) - 5);
if (ImGuiComponents.IconButton($"###cloneButton{profile.Guid}", FontAwesomeIcon.Copy))
toCloneGuid = profile.Guid;
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Clone this profile");
ImGui.SameLine();
ImGui.SetCursorPosX(windowSize.X - (ImGuiHelpers.GlobalScale * 30 * 3) - 5);
if (ImGuiComponents.IconButton(FontAwesomeIcon.FileExport))
{
ImGui.SetClipboardText(profile.Model.Serialize());
Service<NotificationManager>.Get().AddNotification("Copied to clipboard!", type: NotificationType.Success);
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Copy profile to clipboard for sharing");
didAny = true;
ImGuiHelpers.ScaledDummy(2);
}
if (toCloneGuid != null)
{
profman.CloneProfile(profman.Profiles.First(x => x.Guid == toCloneGuid));
}
if (!didAny)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
ImGuiHelpers.CenteredText("No profiles! Add one!");
ImGui.PopStyleColor();
}
ImGui.EndChild();
}
}
private void DrawEdit()
{
if (this.editingProfileGuid == null)
{
Log.Error("Editing profile guid was null");
this.Reset();
return;
}
var profman = Service<ProfileManager>.Get();
var pm = Service<PluginManager>.Get();
var pic = Service<PluginImageCache>.Get();
var profile = profman.Profiles.FirstOrDefault(x => x.Guid == this.editingProfileGuid);
if (profile == null)
{
Log.Error("Could not find profile {Guid} for edit", this.editingProfileGuid);
this.Reset();
return;
}
const string addPluginToProfilePopup = "###addPluginToProfile";
if (ImGui.BeginPopup(addPluginToProfilePopup))
{
var selected =
pm.InstalledPlugins.FirstOrDefault(
x => x.Manifest.InternalName == this.pickerSelectedPluginInternalName);
if (ImGui.BeginCombo("###pluginPicker", selected == null ? "Pick one" : selected.Manifest.Name))
{
foreach (var plugin in pm.InstalledPlugins.Where(x => x.Manifest.SupportsProfiles))
{
if (ImGui.Selectable($"{plugin.Manifest.Name}###selector{plugin.Manifest.InternalName}"))
{
this.pickerSelectedPluginInternalName = plugin.Manifest.InternalName;
}
}
ImGui.EndCombo();
}
using (ImRaii.Disabled(this.pickerSelectedPluginInternalName == null))
{
if (ImGui.Button("Do it") && selected != null)
{
Task.Run(() => profile.AddOrUpdate(selected.Manifest.InternalName, selected.IsLoaded));
}
}
ImGui.EndPopup();
}
var didAny = false;
// ======== Top bar ========
var windowSize = ImGui.GetWindowSize();
if (ImGuiComponents.IconButton(FontAwesomeIcon.ArrowLeft))
this.Reset();
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Back to overview");
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(5);
ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.FileExport))
{
ImGui.SetClipboardText(profile.Model.Serialize());
Service<NotificationManager>.Get().AddNotification("Copied to clipboard!", type: NotificationType.Success);
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Copy profile to clipboard for sharing");
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(5);
ImGui.SameLine();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash))
{
Task.Run(() => profman.DeleteProfile(profile))
.ContinueWith(t =>
{
this.Reset();
this.installer.DisplayErrorContinuation(t, "Could not refresh profiles.");
});
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Delete this profile");
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(5);
ImGui.SameLine();
ImGui.SetNextItemWidth(windowSize.X / 3);
if (ImGui.InputText("###profileNameInput", ref this.profileNameEdit, 255))
{
profile.Name = this.profileNameEdit;
}
ImGui.SameLine();
ImGui.SetCursorPosX(windowSize.X - (ImGui.GetFrameHeight() * 1.55f * ImGuiHelpers.GlobalScale));
var isEnabled = profile.IsEnabled;
if (ImGuiComponents.ToggleButton($"###toggleButton{profile.Guid}", ref isEnabled))
{
Task.Run(() => profile.SetState(isEnabled))
.ContinueWith(this.installer.DisplayErrorContinuation, "Could not change profile state.");
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Enable/Disable this profile");
ImGui.Separator();
ImGuiHelpers.ScaledDummy(5);
var enableAtBoot = profile.AlwaysEnableAtBoot;
if (ImGui.Checkbox("Always enable when game starts", ref enableAtBoot))
{
profile.AlwaysEnableAtBoot = enableAtBoot;
}
ImGuiHelpers.ScaledDummy(5);
ImGui.Separator();
var wantPluginAddPopup = false;
if (ImGui.BeginChild("###profileEditorPluginList"))
{
var pluginLineHeight = 32 * ImGuiHelpers.GlobalScale;
foreach (var plugin in profile.Plugins)
{
didAny = true;
var pmPlugin = pm.InstalledPlugins.FirstOrDefault(x => x.Manifest.InternalName == plugin.InternalName);
if (pmPlugin != null)
{
pic.TryGetIcon(pmPlugin, pmPlugin.Manifest, pmPlugin.Manifest.IsThirdParty, out var icon);
icon ??= pic.DefaultIcon;
ImGui.Image(icon.ImGuiHandle, new Vector2(pluginLineHeight));
ImGui.SameLine();
var text = $"{pmPlugin.Name}";
var textHeight = ImGui.CalcTextSize(text);
var before = ImGui.GetCursorPos();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (pluginLineHeight / 2) - (textHeight.Y / 2));
ImGui.TextUnformatted(text);
ImGui.SetCursorPos(before);
}
else
{
ImGui.Image(pic.DefaultIcon.ImGuiHandle, new Vector2(pluginLineHeight));
ImGui.SameLine();
var text = $"{plugin.InternalName} (Not Installed)";
var textHeight = ImGui.CalcTextSize(text);
var before = ImGui.GetCursorPos();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (pluginLineHeight / 2) - (textHeight.Y / 2));
ImGui.TextUnformatted(text);
var available =
pm.AvailablePlugins.FirstOrDefault(
x => x.InternalName == plugin.InternalName && !x.SourceRepo.IsThirdParty);
if (available != null)
{
ImGui.SameLine();
ImGui.SetCursorPosX(windowSize.X - (ImGuiHelpers.GlobalScale * 32 * 2));
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (pluginLineHeight / 2) - (ImGui.GetFrameHeight() / 2));
if (ImGuiComponents.IconButton(FontAwesomeIcon.Download))
{
this.installer.StartInstall(available, false);
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Install this plugin");
}
ImGui.SetCursorPos(before);
}
ImGui.SameLine();
ImGui.SetCursorPosX(windowSize.X - (ImGuiHelpers.GlobalScale * 30));
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (pluginLineHeight / 2) - (ImGui.GetFrameHeight() / 2));
var enabled = plugin.IsEnabled;
if (ImGui.Checkbox($"###{this.editingProfileGuid}-{plugin.InternalName}", ref enabled))
{
Task.Run(() => profile.AddOrUpdate(plugin.InternalName, enabled))
.ContinueWith(this.installer.DisplayErrorContinuation, "Could not change plugin state.");
}
}
if (!didAny)
{
ImGui.TextColored(ImGuiColors.DalamudGrey, "Profile has no plugins!");
}
ImGuiHelpers.ScaledDummy(10);
var addPluginsText = "Add a plugin!";
ImGuiHelpers.CenterCursorFor((int)(ImGui.CalcTextSize(addPluginsText).X + 30 + (ImGuiHelpers.GlobalScale * 5)));
if (ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
wantPluginAddPopup = true;
ImGui.SameLine();
ImGuiHelpers.ScaledDummy(5);
ImGui.SameLine();
ImGui.TextUnformatted(addPluginsText);
ImGuiHelpers.ScaledDummy(10);
ImGui.EndChild();
}
if (wantPluginAddPopup)
ImGui.OpenPopup(addPluginToProfilePopup);
}
private enum Mode
{
Overview,
EditSingleProfile,
}
}