Add "restart in safe mode" button to blocked message

This commit is contained in:
goaaats 2025-04-25 22:12:39 +02:00
parent 999e3ea57a
commit 08f959444b
2 changed files with 192 additions and 8 deletions

View file

@ -639,11 +639,27 @@ internal class PluginInstallerWindow : Window, IDisposable
throw new ArgumentOutOfRangeException();
}
if (DateTime.Now - this.timeLoaded > TimeSpan.FromSeconds(90) && !pluginManager.PluginsReady)
if (DateTime.Now - this.timeLoaded > TimeSpan.FromSeconds(30) && !pluginManager.PluginsReady)
{
ImGuiHelpers.ScaledDummy(10);
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGuiHelpers.CenteredText("One of your plugins may be blocking the installer.");
ImGuiHelpers.CenteredText("You can try restarting in safe mode, and deleting the plugin.");
ImGui.PopStyleColor();
ImGuiHelpers.BeginHorizontalButtonGroup()
.Add(
"Restart in Safe Mode",
() =>
{
var config = Service<DalamudConfiguration>.Get();
config.PluginSafeMode = true;
config.ForceSave();
Dalamud.RestartGame();
})
.SetCentered(true)
.WithHeight(30)
.Draw();
}
}
}
@ -3136,11 +3152,13 @@ internal class PluginInstallerWindow : Window, IDisposable
{
ImGuiComponents.DisabledToggleButton(toggleId, this.loadingIndicatorKind == LoadingIndicatorKind.EnablingSingle);
}
else if (disabled || inMultipleProfiles || inSingleNonDefaultProfileWhichIsDisabled)
else if (disabled || inMultipleProfiles || inSingleNonDefaultProfileWhichIsDisabled || pluginManager.SafeMode)
{
ImGuiComponents.DisabledToggleButton(toggleId, isLoadedAndUnloadable);
if (inMultipleProfiles && ImGui.IsItemHovered())
if (pluginManager.SafeMode && ImGui.IsItemHovered())
ImGui.SetTooltip(Locs.PluginButtonToolTip_SafeMode);
else if (inMultipleProfiles && ImGui.IsItemHovered())
ImGui.SetTooltip(Locs.PluginButtonToolTip_NeedsToBeInSingleProfile);
else if (inSingleNonDefaultProfileWhichIsDisabled && ImGui.IsItemHovered())
ImGui.SetTooltip(Locs.PluginButtonToolTip_SingleProfileDisabled(profilesThatWantThisPlugin.First().Name));
@ -4220,6 +4238,8 @@ internal class PluginInstallerWindow : Window, IDisposable
public static string PluginButtonToolTip_NeedsToBeInSingleProfile => Loc.Localize("InstallerUnloadNeedsToBeInSingleProfile", "This plugin is in more than one collection. If you want to enable or disable it, please do so by enabling or disabling the collections it is in.\nIf you want to manage it here, make sure it is only in a single collection.");
public static string PluginButtonToolTip_SafeMode => Loc.Localize("InstallerButtonSafeModeTooltip", "Cannot enable plugins in safe mode.");
public static string PluginButtonToolTip_SingleProfileDisabled(string name) => Loc.Localize("InstallerSingleProfileDisabled", "The collection '{0}' which contains this plugin is disabled.\nPlease enable it in the collections manager to toggle the plugin individually.").Format(name);
#endregion

View file

@ -111,7 +111,7 @@ public static class ImGuiHelpers
/// </summary>
/// <param name="size">The size of the indent.</param>
public static void ScaledIndent(float size) => ImGui.Indent(size * GlobalScale);
/// <summary>
/// Use a relative ImGui.SameLine() from your current cursor position, scaled by the Dalamud global scale.
/// </summary>
@ -286,7 +286,7 @@ public static class ImGuiHelpers
foreach (ref var kp in new Span<ImFontKerningPair>((void*)font->KerningPairs.Data, font->KerningPairs.Size))
kp.AdvanceXAdjustment = rounder(kp.AdvanceXAdjustment * scale);
foreach (ref var fkp in new Span<float>((void*)font->FrequentKerningPairs.Data, font->FrequentKerningPairs.Size))
fkp = rounder(fkp * scale);
}
@ -450,7 +450,7 @@ public static class ImGuiHelpers
/// <summary>
/// Center the ImGui cursor for a certain text.
/// </summary>
/// </summary>
/// <param name="text">The text to center for.</param>
public static void CenterCursorForText(string text) => CenterCursorFor(ImGui.CalcTextSize(text).X);
@ -461,6 +461,12 @@ public static class ImGuiHelpers
public static void CenterCursorFor(float itemWidth) =>
ImGui.SetCursorPosX((int)((ImGui.GetWindowWidth() - itemWidth) / 2));
/// <summary>
/// Starts a new horizontal button group.
/// </summary>
/// <returns>The group.</returns>
public static HorizontalButtonGroup BeginHorizontalButtonGroup() => new();
/// <summary>
/// Allocates memory on the heap using <see cref="ImGuiNative.igMemAlloc"/><br />
/// Memory must be freed using <see cref="ImGuiNative.igMemFree"/>.
@ -535,7 +541,7 @@ public static class ImGuiHelpers
builder.BuildRanges(out var vec);
return new ReadOnlySpan<ushort>((void*)vec.Data, vec.Size).ToArray();
}
/// <inheritdoc cref="CreateImGuiRangesFrom(IEnumerable{UnicodeRange})"/>
public static ushort[] CreateImGuiRangesFrom(params UnicodeRange[] ranges)
=> CreateImGuiRangesFrom((IEnumerable<UnicodeRange>)ranges);
@ -618,7 +624,7 @@ public static class ImGuiHelpers
ImGuiNative.ImGuiInputTextCallbackData_InsertChars(data, 0, pBuf, pBuf + len);
ImGuiNative.ImGuiInputTextCallbackData_SelectAll(data);
}
/// <summary>
/// Finds the corresponding ImGui viewport ID for the given window handle.
/// </summary>
@ -891,4 +897,162 @@ public static class ImGuiHelpers
set => this.TextureIndexAndGlyphId = (this.TextureIndexAndGlyphId & ~GlyphIdMask) | ((uint)value << GlyphIdShift);
}
}
/// <summary>
/// Class helper for creating a horizontal button group.
/// </summary>
public class HorizontalButtonGroup
{
private readonly List<ButtonDef> buttons = [];
/// <summary>
/// Gets or sets a value indicating whether the buttons should be centered horizontally.
/// </summary>
public bool IsCentered { get; set; } = false;
/// <summary>
/// Gets or sets the height of the buttons. If null, the default frame height is used.
/// </summary>
public float? Height { get; set; }
/// <summary>
/// Gets or sets the extra margin to add to the inside of each button, before and after the text.
/// If null, the default margin is used.
/// </summary>
public float? ExtraMargin { get; set; }
/// <summary>
/// Gets or sets the padding between buttons. If null, the default item spacing is used.
/// </summary>
public float? PaddingBetweenButtons { get; set; }
/// <summary>
/// Add a button to the group.
/// </summary>
/// <param name="text">The text of the button.</param>
/// <param name="action">The action to perform when the button is pressed.</param>
/// <returns>The group.</returns>
public HorizontalButtonGroup Add(string text, Action action)
{
this.buttons.Add(new ButtonDef(text, action));
return this;
}
/// <summary>
/// Sets whether the buttons should be centered horizontally.
/// </summary>
/// <param name="centered">The value.</param>
/// <returns>The group.</returns>
public HorizontalButtonGroup SetCentered(bool centered)
{
this.IsCentered = centered;
return this;
}
/// <summary>
/// Sets the height of the buttons.
/// </summary>
/// <param name="height">The height.</param>
/// <returns>The group.</returns>
public HorizontalButtonGroup WithHeight(float height)
{
this.Height = height;
return this;
}
/// <summary>
/// Sets the extra margin to add to the inside of each button, before and after the text.
/// </summary>
/// <param name="extraMargin">The margin.</param>
/// <returns>The group.</returns>
public HorizontalButtonGroup WithExtraMargin(float extraMargin)
{
this.ExtraMargin = extraMargin;
return this;
}
/// <summary>
/// Sets the padding between buttons.
/// </summary>
/// <param name="padding">The padding.</param>
/// <returns>The group.</returns>
public HorizontalButtonGroup WithPaddingBetweenButtons(float padding)
{
this.PaddingBetweenButtons = padding;
return this;
}
/// <summary>
/// Draw the button group at the current location.
/// </summary>
public void Draw()
{
var buttonHeight = this.Height * GlobalScale ?? ImGui.GetFrameHeight();
var buttonCount = this.buttons.Count;
if (buttonCount == 0)
return;
var buttonWidths = new float[buttonCount];
var totalContentWidth = 0f;
var extraMargin = this.ExtraMargin ?? 0f;
for (var i = 0; i < buttonCount; i++)
{
var buttonText = this.buttons[i].Text;
buttonWidths[i] = ImGui.CalcTextSize(buttonText).X + (2 * extraMargin) + (2 * ImGui.GetStyle().FramePadding.X);
totalContentWidth += buttonWidths[i];
}
var buttonPadding = this.PaddingBetweenButtons ?? ImGui.GetStyle().ItemSpacing.X;
if (buttonCount > 1)
totalContentWidth += buttonPadding * (buttonCount - 1);
var startX = ImGui.GetCursorPosX();
if (this.IsCentered)
{
var availWidth = ImGui.GetContentRegionAvail().X;
startX += (availWidth - totalContentWidth) * 0.5f;
ImGui.SetCursorPosX(startX);
}
var originalSpacing = ImGui.GetStyle().ItemSpacing;
if (this.PaddingBetweenButtons.HasValue)
{
var spacing = originalSpacing;
spacing.X = this.PaddingBetweenButtons.Value;
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, spacing);
}
for (var i = 0; i < buttonCount; i++)
{
var buttonDef = this.buttons[i];
if (this.ExtraMargin.HasValue)
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, new Vector2(ImGui.GetStyle().FramePadding.X + extraMargin, ImGui.GetStyle().FramePadding.Y));
if (this.Height.HasValue)
{
if (ImGui.Button(buttonDef.Text, new Vector2(buttonWidths[i], buttonHeight)))
buttonDef.Action?.Invoke();
}
else
{
if (ImGui.Button(buttonDef.Text, new Vector2(buttonWidths[i], -1)))
buttonDef.Action?.Invoke();
}
if (this.ExtraMargin.HasValue)
ImGui.PopStyleVar();
if (i < buttonCount - 1)
ImGui.SameLine();
}
if (this.PaddingBetweenButtons.HasValue)
ImGui.PopStyleVar();
}
private record ButtonDef(string Text, Action Action);
}
}