feat: settings window rework

This commit is contained in:
goaaats 2023-01-06 22:32:44 +01:00
parent 0dc58cce56
commit bc3dcdfad7
No known key found for this signature in database
GPG key ID: 49E2AA8C6A76498B
22 changed files with 1724 additions and 1084 deletions

View file

@ -363,7 +363,7 @@ public sealed unsafe class GameGui : IDisposable, IServiceType
/// </summary>
/// <param name="addonPtr">The addon address.</param>
/// <returns>A pointer to the agent interface.</returns>
public unsafe IntPtr FindAgentInterface(IntPtr addonPtr)
public IntPtr FindAgentInterface(IntPtr addonPtr)
{
if (addonPtr == IntPtr.Zero)
return IntPtr.Zero;
@ -411,11 +411,26 @@ public sealed unsafe class GameGui : IDisposable, IServiceType
this.utf8StringFromSequenceHook.Dispose();
}
/// <summary>
/// Indicates if the game is on the title screen.
/// </summary>
/// <returns>A value indicating whether or not the game is on the title screen.</returns>
internal bool IsOnTitleScreen()
{
var charaSelect = this.GetAddonByName("CharaSelect", 1);
var charaMake = this.GetAddonByName("CharaMake", 1);
var titleDcWorldMap = this.GetAddonByName("TitleDCWorldMap", 1);
if (charaMake != nint.Zero || charaSelect != nint.Zero || titleDcWorldMap != nint.Zero)
return false;
return !Service<ClientState.ClientState>.Get().IsLoggedIn;
}
/// <summary>
/// Set the current background music.
/// </summary>
/// <param name="bgmKey">The background music key.</param>
public void SetBgm(ushort bgmKey) => this.setGlobalBgmHook.Original(bgmKey, 0, 0, 0, 0, 0);
internal void SetBgm(ushort bgmKey) => this.setGlobalBgmHook.Original(bgmKey, 0, 0, 0, 0, 0);
/// <summary>
/// Reset the stored "UI hide" state.

View file

@ -101,11 +101,6 @@ internal class DalamudCommands : IServiceType
HelpMessage = Loc.Localize("DalamudInstallerHelp", "Open the plugin installer"),
});
commandManager.AddHandler("/xlcredits", new CommandInfo(this.OnOpenCreditsCommand)
{
HelpMessage = Loc.Localize("DalamudCreditsHelp", "Opens the credits for dalamud."),
});
commandManager.AddHandler("/xllanguage", new CommandInfo(this.OnSetLanguageCommand)
{
HelpMessage =
@ -328,11 +323,6 @@ internal class DalamudCommands : IServiceType
Service<DalamudInterface>.Get().TogglePluginInstallerWindow();
}
private void OnOpenCreditsCommand(string command, string arguments)
{
Service<DalamudInterface>.Get().ToggleCreditsWindow();
}
private void OnSetLanguageCommand(string command, string arguments)
{
var chatGui = Service<ChatGui>.Get();

View file

@ -12,11 +12,13 @@ using Dalamud.Configuration.Internal;
using Dalamud.Game.ClientState.Conditions;
using Dalamud.Game.Gui;
using Dalamud.Game.Internal;
using Dalamud.Interface.Animation.EasingFunctions;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Internal.ManagedAsserts;
using Dalamud.Interface.Internal.Windows;
using Dalamud.Interface.Internal.Windows.PluginInstaller;
using Dalamud.Interface.Internal.Windows.SelfTest;
using Dalamud.Interface.Internal.Windows.Settings;
using Dalamud.Interface.Internal.Windows.StyleEditor;
using Dalamud.Interface.Style;
using Dalamud.Interface.Windowing;
@ -40,12 +42,13 @@ namespace Dalamud.Interface.Internal;
[ServiceManager.EarlyLoadedService]
internal class DalamudInterface : IDisposable, IServiceType
{
private const float CreditsDarkeningMaxAlpha = 0.8f;
private static readonly ModuleLog Log = new("DUI");
private readonly ChangelogWindow changelogWindow;
private readonly ColorDemoWindow colorDemoWindow;
private readonly ComponentDemoWindow componentDemoWindow;
private readonly CreditsWindow creditsWindow;
private readonly DataWindow dataWindow;
private readonly GamepadModeNotifierWindow gamepadModeNotifierWindow;
private readonly ImeWindow imeWindow;
@ -62,6 +65,9 @@ internal class DalamudInterface : IDisposable, IServiceType
private readonly TextureWrap logoTexture;
private readonly TextureWrap tsmLogoTexture;
private bool isCreditsDarkening = false;
private OutCubic creditsDarkeningAnimation = new(TimeSpan.FromSeconds(10));
#if DEBUG
private bool isImGuiDrawDevMenu = true;
#else
@ -90,7 +96,6 @@ internal class DalamudInterface : IDisposable, IServiceType
this.changelogWindow = new ChangelogWindow() { IsOpen = false };
this.colorDemoWindow = new ColorDemoWindow() { IsOpen = false };
this.componentDemoWindow = new ComponentDemoWindow() { IsOpen = false };
this.creditsWindow = new CreditsWindow() { IsOpen = false };
this.dataWindow = new DataWindow() { IsOpen = false };
this.gamepadModeNotifierWindow = new GamepadModeNotifierWindow() { IsOpen = false };
this.imeWindow = new ImeWindow() { IsOpen = false };
@ -107,7 +112,6 @@ internal class DalamudInterface : IDisposable, IServiceType
this.WindowSystem.AddWindow(this.changelogWindow);
this.WindowSystem.AddWindow(this.colorDemoWindow);
this.WindowSystem.AddWindow(this.componentDemoWindow);
this.WindowSystem.AddWindow(this.creditsWindow);
this.WindowSystem.AddWindow(this.dataWindow);
this.WindowSystem.AddWindow(this.gamepadModeNotifierWindow);
this.WindowSystem.AddWindow(this.imeWindow);
@ -147,6 +151,9 @@ internal class DalamudInterface : IDisposable, IServiceType
{
tsm.AddEntryCore(Loc.Localize("TSMDalamudDevMenu", "Developer Menu"), this.tsmLogoTexture, () => this.isImGuiDrawDevMenu = true);
}
this.creditsDarkeningAnimation.Point1 = Vector2.Zero;
this.creditsDarkeningAnimation.Point2 = new Vector2(CreditsDarkeningMaxAlpha);
}
/// <summary>
@ -176,7 +183,6 @@ internal class DalamudInterface : IDisposable, IServiceType
this.WindowSystem.RemoveAllWindows();
this.changelogWindow.Dispose();
this.creditsWindow.Dispose();
this.consoleWindow.Dispose();
this.pluginWindow.Dispose();
this.titleScreenMenuWindow.Dispose();
@ -202,11 +208,6 @@ internal class DalamudInterface : IDisposable, IServiceType
/// </summary>
public void OpenComponentDemoWindow() => this.componentDemoWindow.IsOpen = true;
/// <summary>
/// Opens the <see cref="CreditsWindow"/>.
/// </summary>
public void OpenCreditsWindow() => this.creditsWindow.IsOpen = true;
/// <summary>
/// Opens the <see cref="DataWindow"/>.
/// </summary>
@ -313,11 +314,6 @@ internal class DalamudInterface : IDisposable, IServiceType
/// </summary>
public void ToggleComponentDemoWindow() => this.componentDemoWindow.Toggle();
/// <summary>
/// Toggles the <see cref="CreditsWindow"/>.
/// </summary>
public void ToggleCreditsWindow() => this.creditsWindow.Toggle();
/// <summary>
/// Toggles the <see cref="DataWindow"/>.
/// </summary>
@ -388,6 +384,18 @@ internal class DalamudInterface : IDisposable, IServiceType
#endregion
/// <summary>
/// Toggle the screen darkening effect used for the credits.
/// </summary>
/// <param name="status">Whether or not to turn the effect on.</param>
public void SetCreditsDarkeningAnimation(bool status)
{
this.isCreditsDarkening = status;
if (status)
this.creditsDarkeningAnimation.Restart();
}
private void OnDraw()
{
this.FrameCount++;
@ -430,6 +438,9 @@ internal class DalamudInterface : IDisposable, IServiceType
if (this.isImGuiTestWindowsInMonospace)
ImGui.PopFont();
if (this.isCreditsDarkening)
this.DrawCreditsDarkeningAnimation();
// Release focus of any ImGui window if we click into the game.
var io = ImGui.GetIO();
if (!io.WantCaptureMouse && (User32.GetKeyState((int)User32.VirtualKey.VK_LBUTTON) & 0x8000) != 0)
@ -443,6 +454,26 @@ internal class DalamudInterface : IDisposable, IServiceType
}
}
private void DrawCreditsDarkeningAnimation()
{
ImGui.PushStyleVar(ImGuiStyleVar.WindowRounding, 0f);
ImGui.SetNextWindowPos(new Vector2(0, 0));
ImGui.SetNextWindowSize(ImGuiHelpers.MainViewport.Size);
ImGuiHelpers.ForceNextWindowMainViewport();
this.creditsDarkeningAnimation.Update();
ImGui.SetNextWindowBgAlpha(Math.Min(this.creditsDarkeningAnimation.EasedPoint.X, CreditsDarkeningMaxAlpha));
ImGui.Begin(
"###CreditsDarkenWindow",
ImGuiWindowFlags.NoInputs | ImGuiWindowFlags.NoDocking | ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoMove |
ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.NoBringToFrontOnFocus |
ImGuiWindowFlags.NoNav);
ImGui.End();
ImGui.PopStyleVar();
}
private void DrawHiddenDevMenuOpener()
{
var condition = Service<Condition>.Get();
@ -573,11 +604,6 @@ internal class DalamudInterface : IDisposable, IServiceType
this.OpenDataWindow();
}
if (ImGui.MenuItem("Open Credits window"))
{
this.OpenCreditsWindow();
}
if (ImGui.MenuItem("Open Settings window"))
{
this.OpenSettings();

View file

@ -52,7 +52,7 @@ internal class ConsoleWindow : Window, IDisposable
/// Initializes a new instance of the <see cref="ConsoleWindow"/> class.
/// </summary>
public ConsoleWindow()
: base("Dalamud Console")
: base("Dalamud Console", ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)
{
var configuration = Service<DalamudConfiguration>.Get();

View file

@ -0,0 +1,52 @@
using System;
namespace Dalamud.Interface.Internal.Windows.Settings;
/// <summary>
/// Basic, drawable settings entry.
/// </summary>
public abstract class SettingsEntry
{
/// <summary>
/// Gets or sets the public, searchable name of this settings entry.
/// </summary>
public string? Name { get; protected set; }
/// <summary>
/// Gets or sets a value indicating whether or not this entry is valid.
/// </summary>
public virtual bool IsValid { get; protected set; } = true;
/// <summary>
/// Gets or sets a value indicating whether or not this entry is visible.
/// </summary>
public virtual bool IsVisible { get; protected set; } = true;
/// <summary>
/// Gets the ID of this settings entry, used for ImGui uniqueness.
/// </summary>
protected Guid Id { get; } = Guid.NewGuid();
/// <summary>
/// Load this setting.
/// </summary>
public abstract void Load();
/// <summary>
/// Save this setting.
/// </summary>
public abstract void Save();
/// <summary>
/// Draw this setting control.
/// </summary>
public abstract void Draw();
/// <summary>
/// Function to be called when the tab is closed.
/// </summary>
public virtual void OnClose()
{
// ignored
}
}

View file

@ -0,0 +1,72 @@
using System;
using System.Diagnostics.CodeAnalysis;
namespace Dalamud.Interface.Internal.Windows.Settings;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public abstract class SettingsTab : IDisposable
{
public abstract SettingsEntry[] Entries { get; }
public abstract string Title { get; }
public bool IsOpen { get; set; } = false;
public virtual bool IsVisible { get; } = true;
public virtual void OnOpen()
{
// ignored
}
public virtual void OnClose()
{
foreach (var settingsEntry in this.Entries)
{
settingsEntry.OnClose();
}
}
public virtual void Draw()
{
foreach (var settingsEntry in this.Entries)
{
if (settingsEntry.IsVisible)
settingsEntry.Draw();
ImGuiHelpers.ScaledDummy(5);
}
ImGuiHelpers.ScaledDummy(15);
}
public virtual void Load()
{
foreach (var settingsEntry in this.Entries)
{
settingsEntry.Load();
}
}
public virtual void Save()
{
foreach (var settingsEntry in this.Entries)
{
settingsEntry.Save();
}
}
public virtual void Discard()
{
foreach (var settingsEntry in this.Entries)
{
settingsEntry.Load();
}
}
/// <inheritdoc/>
public virtual void Dispose()
{
// ignored
}
}

View file

@ -0,0 +1,232 @@
using System.Linq;
using System.Numerics;
using CheapLoc;
using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Internal.Windows.Settings.Tabs;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin.Internal;
using Dalamud.Utility;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Settings;
/// <summary>
/// The window that allows for general configuration of Dalamud itself.
/// </summary>
internal class SettingsWindow : Window
{
private readonly SettingsTab[] tabs =
{
new SettingsTabGeneral(),
new SettingsTabLook(),
new SettingsTabDtr(),
new SettingsTabExperimental(),
new SettingsTabAbout(),
};
private string searchInput = string.Empty;
/// <summary>
/// Initializes a new instance of the <see cref="SettingsWindow"/> class.
/// </summary>
public SettingsWindow()
: base(Loc.Localize("DalamudSettingsHeader", "Dalamud Settings") + "###XlSettings2", ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoScrollbar)
{
this.Size = new Vector2(740, 550);
this.SizeConstraints = new WindowSizeConstraints()
{
MinimumSize = new Vector2(752, 610),
MaximumSize = new Vector2(1780, 940),
};
this.SizeCondition = ImGuiCond.FirstUseEver;
}
/// <inheritdoc/>
public override void OnOpen()
{
foreach (var settingsTab in this.tabs)
{
settingsTab.Load();
}
this.searchInput = string.Empty;
base.OnOpen();
}
/// <inheritdoc/>
public override void OnClose()
{
var configuration = Service<DalamudConfiguration>.Get();
var interfaceManager = Service<InterfaceManager>.Get();
var rebuildFont =
ImGui.GetIO().FontGlobalScale != configuration.GlobalUiScale ||
interfaceManager.FontGamma != configuration.FontGammaLevel ||
interfaceManager.UseAxis != configuration.UseAxisFontsFromGame;
ImGui.GetIO().FontGlobalScale = configuration.GlobalUiScale;
interfaceManager.FontGammaOverride = null;
interfaceManager.UseAxisOverride = null;
if (rebuildFont)
interfaceManager.RebuildFonts();
foreach (var settingsTab in this.tabs)
{
if (settingsTab.IsOpen)
settingsTab.OnClose();
settingsTab.IsOpen = false;
}
}
/// <inheritdoc/>
public override void Draw()
{
var windowSize = ImGui.GetWindowSize();
if (ImGui.BeginTabBar("###settingsTabs"))
{
if (string.IsNullOrEmpty(this.searchInput))
{
foreach (var settingsTab in this.tabs.Where(x => x.IsVisible))
{
if (ImGui.BeginTabItem(settingsTab.Title))
{
if (!settingsTab.IsOpen)
{
settingsTab.IsOpen = true;
settingsTab.OnOpen();
}
if (ImGui.BeginChild($"###settings_scrolling_{settingsTab.Title}", new Vector2(-1, -1), false))
{
settingsTab.Draw();
}
ImGui.EndChild();
ImGui.EndTabItem();
}
else if (settingsTab.IsOpen)
{
settingsTab.IsOpen = false;
settingsTab.OnClose();
}
}
}
else
{
if (ImGui.BeginTabItem("Search Results"))
{
var any = false;
foreach (var settingsTab in this.tabs.Where(x => x.IsVisible))
{
var eligible = settingsTab.Entries.Where(x => !x.Name.IsNullOrEmpty() && x.Name.ToLower().Contains(this.searchInput.ToLower())).ToArray();
if (!eligible.Any())
continue;
any = true;
ImGui.TextColored(ImGuiColors.DalamudGrey, settingsTab.Title);
ImGui.Dummy(new Vector2(5));
foreach (var settingsTabEntry in eligible)
{
settingsTabEntry.Draw();
ImGuiHelpers.ScaledDummy(3);
}
ImGui.Separator();
ImGui.Dummy(new Vector2(10));
}
if (!any)
ImGui.TextColored(ImGuiColors.DalamudGrey, "No results found...");
ImGui.EndTabItem();
}
}
}
ImGui.SetCursorPos(windowSize - ImGuiHelpers.ScaledVector2(70));
if (ImGui.BeginChild("###settingsFinishButton"))
{
ImGui.PushStyleVar(ImGuiStyleVar.FrameRounding, 100f);
ImGui.PushFont(InterfaceManager.IconFont);
var invalid = this.tabs.Any(x => x.Entries.Any(y => !y.IsValid));
if (invalid)
ImGui.BeginDisabled();
if (ImGui.Button(FontAwesomeIcon.Save.ToIconString(), new Vector2(40)))
{
this.Save();
this.IsOpen = false;
}
ImGui.PopStyleVar();
ImGui.PopFont();
if (ImGui.IsItemHovered())
ImGui.SetTooltip(Loc.Localize("DalamudSettingsSaveAndExit", "Save changes and close"));
if (invalid)
ImGui.EndDisabled();
}
ImGui.EndChild();
ImGui.SetCursorPos(new Vector2(windowSize.X - 250, ImGui.GetTextLineHeightWithSpacing() + (ImGui.GetStyle().FramePadding.Y * 2)));
ImGui.SetNextItemWidth(240);
ImGui.InputTextWithHint("###searchInput", "Search for settings...", ref this.searchInput, 100);
}
private void Save()
{
var configuration = Service<DalamudConfiguration>.Get();
foreach (var settingsTab in this.tabs)
{
settingsTab.Save();
}
// Apply docking flag
if (!configuration.IsDocking)
{
ImGui.GetIO().ConfigFlags &= ~ImGuiConfigFlags.DockingEnable;
}
else
{
ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.DockingEnable;
}
// NOTE (Chiv) Toggle gamepad navigation via setting
if (!configuration.IsGamepadNavigationEnabled)
{
ImGui.GetIO().BackendFlags &= ~ImGuiBackendFlags.HasGamepad;
ImGui.GetIO().ConfigFlags &= ~ImGuiConfigFlags.NavEnableSetMousePos;
var di = Service<DalamudInterface>.Get();
di.CloseGamepadModeNotifierWindow();
}
else
{
ImGui.GetIO().BackendFlags |= ImGuiBackendFlags.HasGamepad;
ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.NavEnableSetMousePos;
}
configuration.QueueSave();
_ = Service<PluginManager>.Get().ReloadPluginMastersAsync();
Service<InterfaceManager>.Get().RebuildFonts();
}
}

View file

@ -1,23 +1,22 @@
using System;
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Numerics;
using CheapLoc;
using Dalamud.Game.Gui;
using Dalamud.Interface.GameFonts;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin.Internal;
using Dalamud.Utility;
using ImGuiNET;
using ImGuiScene;
namespace Dalamud.Interface.Internal.Windows;
namespace Dalamud.Interface.Internal.Windows.Settings.Tabs;
/// <summary>
/// A window documenting contributors to the project.
/// </summary>
internal class CreditsWindow : Window, IDisposable
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public class SettingsTabAbout : SettingsTab
{
private const float CreditFps = 60.0f;
private const string ThankYouText = "Thank you!";
@ -27,7 +26,8 @@ A FFXIV Plugin Framework
Version D{0}
created by:
Created by:
goat
daemitus
@ -124,8 +124,15 @@ philpax
We use these awesome libraries:
FFXIVClientStructs ({2})
Copyright (c) 2021 aers
Licensed under the MIT License
Lumina by Adam
FFXIVClientStructs by aers ({2})
Licensed under the WTFPL v2.0
Reloaded Libraries by Sewer56
Licensed under the GNU Lesser General Public License v3.0
DotNetCorePlugins
Copyright (c) Nate McMaster
@ -145,17 +152,20 @@ Licensed under the BSD 2-Clause License
SRELL
Copyright (c) 2012-2022, Nozomu Katoo
STB Libraries
Copyright (c) 2017 Sean Barrett
Licensed under the MIT License
Please see licenses.txt for more information.
Thanks to everyone in the XIVLauncher Discord server
Thanks to everyone in the XIVLauncher Discord server!
Join us at: https://discord.gg/3NMcUV5
Dalamud is licensed under AGPL v3 or later
Contribute at: https://github.com/goatsoft/Dalamud
Dalamud is licensed under AGPL v3 or later.
Contribute at: https://github.com/goatcorp/Dalamud
";
private readonly TextureWrap logoTexture;
@ -163,28 +173,22 @@ Contribute at: https://github.com/goatsoft/Dalamud
private string creditsText;
private bool resetNow = false;
private GameFontHandle? thankYouFont;
/// <summary>
/// Initializes a new instance of the <see cref="CreditsWindow"/> class.
/// </summary>
public CreditsWindow()
: base("Dalamud Credits", ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoTitleBar, true)
public SettingsTabAbout()
{
var dalamud = Service<Dalamud>.Get();
var interfaceManager = Service<InterfaceManager>.Get();
this.logoTexture = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "logo.png"));
this.logoTexture = interfaceManager.LoadImage(Path.Combine(dalamud.AssetDirectory.FullName, "UIRes", "logo.png"))!;
this.creditsThrottler = new();
this.Size = new Vector2(500, 400);
this.SizeCondition = ImGuiCond.Always;
this.PositionCondition = ImGuiCond.Always;
this.BgAlpha = 0.8f;
}
public override SettingsEntry[] Entries { get; } = { };
public override string Title => Loc.Localize("DalamudAbout", "About");
/// <inheritdoc/>
public override void OnOpen()
{
@ -195,7 +199,10 @@ Contribute at: https://github.com/goatsoft/Dalamud
this.creditsText = string.Format(CreditsTextTempl, typeof(Dalamud).Assembly.GetName().Version, pluginCredits, Util.GetGitHashClientStructs());
Service<GameGui>.Get().SetBgm(833);
var gg = Service<GameGui>.Get();
if (!gg.IsOnTitleScreen())
gg.SetBgm(833);
this.creditsThrottler.Restart();
if (this.thankYouFont == null)
@ -203,41 +210,36 @@ Contribute at: https://github.com/goatsoft/Dalamud
var gfm = Service<GameFontManager>.Get();
this.thankYouFont = gfm.NewFontRef(new GameFontStyle(GameFontFamilyAndSize.TrumpGothic34));
}
this.resetNow = true;
Service<DalamudInterface>.Get().SetCreditsDarkeningAnimation(true);
}
/// <inheritdoc/>
public override void OnClose()
{
this.creditsThrottler.Reset();
Service<GameGui>.Get().SetBgm(9999);
var gg = Service<GameGui>.Get();
if (!gg.IsOnTitleScreen())
gg.SetBgm(9999);
Service<DalamudInterface>.Get().SetCreditsDarkeningAnimation(false);
}
/// <inheritdoc/>
public override void PreDraw()
{
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 0));
base.PreDraw();
}
/// <inheritdoc/>
public override void PostDraw()
{
ImGui.PopStyleVar();
base.PostDraw();
}
/// <inheritdoc/>
public override void Draw()
{
var screenSize = ImGui.GetMainViewport().Size;
var windowSize = ImGui.GetWindowSize();
this.Position = (screenSize - windowSize) / 2;
ImGui.BeginChild("scrolling", Vector2.Zero, false, ImGuiWindowFlags.NoScrollbar);
if (this.resetNow)
{
ImGui.SetScrollY(0);
this.resetNow = false;
}
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero);
ImGuiHelpers.ScaledDummy(0, windowSize.Y + 20f);
@ -295,30 +297,13 @@ Contribute at: https://github.com/goatsoft/Dalamud
ImGui.EndChild();
ImGui.SetCursorPos(new Vector2(0));
ImGui.BeginChild("button", Vector2.Zero, false, ImGuiWindowFlags.NoScrollbar);
var closeButtonSize = new Vector2(30);
ImGui.PushFont(InterfaceManager.IconFont);
ImGui.SetCursorPos(new Vector2(windowSize.X - closeButtonSize.X - 5, 5));
ImGui.PushStyleColor(ImGuiCol.Button, Vector4.Zero);
ImGui.PushStyleColor(ImGuiCol.ButtonHovered, Vector4.Zero);
ImGui.PushStyleColor(ImGuiCol.ButtonActive, Vector4.Zero);
if (ImGui.Button(FontAwesomeIcon.Times.ToIconString(), closeButtonSize))
{
this.IsOpen = false;
}
ImGui.PopStyleColor(3);
ImGui.PopFont();
ImGui.EndChild();
base.Draw();
}
/// <summary>
/// Disposes of managed and unmanaged resources.
/// </summary>
public void Dispose()
public override void Dispose()
{
this.logoTexture?.Dispose();
this.thankYouFont?.Dispose();

View file

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using CheapLoc;
using Dalamud.Configuration.Internal;
using Dalamud.Game.Gui.Dtr;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Settings.Tabs;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public class SettingsTabDtr : SettingsTab
{
private List<string>? dtrOrder;
private List<string>? dtrIgnore;
private int dtrSpacing;
private bool dtrSwapDirection;
public override SettingsEntry[] Entries { get; } = Array.Empty<SettingsEntry>();
public override string Title => Loc.Localize("DalamudSettingsServerInfoBar", "Server Info Bar");
public override void Draw()
{
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarHint", "Plugins can put additional information into your server information bar(where world & time can be seen).\nYou can reorder and disable these here."));
ImGuiHelpers.ScaledDummy(10);
var configuration = Service<DalamudConfiguration>.Get();
var dtrBar = Service<DtrBar>.Get();
var order = configuration.DtrOrder!.Where(x => dtrBar.HasEntry(x)).ToList();
var ignore = configuration.DtrIgnore!.Where(x => dtrBar.HasEntry(x)).ToList();
var orderLeft = configuration.DtrOrder!.Where(x => !order.Contains(x)).ToList();
var ignoreLeft = configuration.DtrIgnore!.Where(x => !ignore.Contains(x)).ToList();
if (order.Count == 0)
{
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarDidNone", "You have no plugins that use this feature."));
}
var isOrderChange = false;
for (var i = 0; i < order.Count; i++)
{
var title = order[i];
// TODO: Maybe we can also resort the rest of the bar in the future?
// var isRequired = search is Configuration.SearchSetting.Internal or Configuration.SearchSetting.MacroLinks;
ImGui.PushFont(UiBuilder.IconFont);
var arrowUpText = $"{FontAwesomeIcon.ArrowUp.ToIconString()}##{title}";
if (i == 0)
{
ImGuiComponents.DisabledButton(arrowUpText);
}
else
{
if (ImGui.Button(arrowUpText))
{
(order[i], order[i - 1]) = (order[i - 1], order[i]);
isOrderChange = true;
}
}
ImGui.SameLine();
var arrowDownText = $"{FontAwesomeIcon.ArrowDown.ToIconString()}##{title}";
if (i == order.Count - 1)
{
ImGuiComponents.DisabledButton(arrowDownText);
}
else
{
if (ImGui.Button(arrowDownText) && i != order.Count - 1)
{
(order[i], order[i + 1]) = (order[i + 1], order[i]);
isOrderChange = true;
}
}
ImGui.PopFont();
ImGui.SameLine();
// if (isRequired) {
// ImGui.TextUnformatted($"Search in {name}");
// } else {
var isShown = ignore.All(x => x != title);
var nextIsShow = isShown;
if (ImGui.Checkbox($"{title}###dtrEntry{i}", ref nextIsShow) && nextIsShow != isShown)
{
if (nextIsShow)
ignore.Remove(title);
else
ignore.Add(title);
dtrBar.MakeDirty(title);
}
// }
}
configuration.DtrOrder = order.Concat(orderLeft).ToList();
configuration.DtrIgnore = ignore.Concat(ignoreLeft).ToList();
if (isOrderChange)
dtrBar.ApplySort();
ImGuiHelpers.ScaledDummy(10);
ImGui.Text(Loc.Localize("DalamudSettingServerInfoBarSpacing", "Server Info Bar spacing"));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarSpacingHint", "Configure the amount of space between entries in the server info bar here."));
ImGui.SliderInt("Spacing", ref this.dtrSpacing, 0, 40);
ImGui.Text(Loc.Localize("DalamudSettingServerInfoBarDirection", "Server Info Bar direction"));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarDirectionHint", "If checked, the Server Info Bar elements will expand to the right instead of the left."));
ImGui.Checkbox("Swap Direction", ref this.dtrSwapDirection);
base.Draw();
}
public override void OnClose()
{
var configuration = Service<DalamudConfiguration>.Get();
configuration.DtrOrder = this.dtrOrder;
configuration.DtrIgnore = this.dtrIgnore;
base.OnClose();
}
public override void Load()
{
var configuration = Service<DalamudConfiguration>.Get();
this.dtrSpacing = configuration.DtrSpacing;
this.dtrSwapDirection = configuration.DtrSwapDirection;
this.dtrOrder = configuration.DtrOrder;
this.dtrIgnore = configuration.DtrIgnore;
base.Load();
}
public override void Save()
{
var configuration = Service<DalamudConfiguration>.Get();
configuration.DtrSpacing = this.dtrSpacing;
configuration.DtrSwapDirection = this.dtrSwapDirection;
this.dtrOrder = configuration.DtrOrder;
this.dtrIgnore = configuration.DtrIgnore;
base.Save();
}
}

View file

@ -0,0 +1,59 @@
using System;
using System.Diagnostics.CodeAnalysis;
using CheapLoc;
using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Internal.Windows.PluginInstaller;
using Dalamud.Interface.Internal.Windows.Settings.Widgets;
using Dalamud.Plugin.Internal;
using Dalamud.Utility;
namespace Dalamud.Interface.Internal.Windows.Settings.Tabs;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public class SettingsTabExperimental : SettingsTab
{
public override SettingsEntry[] Entries { get; } =
{
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingsPluginTest", "Get plugin testing builds"),
string.Format(
Loc.Localize("DalamudSettingsPluginTestHint", "Receive testing prereleases for selected plugins.\nTo opt-in to testing builds for a plugin, you have to right click it in the \"{0}\" tab of the plugin installer and select \"{1}\"."),
PluginCategoryManager.Locs.Group_Installed,
PluginInstallerWindow.Locs.PluginContext_TestingOptIn),
c => c.DoPluginTest,
(v, c) => c.DoPluginTest = v),
new HintSettingsEntry(
Loc.Localize("DalamudSettingsPluginTestWarning", "Testing plugins may not have been vetted before being published. Please only enable this if you are aware of the risks."),
ImGuiColors.DalamudRed),
new GapSettingsEntry(5),
new ButtonSettingsEntry(
Loc.Localize("DalamudSettingsClearHidden", "Clear hidden plugins"),
Loc.Localize("DalamudSettingsClearHiddenHint", "Restore plugins you have previously hidden from the plugin installer."),
() =>
{
Service<DalamudConfiguration>.Get().HiddenPluginInternalName.Clear();
Service<PluginManager>.Get().RefilterPluginMasters();
}),
new GapSettingsEntry(5, true),
new DevPluginsSettingsEntry(),
new GapSettingsEntry(5, true),
new ThirdRepoSettingsEntry(),
};
public override string Title => Loc.Localize("DalamudSettingsExperimental", "Experimental");
public override void Draw()
{
base.Draw();
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, "Total memory used by Dalamud & Plugins: " + Util.FormatBytes(GC.GetTotalMemory(false)));
}
}

View file

@ -0,0 +1,92 @@
using System.Diagnostics.CodeAnalysis;
using CheapLoc;
using Dalamud.Game.Text;
using Dalamud.Interface.Internal.Windows.Settings.Widgets;
namespace Dalamud.Interface.Internal.Windows.Settings.Tabs;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public class SettingsTabGeneral : SettingsTab
{
public override SettingsEntry[] Entries { get; } =
{
new LanguageChooserSettingsEntry(),
new GapSettingsEntry(5),
new SettingsEntry<XivChatType>(
Loc.Localize("DalamudSettingsChannel", "Dalamud Chat Channel"),
Loc.Localize("DalamudSettingsChannelHint", "Select the chat channel that is to be used for general Dalamud messages."),
c => c.GeneralChatType,
(v, c) => c.GeneralChatType = v,
warning: (v) =>
{
// TODO: Maybe actually implement UI for the validity check...
if (v == XivChatType.None)
return Loc.Localize("DalamudSettingsChannelNone", "Do not pick \"None\".");
return null;
}),
new GapSettingsEntry(5),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingsWaitForPluginsOnStartup", "Wait for plugins before game loads"),
Loc.Localize("DalamudSettingsWaitForPluginsOnStartupHint", "Do not let the game load, until plugins are loaded."),
c => c.IsResumeGameAfterPluginLoad,
(v, c) => c.IsResumeGameAfterPluginLoad = v),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingsFlash", "Flash FFXIV window on duty pop"),
Loc.Localize("DalamudSettingsFlashHint", "Flash the FFXIV window in your task bar when a duty is ready."),
c => c.DutyFinderTaskbarFlash,
(v, c) => c.DutyFinderTaskbarFlash = v),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingsDutyFinderMessage", "Chatlog message on duty pop"),
Loc.Localize("DalamudSettingsDutyFinderMessageHint", "Send a message in FFXIV chat when a duty is ready."),
c => c.DutyFinderChatMessage,
(v, c) => c.DutyFinderChatMessage = v),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingsPrintPluginsWelcomeMsg", "Display loaded plugins in the welcome message"),
Loc.Localize("DalamudSettingsPrintPluginsWelcomeMsgHint", "Display loaded plugins in FFXIV chat when logging in with a character."),
c => c.PrintPluginsWelcomeMsg,
(v, c) => c.PrintPluginsWelcomeMsg = v),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingsAutoUpdatePlugins", "Auto-update plugins"),
Loc.Localize("DalamudSettingsAutoUpdatePluginsMsgHint", "Automatically update plugins when logging in with a character."),
c => c.AutoUpdatePlugins,
(v, c) => c.AutoUpdatePlugins = v),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingsSystemMenu", "Dalamud buttons in system menu"),
Loc.Localize("DalamudSettingsSystemMenuMsgHint", "Add buttons for Dalamud plugins and settings to the system menu."),
c => c.DoButtonsSystemMenu,
(v, c) => c.DoButtonsSystemMenu = v),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingsSystemMenu", "Dalamud buttons in system menu"),
Loc.Localize("DalamudSettingsSystemMenuMsgHint", "Add buttons for Dalamud plugins and settings to the system menu."),
c => c.DoButtonsSystemMenu,
(v, c) => c.DoButtonsSystemMenu = v),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingsEnableRmtFiltering", "Enable RMT Filtering"),
Loc.Localize("DalamudSettingsEnableRmtFilteringMsgHint", "Enable Dalamud's built-in RMT ad filtering."),
c => !c.DisableRmtFiltering,
(v, c) => c.DisableRmtFiltering = !v),
new GapSettingsEntry(5),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingDoMbCollect", "Anonymously upload market board data"),
Loc.Localize("DalamudSettingDoMbCollectHint", "Anonymously provide data about in-game economics to Universalis when browsing the market board. This data can't be tied to you in any way and everyone benefits!"),
c => c.IsMbCollect,
(v, c) => c.IsMbCollect = v),
};
public override string Title => Loc.Localize("DalamudSettingsGeneral", "General");
}

View file

@ -0,0 +1,194 @@
using System.Diagnostics.CodeAnalysis;
using CheapLoc;
using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Internal.Windows.Settings.Widgets;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Settings.Tabs;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public class SettingsTabLook : SettingsTab
{
private float globalUiScale;
private float fontGamma;
public override SettingsEntry[] Entries { get; } =
{
new GapSettingsEntry(5),
new ButtonSettingsEntry(
Loc.Localize("DalamudSettingsOpenStyleEditor", "Open Style Editor"),
Loc.Localize("DalamudSettingsStyleEditorHint", "Modify the look & feel of Dalamud windows."),
() => Service<DalamudInterface>.Get().OpenStyleEditor()),
new GapSettingsEntry(5),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingToggleAxisFonts", "Use AXIS fonts as default Dalamud font"),
Loc.Localize("DalamudSettingToggleUiAxisFontsHint", "Use AXIS fonts (the game's main UI fonts) as default Dalamud font."),
c => c.UseAxisFontsFromGame,
(v, c) => c.UseAxisFontsFromGame = v,
v =>
{
var im = Service<InterfaceManager>.Get();
im.UseAxisOverride = v;
im.RebuildFonts();
}),
new GapSettingsEntry(5, true),
new HintSettingsEntry(Loc.Localize("DalamudSettingToggleUiHideOptOutNote", "Plugins may independently opt out of the settings below.")),
new GapSettingsEntry(3),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingToggleUiHide", "Hide plugin UI when the game UI is toggled off"),
Loc.Localize("DalamudSettingToggleUiHideHint", "Hide any open windows by plugins when toggling the game overlay."),
c => c.ToggleUiHide,
(v, c) => c.ToggleUiHide = v),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingToggleUiHideDuringCutscenes", "Hide plugin UI during cutscenes"),
Loc.Localize("DalamudSettingToggleUiHideDuringCutscenesHint", "Hide any open windows by plugins during cutscenes."),
c => c.ToggleUiHideDuringCutscenes,
(v, c) => c.ToggleUiHideDuringCutscenes = v),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingToggleUiHideDuringGpose", "Hide plugin UI while gpose is active"),
Loc.Localize("DalamudSettingToggleUiHideDuringGposeHint", "Hide any open windows by plugins while gpose is active."),
c => c.ToggleUiHideDuringGpose,
(v, c) => c.ToggleUiHideDuringGpose = v),
new GapSettingsEntry(5, true),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingToggleFocusManagement", "Use escape to close Dalamud windows"),
Loc.Localize("DalamudSettingToggleFocusManagementHint", "This will cause Dalamud windows to behave like in-game windows when pressing escape.\nThey will close one after another until all are closed. May not work for all plugins."),
c => c.IsFocusManagementEnabled,
(v, c) => c.IsFocusManagementEnabled = v),
// This is applied every frame in InterfaceManager::CheckViewportState()
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingToggleViewports", "Enable multi-monitor windows"),
Loc.Localize("DalamudSettingToggleViewportsHint", "This will allow you move plugin windows onto other monitors.\nWill only work in Borderless Window or Windowed mode."),
c => !c.IsDisableViewport,
(v, c) => c.IsDisableViewport = !v),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingToggleDocking", "Enable window docking"),
Loc.Localize("DalamudSettingToggleDockingHint", "This will allow you to fuse and tab plugin windows."),
c => c.IsDocking,
(v, c) => c.IsDocking = v),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingToggleGamepadNavigation", "Control plugins via gamepad"),
Loc.Localize("DalamudSettingToggleGamepadNavigationHint", "This will allow you to toggle between game and plugin navigation via L1+L3.\nToggle the PluginInstaller window via R3 if ImGui navigation is enabled."),
c => c.IsGamepadNavigationEnabled,
(v, c) => c.IsGamepadNavigationEnabled = v),
new SettingsEntry<bool>(
Loc.Localize("DalamudSettingToggleTsm", "Show title screen menu"),
Loc.Localize("DalamudSettingToggleTsmHint", "This will allow you to access certain Dalamud and Plugin functionality from the title screen."),
c => c.ShowTsm,
(v, c) => c.ShowTsm = v),
};
public override string Title => Loc.Localize("DalamudSettingsVisual", "Look & Feel");
public override void Draw()
{
var interfaceManager = Service<InterfaceManager>.Get();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3);
ImGui.Text(Loc.Localize("DalamudSettingsGlobalUiScale", "Global Font Scale"));
ImGui.SameLine();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 3);
if (ImGui.Button("9.6pt##DalamudSettingsGlobalUiScaleReset96"))
{
this.globalUiScale = 9.6f / 12.0f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
interfaceManager.RebuildFonts();
}
ImGui.SameLine();
if (ImGui.Button("12pt##DalamudSettingsGlobalUiScaleReset12"))
{
this.globalUiScale = 1.0f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
interfaceManager.RebuildFonts();
}
ImGui.SameLine();
if (ImGui.Button("14pt##DalamudSettingsGlobalUiScaleReset14"))
{
this.globalUiScale = 14.0f / 12.0f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
interfaceManager.RebuildFonts();
}
ImGui.SameLine();
if (ImGui.Button("18pt##DalamudSettingsGlobalUiScaleReset18"))
{
this.globalUiScale = 18.0f / 12.0f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
interfaceManager.RebuildFonts();
}
ImGui.SameLine();
if (ImGui.Button("36pt##DalamudSettingsGlobalUiScaleReset36"))
{
this.globalUiScale = 36.0f / 12.0f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
interfaceManager.RebuildFonts();
}
var globalUiScaleInPt = 12f * this.globalUiScale;
if (ImGui.DragFloat("##DalamudSettingsGlobalUiScaleDrag", ref globalUiScaleInPt, 0.1f, 9.6f, 36f, "%.1fpt", ImGuiSliderFlags.AlwaysClamp))
{
this.globalUiScale = globalUiScaleInPt / 12f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
interfaceManager.RebuildFonts();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsGlobalUiScaleHint", "Scale text in all XIVLauncher UI elements - this is useful for 4K displays."));
ImGuiHelpers.ScaledDummy(5);
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3);
ImGui.Text(Loc.Localize("DalamudSettingsFontGamma", "Font Gamma"));
ImGui.SameLine();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 3);
if (ImGui.Button(Loc.Localize("DalamudSettingsIndividualConfigResetToDefaultValue", "Reset") + "##DalamudSettingsFontGammaReset"))
{
this.fontGamma = 1.4f;
interfaceManager.FontGammaOverride = this.fontGamma;
interfaceManager.RebuildFonts();
}
if (ImGui.DragFloat("##DalamudSettingsFontGammaDrag", ref this.fontGamma, 0.005f, 0.3f, 3f, "%.2f", ImGuiSliderFlags.AlwaysClamp))
{
interfaceManager.FontGammaOverride = this.fontGamma;
interfaceManager.RebuildFonts();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsFontGammaHint", "Changes the thickness of text."));
base.Draw();
}
public override void Load()
{
this.globalUiScale = Service<DalamudConfiguration>.Get().GlobalUiScale;
this.fontGamma = Service<DalamudConfiguration>.Get().FontGammaLevel;
base.Load();
}
public override void Save()
{
Service<DalamudConfiguration>.Get().GlobalUiScale = this.globalUiScale;
base.Save();
}
}

View file

@ -0,0 +1,41 @@
using System;
using System.Diagnostics.CodeAnalysis;
using Dalamud.Interface.Colors;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Settings.Widgets;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public class ButtonSettingsEntry : SettingsEntry
{
private readonly string description;
private readonly Action runs;
public ButtonSettingsEntry(string name, string description, Action runs)
{
this.description = description;
this.runs = runs;
this.Name = name;
}
public override void Load()
{
// ignored
}
public override void Save()
{
// ignored
}
public override void Draw()
{
if (ImGui.Button(this.Name))
{
this.runs.Invoke();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, this.description);
}
}

View file

@ -0,0 +1,184 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using CheapLoc;
using Dalamud.Configuration;
using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Plugin.Internal;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Settings.Widgets;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public class DevPluginsSettingsEntry : SettingsEntry
{
private List<DevPluginLocationSettings> devPluginLocations = new();
private bool devPluginLocationsChanged;
private string devPluginTempLocation = string.Empty;
private string devPluginLocationAddError = string.Empty;
public DevPluginsSettingsEntry()
{
this.Name = Loc.Localize("DalamudSettingsDevPluginLocation", "Dev Plugin Locations");
}
public override void OnClose()
{
this.devPluginLocations =
Service<DalamudConfiguration>.Get().DevPluginLoadLocations.Select(x => x.Clone()).ToList();
}
public override void Load()
{
this.devPluginLocations =
Service<DalamudConfiguration>.Get().DevPluginLoadLocations.Select(x => x.Clone()).ToList();
this.devPluginLocationsChanged = false;
}
public override void Save()
{
Service<DalamudConfiguration>.Get().DevPluginLoadLocations = this.devPluginLocations.Select(x => x.Clone()).ToList();
if (this.devPluginLocationsChanged)
{
Service<PluginManager>.Get().ScanDevPlugins();
this.devPluginLocationsChanged = false;
}
}
public override void Draw()
{
ImGui.Text(this.Name);
if (this.devPluginLocationsChanged)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen);
ImGui.SameLine();
ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)"));
ImGui.PopStyleColor();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsDevPluginLocationsHint", "Add additional dev plugin load locations.\nThese can be either the directory or DLL path."));
ImGuiHelpers.ScaledDummy(5);
ImGui.Columns(4);
ImGui.SetColumnWidth(0, 18 + (5 * ImGuiHelpers.GlobalScale));
ImGui.SetColumnWidth(1, ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale));
ImGui.SetColumnWidth(2, 16 + (45 * ImGuiHelpers.GlobalScale));
ImGui.SetColumnWidth(3, 14 + (26 * ImGuiHelpers.GlobalScale));
ImGui.Separator();
ImGui.Text("#");
ImGui.NextColumn();
ImGui.Text("Path");
ImGui.NextColumn();
ImGui.Text("Enabled");
ImGui.NextColumn();
ImGui.Text(string.Empty);
ImGui.NextColumn();
ImGui.Separator();
DevPluginLocationSettings locationToRemove = null;
var locNumber = 1;
foreach (var devPluginLocationSetting in this.devPluginLocations)
{
var isEnabled = devPluginLocationSetting.IsEnabled;
ImGui.PushID($"devPluginLocation_{devPluginLocationSetting.Path}");
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(locNumber.ToString()).X / 2));
ImGui.Text(locNumber.ToString());
ImGui.NextColumn();
ImGui.SetNextItemWidth(-1);
var path = devPluginLocationSetting.Path;
if (ImGui.InputText($"##devPluginLocationInput", ref path, 65535, ImGuiInputTextFlags.EnterReturnsTrue))
{
var contains = this.devPluginLocations.Select(loc => loc.Path).Contains(path);
if (devPluginLocationSetting.Path == path)
{
// no change.
}
else if (contains && devPluginLocationSetting.Path != path)
{
this.devPluginLocationAddError = Loc.Localize("DalamudDevPluginLocationExists", "Location already exists.");
Task.Delay(5000).ContinueWith(t => this.devPluginLocationAddError = string.Empty);
}
else
{
devPluginLocationSetting.Path = path;
this.devPluginLocationsChanged = path != devPluginLocationSetting.Path;
}
}
ImGui.NextColumn();
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 7 - (12 * ImGuiHelpers.GlobalScale));
ImGui.Checkbox("##devPluginLocationCheck", ref isEnabled);
ImGui.NextColumn();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash))
{
locationToRemove = devPluginLocationSetting;
}
ImGui.PopID();
ImGui.NextColumn();
ImGui.Separator();
devPluginLocationSetting.IsEnabled = isEnabled;
locNumber++;
}
if (locationToRemove != null)
{
this.devPluginLocations.Remove(locationToRemove);
this.devPluginLocationsChanged = true;
}
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(locNumber.ToString()).X / 2));
ImGui.Text(locNumber.ToString());
ImGui.NextColumn();
ImGui.SetNextItemWidth(-1);
ImGui.InputText("##devPluginLocationInput", ref this.devPluginTempLocation, 300);
ImGui.NextColumn();
// Enabled button
ImGui.NextColumn();
if (!string.IsNullOrEmpty(this.devPluginTempLocation) && ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
{
if (this.devPluginLocations.Any(r => string.Equals(r.Path, this.devPluginTempLocation, StringComparison.InvariantCultureIgnoreCase)))
{
this.devPluginLocationAddError = Loc.Localize("DalamudDevPluginLocationExists", "Location already exists.");
Task.Delay(5000).ContinueWith(t => this.devPluginLocationAddError = string.Empty);
}
else
{
this.devPluginLocations.Add(new DevPluginLocationSettings
{
Path = this.devPluginTempLocation.Replace("\"", string.Empty),
IsEnabled = true,
});
this.devPluginLocationsChanged = true;
this.devPluginTempLocation = string.Empty;
}
}
ImGui.Columns(1);
if (!string.IsNullOrEmpty(this.devPluginLocationAddError))
{
ImGuiHelpers.SafeTextColoredWrapped(new Vector4(1, 0, 0, 1), this.devPluginLocationAddError);
}
}
}

View file

@ -0,0 +1,40 @@
using System.Diagnostics.CodeAnalysis;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Settings.Widgets;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public sealed class GapSettingsEntry : SettingsEntry
{
private readonly float size;
private readonly bool hr;
public GapSettingsEntry(float size, bool hr = false)
{
this.size = size;
this.hr = hr;
this.IsValid = true;
}
public override void Load()
{
// ignored
}
public override void Save()
{
// ignored
}
public override void Draw()
{
ImGuiHelpers.ScaledDummy(this.size);
if (this.hr)
{
ImGui.Separator();
ImGuiHelpers.ScaledDummy(this.size);
}
}
}

View file

@ -0,0 +1,34 @@
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using Dalamud.Interface.Colors;
namespace Dalamud.Interface.Internal.Windows.Settings.Widgets;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public class HintSettingsEntry : SettingsEntry
{
private readonly string text;
private readonly Vector4 color;
public HintSettingsEntry(string text, Vector4? color = null)
{
this.text = text;
this.color = color ?? ImGuiColors.DalamudGrey;
}
public override void Load()
{
// ignore
}
public override void Save()
{
// ignore
}
public override void Draw()
{
ImGuiHelpers.SafeTextColoredWrapped(this.color, this.text);
}
}

View file

@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using CheapLoc;
using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Settings.Widgets;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public sealed class LanguageChooserSettingsEntry : SettingsEntry
{
private readonly string[] languages;
private readonly string[] locLanguages;
private int langIndex = -1;
public LanguageChooserSettingsEntry()
{
this.languages = Localization.ApplicableLangCodes.Prepend("en").ToArray();
this.Name = Loc.Localize("DalamudSettingsLanguage", "Language");
this.IsValid = true;
this.IsVisible = true;
try
{
var locLanguagesList = new List<string>();
string locLanguage;
foreach (var language in this.languages)
{
if (language != "ko")
{
locLanguage = CultureInfo.GetCultureInfo(language).NativeName;
locLanguagesList.Add(char.ToUpper(locLanguage[0]) + locLanguage[1..]);
}
else
{
locLanguagesList.Add("Korean");
}
}
this.locLanguages = locLanguagesList.ToArray();
}
catch (Exception)
{
this.locLanguages = this.languages; // Languages not localized, only codes.
}
}
public override void Load()
{
this.langIndex = Array.IndexOf(this.languages, Service<DalamudConfiguration>.Get().EffectiveLanguage);
if (this.langIndex == -1)
this.langIndex = 0;
}
public override void Save()
{
Service<Localization>.Get().SetupWithLangCode(this.languages[this.langIndex]);
Service<DalamudConfiguration>.Get().LanguageOverride = this.languages[this.langIndex];
}
public override void Draw()
{
ImGui.Text(this.Name);
ImGui.Combo("##XlLangCombo", ref this.langIndex, this.locLanguages, this.locLanguages.Length);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsLanguageHint", "Select the language Dalamud will be displayed in."));
}
}

View file

@ -0,0 +1,174 @@
using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors;
using Dalamud.Utility;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Settings.Widgets;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
internal sealed class SettingsEntry<T> : SettingsEntry
{
private readonly LoadSettingDelegate load;
private readonly SaveSettingDelegate save;
private readonly Action<T?>? change;
private object? valueBacking;
public SettingsEntry(string name, string description, LoadSettingDelegate load, SaveSettingDelegate save, Action<T?>? change = null, Func<T?, string?>? warning = null, Func<T?, string?>? validity = null)
{
this.load = load;
this.save = save;
this.change = change;
this.Name = name;
this.Description = description;
this.CheckWarning = warning;
this.CheckValidity = validity;
}
public delegate T? LoadSettingDelegate(DalamudConfiguration config);
public delegate void SaveSettingDelegate(T? value, DalamudConfiguration config);
public T? Value => this.valueBacking == default ? default : (T)this.valueBacking;
public string Description { get; }
public Func<T?, string?>? CheckValidity { get; init; }
public Func<T?, string?>? CheckWarning { get; init; }
public Func<bool>? CheckVisibility { get; init; }
public override bool IsVisible => this.CheckVisibility?.Invoke() ?? true;
public override void Draw()
{
Debug.Assert(this.Name != null, "this.Name != null");
var type = typeof(T);
if (type == typeof(DirectoryInfo))
{
ImGuiHelpers.SafeTextWrapped(this.Name);
var value = this.Value as DirectoryInfo;
var nativeBuffer = value?.FullName ?? string.Empty;
if (ImGui.InputText($"###{this.Id.ToString()}", ref nativeBuffer, 1000))
{
this.valueBacking = !string.IsNullOrEmpty(nativeBuffer) ? new DirectoryInfo(nativeBuffer) : null;
}
}
else if (type == typeof(string))
{
ImGuiHelpers.SafeTextWrapped(this.Name);
var nativeBuffer = this.Value as string ?? string.Empty;
if (ImGui.InputText($"###{this.Id.ToString()}", ref nativeBuffer, 1000))
{
this.valueBacking = nativeBuffer;
}
}
else if (type == typeof(bool))
{
var nativeValue = this.Value as bool? ?? false;
if (ImGui.Checkbox($"{this.Name}###{this.Id.ToString()}", ref nativeValue))
{
this.valueBacking = nativeValue;
this.change?.Invoke(this.Value);
}
}
else if (type.IsEnum)
{
ImGuiHelpers.SafeTextWrapped(this.Name);
var idx = (Enum)(this.valueBacking ?? 0);
var values = Enum.GetValues(type);
var descriptions =
values.Cast<Enum>().ToDictionary(x => x, x => x.GetAttribute<SettingsAnnotationAttribute>() ?? new SettingsAnnotationAttribute(x.ToString(), string.Empty));
if (ImGui.BeginCombo($"###{this.Id.ToString()}", descriptions[idx].FriendlyName))
{
foreach (Enum value in values)
{
if (ImGui.Selectable(descriptions[value].FriendlyName, idx.Equals(value)))
{
this.valueBacking = value;
}
}
ImGui.EndCombo();
}
}
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
ImGuiHelpers.SafeTextWrapped(this.Description);
ImGui.PopStyleColor();
if (this.CheckValidity != null)
{
var validityMsg = this.CheckValidity.Invoke(this.Value);
this.IsValid = string.IsNullOrEmpty(validityMsg);
if (!this.IsValid)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGui.Text(validityMsg);
ImGui.PopStyleColor();
}
}
else
{
this.IsValid = true;
}
var warningMessage = this.CheckWarning?.Invoke(this.Value);
if (warningMessage != null)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudRed);
ImGui.Text(warningMessage);
ImGui.PopStyleColor();
}
}
public override void Load()
{
this.valueBacking = this.load(Service<DalamudConfiguration>.Get());
if (this.CheckValidity != null)
{
this.IsValid = this.CheckValidity(this.Value) == null;
}
else
{
this.IsValid = true;
}
}
public override void Save() => this.save(this.Value, Service<DalamudConfiguration>.Get());
}
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
[AttributeUsage(AttributeTargets.Field)]
internal class SettingsAnnotationAttribute : Attribute
{
public SettingsAnnotationAttribute(string friendlyName, string description)
{
this.FriendlyName = friendlyName;
this.Description = description;
}
public string FriendlyName { get; set; }
public string Description { get; set; }
}

View file

@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using CheapLoc;
using Dalamud.Configuration;
using Dalamud.Configuration.Internal;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Plugin.Internal;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows.Settings.Widgets;
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1600:Elements should be documented", Justification = "Internals")]
public class ThirdRepoSettingsEntry : SettingsEntry
{
private List<ThirdPartyRepoSettings> thirdRepoList = new();
private bool thirdRepoListChanged;
private string thirdRepoTempUrl = string.Empty;
private string thirdRepoAddError = string.Empty;
public override void OnClose()
{
this.thirdRepoList =
Service<DalamudConfiguration>.Get().ThirdRepoList.Select(x => x.Clone()).ToList();
}
public override void Load()
{
this.thirdRepoList =
Service<DalamudConfiguration>.Get().ThirdRepoList.Select(x => x.Clone()).ToList();
this.thirdRepoListChanged = false;
}
public override void Save()
{
Service<DalamudConfiguration>.Get().ThirdRepoList =
this.thirdRepoList.Select(x => x.Clone()).ToList();
if (this.thirdRepoListChanged)
{
_ = Service<PluginManager>.Get().SetPluginReposFromConfigAsync(true);
this.thirdRepoListChanged = false;
}
}
public override void Draw()
{
ImGui.Text(Loc.Localize("DalamudSettingsCustomRepo", "Custom Plugin Repositories"));
if (this.thirdRepoListChanged)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen);
ImGui.SameLine();
ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)"));
ImGui.PopStyleColor();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingCustomRepoHint", "Add custom plugin repositories."));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning", "We cannot take any responsibility for third-party plugins and repositories."));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning2", "Plugins have full control over your PC, like any other program, and may cause harm or crashes."));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning4", "They can delete your character, upload your family photos and burn down your house."));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning3", "Please make absolutely sure that you only install third-party plugins from developers you trust."));
ImGuiHelpers.ScaledDummy(5);
ImGui.Columns(4);
ImGui.SetColumnWidth(0, 18 + (5 * ImGuiHelpers.GlobalScale));
ImGui.SetColumnWidth(1, ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale));
ImGui.SetColumnWidth(2, 16 + (45 * ImGuiHelpers.GlobalScale));
ImGui.SetColumnWidth(3, 14 + (26 * ImGuiHelpers.GlobalScale));
ImGui.Separator();
ImGui.Text("#");
ImGui.NextColumn();
ImGui.Text("URL");
ImGui.NextColumn();
ImGui.Text("Enabled");
ImGui.NextColumn();
ImGui.Text(string.Empty);
ImGui.NextColumn();
ImGui.Separator();
ImGui.Text("0");
ImGui.NextColumn();
ImGui.Text("XIVLauncher");
ImGui.NextColumn();
ImGui.NextColumn();
ImGui.NextColumn();
ImGui.Separator();
ThirdPartyRepoSettings repoToRemove = null;
var repoNumber = 1;
foreach (var thirdRepoSetting in this.thirdRepoList)
{
var isEnabled = thirdRepoSetting.IsEnabled;
ImGui.PushID($"thirdRepo_{thirdRepoSetting.Url}");
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(repoNumber.ToString()).X / 2));
ImGui.Text(repoNumber.ToString());
ImGui.NextColumn();
ImGui.SetNextItemWidth(-1);
var url = thirdRepoSetting.Url;
if (ImGui.InputText($"##thirdRepoInput", ref url, 65535, ImGuiInputTextFlags.EnterReturnsTrue))
{
var contains = this.thirdRepoList.Select(repo => repo.Url).Contains(url);
if (thirdRepoSetting.Url == url)
{
// no change.
}
else if (contains && thirdRepoSetting.Url != url)
{
this.thirdRepoAddError = Loc.Localize("DalamudThirdRepoExists", "Repo already exists.");
Task.Delay(5000).ContinueWith(t => this.thirdRepoAddError = string.Empty);
}
else
{
thirdRepoSetting.Url = url;
this.thirdRepoListChanged = url != thirdRepoSetting.Url;
}
}
ImGui.NextColumn();
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 7 - (12 * ImGuiHelpers.GlobalScale));
ImGui.Checkbox("##thirdRepoCheck", ref isEnabled);
ImGui.NextColumn();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash))
{
repoToRemove = thirdRepoSetting;
}
ImGui.PopID();
ImGui.NextColumn();
ImGui.Separator();
thirdRepoSetting.IsEnabled = isEnabled;
repoNumber++;
}
if (repoToRemove != null)
{
this.thirdRepoList.Remove(repoToRemove);
this.thirdRepoListChanged = true;
}
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(repoNumber.ToString()).X / 2));
ImGui.Text(repoNumber.ToString());
ImGui.NextColumn();
ImGui.SetNextItemWidth(-1);
ImGui.InputText("##thirdRepoUrlInput", ref this.thirdRepoTempUrl, 300);
ImGui.NextColumn();
// Enabled button
ImGui.NextColumn();
if (!string.IsNullOrEmpty(this.thirdRepoTempUrl) && ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
{
this.thirdRepoTempUrl = this.thirdRepoTempUrl.TrimEnd();
if (this.thirdRepoList.Any(r => string.Equals(r.Url, this.thirdRepoTempUrl, StringComparison.InvariantCultureIgnoreCase)))
{
this.thirdRepoAddError = Loc.Localize("DalamudThirdRepoExists", "Repo already exists.");
Task.Delay(5000).ContinueWith(t => this.thirdRepoAddError = string.Empty);
}
else
{
this.thirdRepoList.Add(new ThirdPartyRepoSettings
{
Url = this.thirdRepoTempUrl,
IsEnabled = true,
});
this.thirdRepoListChanged = true;
this.thirdRepoTempUrl = string.Empty;
}
}
ImGui.Columns(1);
if (!string.IsNullOrEmpty(this.thirdRepoAddError))
{
ImGuiHelpers.SafeTextColoredWrapped(new Vector4(1, 0, 0, 1), this.thirdRepoAddError);
}
}
}

View file

@ -1,982 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Numerics;
using System.Threading.Tasks;
using CheapLoc;
using Dalamud.Configuration;
using Dalamud.Configuration.Internal;
using Dalamud.Game.Gui.Dtr;
using Dalamud.Game.Text;
using Dalamud.Interface.Colors;
using Dalamud.Interface.Components;
using Dalamud.Interface.Internal.Windows.PluginInstaller;
using Dalamud.Interface.Windowing;
using Dalamud.Plugin.Internal;
using Dalamud.Utility;
using ImGuiNET;
namespace Dalamud.Interface.Internal.Windows;
/// <summary>
/// The window that allows for general configuration of Dalamud itself.
/// </summary>
internal class SettingsWindow : Window
{
private readonly string[] languages;
private readonly string[] locLanguages;
private int langIndex;
private XivChatType dalamudMessagesChatType;
private bool doWaitForPluginsOnStartup;
private bool doCfTaskBarFlash;
private bool doCfChatMessage;
private bool doMbCollect;
private float globalUiScale;
private bool doUseAxisFontsFromGame;
private float fontGamma;
private bool doToggleUiHide;
private bool doToggleUiHideDuringCutscenes;
private bool doToggleUiHideDuringGpose;
private bool doDocking;
private bool doViewport;
private bool doGamepad;
private bool doFocus;
private bool doTsm;
private List<string>? dtrOrder;
private List<string>? dtrIgnore;
private int dtrSpacing;
private bool dtrSwapDirection;
private int? pluginWaitBeforeFree;
private List<ThirdPartyRepoSettings> thirdRepoList;
private bool thirdRepoListChanged;
private string thirdRepoTempUrl = string.Empty;
private string thirdRepoAddError = string.Empty;
private List<DevPluginLocationSettings> devPluginLocations;
private bool devPluginLocationsChanged;
private string devPluginTempLocation = string.Empty;
private string devPluginLocationAddError = string.Empty;
private bool printPluginsWelcomeMsg;
private bool autoUpdatePlugins;
private bool doButtonsSystemMenu;
private bool disableRmtFiltering;
#region Experimental
private bool doPluginTest;
#endregion
/// <summary>
/// Initializes a new instance of the <see cref="SettingsWindow"/> class.
/// </summary>
public SettingsWindow()
: base(Loc.Localize("DalamudSettingsHeader", "Dalamud Settings") + "###XlSettings2", ImGuiWindowFlags.NoCollapse)
{
var configuration = Service<DalamudConfiguration>.Get();
this.Size = new Vector2(740, 550);
this.SizeCondition = ImGuiCond.FirstUseEver;
this.dalamudMessagesChatType = configuration.GeneralChatType;
this.doWaitForPluginsOnStartup = configuration.IsResumeGameAfterPluginLoad;
this.doCfTaskBarFlash = configuration.DutyFinderTaskbarFlash;
this.doCfChatMessage = configuration.DutyFinderChatMessage;
this.doMbCollect = configuration.IsMbCollect;
this.globalUiScale = configuration.GlobalUiScale;
this.fontGamma = configuration.FontGammaLevel;
this.doUseAxisFontsFromGame = configuration.UseAxisFontsFromGame;
this.doToggleUiHide = configuration.ToggleUiHide;
this.doToggleUiHideDuringCutscenes = configuration.ToggleUiHideDuringCutscenes;
this.doToggleUiHideDuringGpose = configuration.ToggleUiHideDuringGpose;
this.doDocking = configuration.IsDocking;
this.doViewport = !configuration.IsDisableViewport;
this.doGamepad = configuration.IsGamepadNavigationEnabled;
this.doFocus = configuration.IsFocusManagementEnabled;
this.doTsm = configuration.ShowTsm;
this.dtrSpacing = configuration.DtrSpacing;
this.dtrSwapDirection = configuration.DtrSwapDirection;
this.pluginWaitBeforeFree = configuration.PluginWaitBeforeFree;
this.doPluginTest = configuration.DoPluginTest;
this.thirdRepoList = configuration.ThirdRepoList.Select(x => x.Clone()).ToList();
this.devPluginLocations = configuration.DevPluginLoadLocations.Select(x => x.Clone()).ToList();
this.printPluginsWelcomeMsg = configuration.PrintPluginsWelcomeMsg;
this.autoUpdatePlugins = configuration.AutoUpdatePlugins;
this.doButtonsSystemMenu = configuration.DoButtonsSystemMenu;
this.disableRmtFiltering = configuration.DisableRmtFiltering;
this.languages = Localization.ApplicableLangCodes.Prepend("en").ToArray();
this.langIndex = Array.IndexOf(this.languages, configuration.EffectiveLanguage);
if (this.langIndex == -1)
this.langIndex = 0;
try
{
var locLanguagesList = new List<string>();
string locLanguage;
foreach (var language in this.languages)
{
if (language != "ko")
{
locLanguage = CultureInfo.GetCultureInfo(language).NativeName;
locLanguagesList.Add(char.ToUpper(locLanguage[0]) + locLanguage[1..]);
}
else
{
locLanguagesList.Add("Korean");
}
}
this.locLanguages = locLanguagesList.ToArray();
}
catch (Exception)
{
this.locLanguages = this.languages; // Languages not localized, only codes.
}
}
/// <inheritdoc/>
public override void OnOpen()
{
this.thirdRepoListChanged = false;
this.devPluginLocationsChanged = false;
var configuration = Service<DalamudConfiguration>.Get();
this.dtrOrder = configuration.DtrOrder;
this.dtrIgnore = configuration.DtrIgnore;
}
/// <inheritdoc/>
public override void OnClose()
{
var configuration = Service<DalamudConfiguration>.Get();
var interfaceManager = Service<InterfaceManager>.Get();
var rebuildFont = ImGui.GetIO().FontGlobalScale != configuration.GlobalUiScale
|| interfaceManager.FontGamma != configuration.FontGammaLevel
|| interfaceManager.UseAxis != configuration.UseAxisFontsFromGame;
ImGui.GetIO().FontGlobalScale = configuration.GlobalUiScale;
interfaceManager.FontGammaOverride = null;
interfaceManager.UseAxisOverride = null;
this.thirdRepoList = configuration.ThirdRepoList.Select(x => x.Clone()).ToList();
this.devPluginLocations = configuration.DevPluginLoadLocations.Select(x => x.Clone()).ToList();
configuration.DtrOrder = this.dtrOrder;
configuration.DtrIgnore = this.dtrIgnore;
if (rebuildFont)
interfaceManager.RebuildFonts();
}
/// <inheritdoc/>
public override void Draw()
{
var windowSize = ImGui.GetWindowSize();
ImGui.BeginChild("scrolling", new Vector2(windowSize.X - 5 - (5 * ImGuiHelpers.GlobalScale), windowSize.Y - 35 - (35 * ImGuiHelpers.GlobalScale)), false);
if (ImGui.BeginTabBar("SetTabBar"))
{
if (ImGui.BeginTabItem(Loc.Localize("DalamudSettingsGeneral", "General") + "###settingsTabGeneral"))
{
this.DrawGeneralTab();
ImGui.EndTabItem();
}
if (ImGui.BeginTabItem(Loc.Localize("DalamudSettingsVisual", "Look & Feel") + "###settingsTabVisual"))
{
this.DrawLookAndFeelTab();
ImGui.EndTabItem();
}
if (ImGui.BeginTabItem(Loc.Localize("DalamudSettingsServerInfoBar", "Server Info Bar") + "###settingsTabInfoBar"))
{
this.DrawServerInfoBarTab();
ImGui.EndTabItem();
}
if (ImGui.BeginTabItem(Loc.Localize("DalamudSettingsExperimental", "Experimental") + "###settingsTabExperimental"))
{
this.DrawExperimentalTab();
ImGui.EndTabItem();
}
ImGui.EndTabBar();
}
ImGui.EndChild();
this.DrawSaveCloseButtons();
}
private void DrawGeneralTab()
{
ImGui.Text(Loc.Localize("DalamudSettingsLanguage", "Language"));
ImGui.Combo("##XlLangCombo", ref this.langIndex, this.locLanguages, this.locLanguages.Length);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsLanguageHint", "Select the language Dalamud will be displayed in."));
ImGuiHelpers.ScaledDummy(5);
ImGui.Text(Loc.Localize("DalamudSettingsChannel", "General Chat Channel"));
if (ImGui.BeginCombo("##XlChatTypeCombo", this.dalamudMessagesChatType.ToString()))
{
foreach (var type in Enum.GetValues(typeof(XivChatType)).Cast<XivChatType>())
{
if (ImGui.Selectable(type.ToString(), type == this.dalamudMessagesChatType))
{
this.dalamudMessagesChatType = type;
}
}
ImGui.EndCombo();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsChannelHint", "Select the chat channel that is to be used for general Dalamud messages."));
ImGuiHelpers.ScaledDummy(5);
ImGui.Checkbox(Loc.Localize("DalamudSettingsWaitForPluginsOnStartup", "Wait for plugins before game loads"), ref this.doWaitForPluginsOnStartup);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsWaitForPluginsOnStartupHint", "Do not let the game load, until plugins are loaded."));
ImGui.Checkbox(Loc.Localize("DalamudSettingsFlash", "Flash FFXIV window on duty pop"), ref this.doCfTaskBarFlash);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsFlashHint", "Flash the FFXIV window in your task bar when a duty is ready."));
ImGui.Checkbox(Loc.Localize("DalamudSettingsDutyFinderMessage", "Chatlog message on duty pop"), ref this.doCfChatMessage);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsDutyFinderMessageHint", "Send a message in FFXIV chat when a duty is ready."));
ImGui.Checkbox(Loc.Localize("DalamudSettingsPrintPluginsWelcomeMsg", "Display loaded plugins in the welcome message"), ref this.printPluginsWelcomeMsg);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsPrintPluginsWelcomeMsgHint", "Display loaded plugins in FFXIV chat when logging in with a character."));
ImGui.Checkbox(Loc.Localize("DalamudSettingsAutoUpdatePlugins", "Auto-update plugins"), ref this.autoUpdatePlugins);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsAutoUpdatePluginsMsgHint", "Automatically update plugins when logging in with a character."));
ImGui.Checkbox(Loc.Localize("DalamudSettingsSystemMenu", "Dalamud buttons in system menu"), ref this.doButtonsSystemMenu);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsSystemMenuMsgHint", "Add buttons for Dalamud plugins and settings to the system menu."));
ImGui.Checkbox(Loc.Localize("DalamudSettingsDisableRmtFiltering", "Disable RMT Filtering"), ref this.disableRmtFiltering);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsDisableRmtFilteringMsgHint", "Disable Dalamud's built-in RMT ad filtering."));
ImGuiHelpers.ScaledDummy(5);
ImGui.Checkbox(Loc.Localize("DalamudSettingDoMbCollect", "Anonymously upload market board data"), ref this.doMbCollect);
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.DalamudGrey);
ImGui.TextWrapped(Loc.Localize("DalamudSettingDoMbCollectHint", "Anonymously provide data about in-game economics to Universalis when browsing the market board. This data can't be tied to you in any way and everyone benefits!"));
ImGui.PopStyleColor();
}
private void DrawLookAndFeelTab()
{
var interfaceManager = Service<InterfaceManager>.Get();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3);
ImGui.Text(Loc.Localize("DalamudSettingsGlobalUiScale", "Global Font Scale"));
ImGui.SameLine();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 3);
if (ImGui.Button("9.6pt##DalamudSettingsGlobalUiScaleReset96"))
{
this.globalUiScale = 9.6f / 12.0f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
interfaceManager.RebuildFonts();
}
ImGui.SameLine();
if (ImGui.Button("12pt##DalamudSettingsGlobalUiScaleReset12"))
{
this.globalUiScale = 1.0f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
interfaceManager.RebuildFonts();
}
ImGui.SameLine();
if (ImGui.Button("14pt##DalamudSettingsGlobalUiScaleReset14"))
{
this.globalUiScale = 14.0f / 12.0f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
interfaceManager.RebuildFonts();
}
ImGui.SameLine();
if (ImGui.Button("18pt##DalamudSettingsGlobalUiScaleReset18"))
{
this.globalUiScale = 18.0f / 12.0f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
interfaceManager.RebuildFonts();
}
ImGui.SameLine();
if (ImGui.Button("36pt##DalamudSettingsGlobalUiScaleReset36"))
{
this.globalUiScale = 36.0f / 12.0f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
interfaceManager.RebuildFonts();
}
var globalUiScaleInPt = 12f * this.globalUiScale;
if (ImGui.DragFloat("##DalamudSettingsGlobalUiScaleDrag", ref globalUiScaleInPt, 0.1f, 9.6f, 36f, "%.1fpt", ImGuiSliderFlags.AlwaysClamp))
{
this.globalUiScale = globalUiScaleInPt / 12f;
ImGui.GetIO().FontGlobalScale = this.globalUiScale;
interfaceManager.RebuildFonts();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsGlobalUiScaleHint", "Scale text in all XIVLauncher UI elements - this is useful for 4K displays."));
ImGuiHelpers.ScaledDummy(10, 16);
if (ImGui.Button(Loc.Localize("DalamudSettingsOpenStyleEditor", "Open Style Editor")))
{
Service<DalamudInterface>.Get().OpenStyleEditor();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsStyleEditorHint", "Modify the look & feel of Dalamud windows."));
ImGuiHelpers.ScaledDummy(10);
if (ImGui.Checkbox(Loc.Localize("DalamudSettingToggleAxisFonts", "Use AXIS fonts as default Dalamud font"), ref this.doUseAxisFontsFromGame))
{
interfaceManager.UseAxisOverride = this.doUseAxisFontsFromGame;
interfaceManager.RebuildFonts();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiAxisFontsHint", "Use AXIS fonts (the game's main UI fonts) as default Dalamud font."));
ImGuiHelpers.ScaledDummy(10);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiHideOptOutNote", "Plugins may independently opt out of the settings below."));
ImGuiHelpers.ScaledDummy(3);
ImGui.Checkbox(Loc.Localize("DalamudSettingToggleUiHide", "Hide plugin UI when the game UI is toggled off"), ref this.doToggleUiHide);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiHideHint", "Hide any open windows by plugins when toggling the game overlay."));
ImGui.Checkbox(Loc.Localize("DalamudSettingToggleUiHideDuringCutscenes", "Hide plugin UI during cutscenes"), ref this.doToggleUiHideDuringCutscenes);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiHideDuringCutscenesHint", "Hide any open windows by plugins during cutscenes."));
ImGui.Checkbox(Loc.Localize("DalamudSettingToggleUiHideDuringGpose", "Hide plugin UI while gpose is active"), ref this.doToggleUiHideDuringGpose);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleUiHideDuringGposeHint", "Hide any open windows by plugins while gpose is active."));
ImGuiHelpers.ScaledDummy(10, 16);
ImGui.Checkbox(Loc.Localize("DalamudSettingToggleFocusManagement", "Use escape to close Dalamud windows"), ref this.doFocus);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleFocusManagementHint", "This will cause Dalamud windows to behave like in-game windows when pressing escape.\nThey will close one after another until all are closed. May not work for all plugins."));
ImGui.Checkbox(Loc.Localize("DalamudSettingToggleViewports", "Enable multi-monitor windows"), ref this.doViewport);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleViewportsHint", "This will allow you move plugin windows onto other monitors.\nWill only work in Borderless Window or Windowed mode."));
ImGui.Checkbox(Loc.Localize("DalamudSettingToggleDocking", "Enable window docking"), ref this.doDocking);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleDockingHint", "This will allow you to fuse and tab plugin windows."));
ImGui.Checkbox(Loc.Localize("DalamudSettingToggleGamepadNavigation", "Control plugins via gamepad"), ref this.doGamepad);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleGamepadNavigationHint", "This will allow you to toggle between game and plugin navigation via L1+L3.\nToggle the PluginInstaller window via R3 if ImGui navigation is enabled."));
ImGui.Checkbox(Loc.Localize("DalamudSettingToggleTsm", "Show title screen menu"), ref this.doTsm);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingToggleTsmHint", "This will allow you to access certain Dalamud and Plugin functionality from the title screen."));
ImGuiHelpers.ScaledDummy(10, 16);
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 3);
ImGui.Text(Loc.Localize("DalamudSettingsFontGamma", "Font Gamma"));
ImGui.SameLine();
ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 3);
if (ImGui.Button(Loc.Localize("DalamudSettingsIndividualConfigResetToDefaultValue", "Reset") + "##DalamudSettingsFontGammaReset"))
{
this.fontGamma = 1.4f;
interfaceManager.FontGammaOverride = this.fontGamma;
interfaceManager.RebuildFonts();
}
if (ImGui.DragFloat("##DalamudSettingsFontGammaDrag", ref this.fontGamma, 0.005f, 0.3f, 3f, "%.2f", ImGuiSliderFlags.AlwaysClamp))
{
interfaceManager.FontGammaOverride = this.fontGamma;
interfaceManager.RebuildFonts();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsFontGammaHint", "Changes the thickness of text."));
ImGuiHelpers.ScaledDummy(10, 16);
}
private void DrawServerInfoBarTab()
{
ImGui.Text(Loc.Localize("DalamudSettingServerInfoBar", "Server Info Bar configuration"));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarHint", "Plugins can put additional information into your server information bar(where world & time can be seen).\nYou can reorder and disable these here."));
ImGuiHelpers.ScaledDummy(10);
var configuration = Service<DalamudConfiguration>.Get();
var dtrBar = Service<DtrBar>.Get();
var order = configuration.DtrOrder!.Where(x => dtrBar.HasEntry(x)).ToList();
var ignore = configuration.DtrIgnore!.Where(x => dtrBar.HasEntry(x)).ToList();
var orderLeft = configuration.DtrOrder!.Where(x => !order.Contains(x)).ToList();
var ignoreLeft = configuration.DtrIgnore!.Where(x => !ignore.Contains(x)).ToList();
if (order.Count == 0)
{
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarDidNone", "You have no plugins that use this feature."));
}
var isOrderChange = false;
for (var i = 0; i < order.Count; i++)
{
var title = order[i];
// TODO: Maybe we can also resort the rest of the bar in the future?
// var isRequired = search is Configuration.SearchSetting.Internal or Configuration.SearchSetting.MacroLinks;
ImGui.PushFont(UiBuilder.IconFont);
var arrowUpText = $"{FontAwesomeIcon.ArrowUp.ToIconString()}##{title}";
if (i == 0)
{
ImGuiComponents.DisabledButton(arrowUpText);
}
else
{
if (ImGui.Button(arrowUpText))
{
(order[i], order[i - 1]) = (order[i - 1], order[i]);
isOrderChange = true;
}
}
ImGui.SameLine();
var arrowDownText = $"{FontAwesomeIcon.ArrowDown.ToIconString()}##{title}";
if (i == order.Count - 1)
{
ImGuiComponents.DisabledButton(arrowDownText);
}
else
{
if (ImGui.Button(arrowDownText) && i != order.Count - 1)
{
(order[i], order[i + 1]) = (order[i + 1], order[i]);
isOrderChange = true;
}
}
ImGui.PopFont();
ImGui.SameLine();
// if (isRequired) {
// ImGui.TextUnformatted($"Search in {name}");
// } else {
var isShown = ignore.All(x => x != title);
var nextIsShow = isShown;
if (ImGui.Checkbox($"{title}###dtrEntry{i}", ref nextIsShow) && nextIsShow != isShown)
{
if (nextIsShow)
ignore.Remove(title);
else
ignore.Add(title);
dtrBar.MakeDirty(title);
}
// }
}
configuration.DtrOrder = order.Concat(orderLeft).ToList();
configuration.DtrIgnore = ignore.Concat(ignoreLeft).ToList();
if (isOrderChange)
dtrBar.ApplySort();
ImGuiHelpers.ScaledDummy(10);
ImGui.Text(Loc.Localize("DalamudSettingServerInfoBarSpacing", "Server Info Bar spacing"));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarSpacingHint", "Configure the amount of space between entries in the server info bar here."));
ImGui.SliderInt("Spacing", ref this.dtrSpacing, 0, 40);
ImGui.Text(Loc.Localize("DalamudSettingServerInfoBarDirection", "Server Info Bar direction"));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingServerInfoBarDirectionHint", "If checked, the Server Info Bar elements will expand to the right instead of the left."));
ImGui.Checkbox("Swap Direction", ref this.dtrSwapDirection);
}
private void DrawExperimentalTab()
{
var configuration = Service<DalamudConfiguration>.Get();
var pluginManager = Service<PluginManager>.Get();
var useCustomPluginWaitBeforeFree = this.pluginWaitBeforeFree.HasValue;
if (ImGui.Checkbox(
Loc.Localize("DalamudSettingsPluginCustomizeWaitTime", "Customize wait time for plugin unload"),
ref useCustomPluginWaitBeforeFree))
{
if (!useCustomPluginWaitBeforeFree)
this.pluginWaitBeforeFree = null;
else
this.pluginWaitBeforeFree = PluginManager.PluginWaitBeforeFreeDefault;
}
if (useCustomPluginWaitBeforeFree)
{
var waitTime = this.pluginWaitBeforeFree ?? PluginManager.PluginWaitBeforeFreeDefault;
if (ImGui.SliderInt(
"Wait time###DalamudSettingsPluginCustomizeWaitTimeSlider",
ref waitTime,
0,
5000))
{
this.pluginWaitBeforeFree = waitTime;
}
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsPluginCustomizeWaitTimeHint", "Configure the wait time between stopping plugin and completely unloading plugin. If you are experiencing crashes when exiting the game, try increasing this value."));
ImGuiHelpers.ScaledDummy(12);
#region Plugin testing
ImGui.Checkbox(Loc.Localize("DalamudSettingsPluginTest", "Get plugin testing builds"), ref this.doPluginTest);
ImGuiHelpers.SafeTextColoredWrapped(
ImGuiColors.DalamudGrey,
string.Format(
Loc.Localize("DalamudSettingsPluginTestHint", "Receive testing prereleases for selected plugins.\nTo opt-in to testing builds for a plugin, you have to right click it in the \"{0}\" tab of the plugin installer and select \"{1}\"."),
PluginCategoryManager.Locs.Group_Installed,
PluginInstallerWindow.Locs.PluginContext_TestingOptIn));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingsPluginTestWarning", "Testing plugins may not have been vetted before being published. Please only enable this if you are aware of the risks."));
#endregion
ImGuiHelpers.ScaledDummy(12);
#region Hidden plugins
if (ImGui.Button(Loc.Localize("DalamudSettingsClearHidden", "Clear hidden plugins")))
{
configuration.HiddenPluginInternalName.Clear();
pluginManager.RefilterPluginMasters();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsClearHiddenHint", "Restore plugins you have previously hidden from the plugin installer."));
#endregion
ImGuiHelpers.ScaledDummy(12);
this.DrawCustomReposSection();
ImGuiHelpers.ScaledDummy(12);
this.DrawDevPluginLocationsSection();
ImGuiHelpers.ScaledDummy(12);
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, "Total memory used by Dalamud & Plugins: " + Util.FormatBytes(GC.GetTotalMemory(false)));
}
private void DrawCustomReposSection()
{
ImGui.Text(Loc.Localize("DalamudSettingsCustomRepo", "Custom Plugin Repositories"));
if (this.thirdRepoListChanged)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen);
ImGui.SameLine();
ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)"));
ImGui.PopStyleColor();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingCustomRepoHint", "Add custom plugin repositories."));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning", "We cannot take any responsibility for third-party plugins and repositories."));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning2", "Plugins have full control over your PC, like any other program, and may cause harm or crashes."));
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudRed, Loc.Localize("DalamudSettingCustomRepoWarning3", "Please make absolutely sure that you only install third-party plugins from developers you trust."));
ImGuiHelpers.ScaledDummy(5);
ImGui.Columns(4);
ImGui.SetColumnWidth(0, 18 + (5 * ImGuiHelpers.GlobalScale));
ImGui.SetColumnWidth(1, ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale));
ImGui.SetColumnWidth(2, 16 + (45 * ImGuiHelpers.GlobalScale));
ImGui.SetColumnWidth(3, 14 + (26 * ImGuiHelpers.GlobalScale));
ImGui.Separator();
ImGui.Text("#");
ImGui.NextColumn();
ImGui.Text("URL");
ImGui.NextColumn();
ImGui.Text("Enabled");
ImGui.NextColumn();
ImGui.Text(string.Empty);
ImGui.NextColumn();
ImGui.Separator();
ImGui.Text("0");
ImGui.NextColumn();
ImGui.Text("XIVLauncher");
ImGui.NextColumn();
ImGui.NextColumn();
ImGui.NextColumn();
ImGui.Separator();
ThirdPartyRepoSettings repoToRemove = null;
var repoNumber = 1;
foreach (var thirdRepoSetting in this.thirdRepoList)
{
var isEnabled = thirdRepoSetting.IsEnabled;
ImGui.PushID($"thirdRepo_{thirdRepoSetting.Url}");
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(repoNumber.ToString()).X / 2));
ImGui.Text(repoNumber.ToString());
ImGui.NextColumn();
ImGui.SetNextItemWidth(-1);
var url = thirdRepoSetting.Url;
if (ImGui.InputText($"##thirdRepoInput", ref url, 65535, ImGuiInputTextFlags.EnterReturnsTrue))
{
var contains = this.thirdRepoList.Select(repo => repo.Url).Contains(url);
if (thirdRepoSetting.Url == url)
{
// no change.
}
else if (contains && thirdRepoSetting.Url != url)
{
this.thirdRepoAddError = Loc.Localize("DalamudThirdRepoExists", "Repo already exists.");
Task.Delay(5000).ContinueWith(t => this.thirdRepoAddError = string.Empty);
}
else
{
thirdRepoSetting.Url = url;
this.thirdRepoListChanged = url != thirdRepoSetting.Url;
}
}
ImGui.NextColumn();
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 7 - (12 * ImGuiHelpers.GlobalScale));
ImGui.Checkbox("##thirdRepoCheck", ref isEnabled);
ImGui.NextColumn();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash))
{
repoToRemove = thirdRepoSetting;
}
ImGui.PopID();
ImGui.NextColumn();
ImGui.Separator();
thirdRepoSetting.IsEnabled = isEnabled;
repoNumber++;
}
if (repoToRemove != null)
{
this.thirdRepoList.Remove(repoToRemove);
this.thirdRepoListChanged = true;
}
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(repoNumber.ToString()).X / 2));
ImGui.Text(repoNumber.ToString());
ImGui.NextColumn();
ImGui.SetNextItemWidth(-1);
ImGui.InputText("##thirdRepoUrlInput", ref this.thirdRepoTempUrl, 300);
ImGui.NextColumn();
// Enabled button
ImGui.NextColumn();
if (!string.IsNullOrEmpty(this.thirdRepoTempUrl) && ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
{
this.thirdRepoTempUrl = this.thirdRepoTempUrl.TrimEnd();
if (this.thirdRepoList.Any(r => string.Equals(r.Url, this.thirdRepoTempUrl, StringComparison.InvariantCultureIgnoreCase)))
{
this.thirdRepoAddError = Loc.Localize("DalamudThirdRepoExists", "Repo already exists.");
Task.Delay(5000).ContinueWith(t => this.thirdRepoAddError = string.Empty);
}
else
{
this.thirdRepoList.Add(new ThirdPartyRepoSettings
{
Url = this.thirdRepoTempUrl,
IsEnabled = true,
});
this.thirdRepoListChanged = true;
this.thirdRepoTempUrl = string.Empty;
}
}
ImGui.Columns(1);
if (!string.IsNullOrEmpty(this.thirdRepoAddError))
{
ImGuiHelpers.SafeTextColoredWrapped(new Vector4(1, 0, 0, 1), this.thirdRepoAddError);
}
}
private void DrawDevPluginLocationsSection()
{
ImGui.Text(Loc.Localize("DalamudSettingsDevPluginLocation", "Dev Plugin Locations"));
if (this.devPluginLocationsChanged)
{
ImGui.PushStyleColor(ImGuiCol.Text, ImGuiColors.HealerGreen);
ImGui.SameLine();
ImGui.Text(Loc.Localize("DalamudSettingsChanged", "(Changed)"));
ImGui.PopStyleColor();
}
ImGuiHelpers.SafeTextColoredWrapped(ImGuiColors.DalamudGrey, Loc.Localize("DalamudSettingsDevPluginLocationsHint", "Add additional dev plugin load locations.\nThese can be either the directory or DLL path."));
ImGuiHelpers.ScaledDummy(5);
ImGui.Columns(4);
ImGui.SetColumnWidth(0, 18 + (5 * ImGuiHelpers.GlobalScale));
ImGui.SetColumnWidth(1, ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X - (18 + 16 + 14) - ((5 + 45 + 26) * ImGuiHelpers.GlobalScale));
ImGui.SetColumnWidth(2, 16 + (45 * ImGuiHelpers.GlobalScale));
ImGui.SetColumnWidth(3, 14 + (26 * ImGuiHelpers.GlobalScale));
ImGui.Separator();
ImGui.Text("#");
ImGui.NextColumn();
ImGui.Text("Path");
ImGui.NextColumn();
ImGui.Text("Enabled");
ImGui.NextColumn();
ImGui.Text(string.Empty);
ImGui.NextColumn();
ImGui.Separator();
DevPluginLocationSettings locationToRemove = null;
var locNumber = 1;
foreach (var devPluginLocationSetting in this.devPluginLocations)
{
var isEnabled = devPluginLocationSetting.IsEnabled;
ImGui.PushID($"devPluginLocation_{devPluginLocationSetting.Path}");
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(locNumber.ToString()).X / 2));
ImGui.Text(locNumber.ToString());
ImGui.NextColumn();
ImGui.SetNextItemWidth(-1);
var path = devPluginLocationSetting.Path;
if (ImGui.InputText($"##devPluginLocationInput", ref path, 65535, ImGuiInputTextFlags.EnterReturnsTrue))
{
var contains = this.devPluginLocations.Select(loc => loc.Path).Contains(path);
if (devPluginLocationSetting.Path == path)
{
// no change.
}
else if (contains && devPluginLocationSetting.Path != path)
{
this.devPluginLocationAddError = Loc.Localize("DalamudDevPluginLocationExists", "Location already exists.");
Task.Delay(5000).ContinueWith(t => this.devPluginLocationAddError = string.Empty);
}
else
{
devPluginLocationSetting.Path = path;
this.devPluginLocationsChanged = path != devPluginLocationSetting.Path;
}
}
ImGui.NextColumn();
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 7 - (12 * ImGuiHelpers.GlobalScale));
ImGui.Checkbox("##devPluginLocationCheck", ref isEnabled);
ImGui.NextColumn();
if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash))
{
locationToRemove = devPluginLocationSetting;
}
ImGui.PopID();
ImGui.NextColumn();
ImGui.Separator();
devPluginLocationSetting.IsEnabled = isEnabled;
locNumber++;
}
if (locationToRemove != null)
{
this.devPluginLocations.Remove(locationToRemove);
this.devPluginLocationsChanged = true;
}
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + (ImGui.GetColumnWidth() / 2) - 8 - (ImGui.CalcTextSize(locNumber.ToString()).X / 2));
ImGui.Text(locNumber.ToString());
ImGui.NextColumn();
ImGui.SetNextItemWidth(-1);
ImGui.InputText("##devPluginLocationInput", ref this.devPluginTempLocation, 300);
ImGui.NextColumn();
// Enabled button
ImGui.NextColumn();
if (!string.IsNullOrEmpty(this.devPluginTempLocation) && ImGuiComponents.IconButton(FontAwesomeIcon.Plus))
{
if (this.devPluginLocations.Any(r => string.Equals(r.Path, this.devPluginTempLocation, StringComparison.InvariantCultureIgnoreCase)))
{
this.devPluginLocationAddError = Loc.Localize("DalamudDevPluginLocationExists", "Location already exists.");
Task.Delay(5000).ContinueWith(t => this.devPluginLocationAddError = string.Empty);
}
else
{
this.devPluginLocations.Add(new DevPluginLocationSettings
{
Path = this.devPluginTempLocation.Replace("\"", string.Empty),
IsEnabled = true,
});
this.devPluginLocationsChanged = true;
this.devPluginTempLocation = string.Empty;
}
}
ImGui.Columns(1);
if (!string.IsNullOrEmpty(this.devPluginLocationAddError))
{
ImGuiHelpers.SafeTextColoredWrapped(new Vector4(1, 0, 0, 1), this.devPluginLocationAddError);
}
}
private void DrawSaveCloseButtons()
{
var buttonSave = false;
var buttonClose = false;
var pluginManager = Service<PluginManager>.Get();
if (ImGui.Button(Loc.Localize("Save", "Save")))
buttonSave = true;
ImGui.SameLine();
if (ImGui.Button(Loc.Localize("Close", "Close")))
buttonClose = true;
ImGui.SameLine();
if (ImGui.Button(Loc.Localize("SaveAndClose", "Save and Close")))
buttonSave = buttonClose = true;
if (buttonSave)
{
this.Save();
if (this.thirdRepoListChanged)
{
_ = pluginManager.SetPluginReposFromConfigAsync(true);
this.thirdRepoListChanged = false;
}
if (this.devPluginLocationsChanged)
{
pluginManager.ScanDevPlugins();
this.devPluginLocationsChanged = false;
}
}
if (buttonClose)
{
this.IsOpen = false;
}
}
private void Save()
{
var configuration = Service<DalamudConfiguration>.Get();
var localization = Service<Localization>.Get();
localization.SetupWithLangCode(this.languages[this.langIndex]);
configuration.LanguageOverride = this.languages[this.langIndex];
configuration.GeneralChatType = this.dalamudMessagesChatType;
configuration.IsResumeGameAfterPluginLoad = this.doWaitForPluginsOnStartup;
configuration.DutyFinderTaskbarFlash = this.doCfTaskBarFlash;
configuration.DutyFinderChatMessage = this.doCfChatMessage;
configuration.IsMbCollect = this.doMbCollect;
configuration.GlobalUiScale = this.globalUiScale;
configuration.ToggleUiHide = this.doToggleUiHide;
configuration.ToggleUiHideDuringCutscenes = this.doToggleUiHideDuringCutscenes;
configuration.ToggleUiHideDuringGpose = this.doToggleUiHideDuringGpose;
configuration.IsDocking = this.doDocking;
configuration.IsGamepadNavigationEnabled = this.doGamepad;
configuration.IsFocusManagementEnabled = this.doFocus;
configuration.ShowTsm = this.doTsm;
configuration.UseAxisFontsFromGame = this.doUseAxisFontsFromGame;
configuration.FontGammaLevel = this.fontGamma;
// This is applied every frame in InterfaceManager::CheckViewportState()
configuration.IsDisableViewport = !this.doViewport;
// Apply docking flag
if (!configuration.IsDocking)
{
ImGui.GetIO().ConfigFlags &= ~ImGuiConfigFlags.DockingEnable;
}
else
{
ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.DockingEnable;
}
// NOTE (Chiv) Toggle gamepad navigation via setting
if (!configuration.IsGamepadNavigationEnabled)
{
ImGui.GetIO().BackendFlags &= ~ImGuiBackendFlags.HasGamepad;
ImGui.GetIO().ConfigFlags &= ~ImGuiConfigFlags.NavEnableSetMousePos;
var di = Service<DalamudInterface>.Get();
di.CloseGamepadModeNotifierWindow();
}
else
{
ImGui.GetIO().BackendFlags |= ImGuiBackendFlags.HasGamepad;
ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.NavEnableSetMousePos;
}
this.dtrOrder = configuration.DtrOrder;
this.dtrIgnore = configuration.DtrIgnore;
configuration.DtrSpacing = this.dtrSpacing;
configuration.DtrSwapDirection = this.dtrSwapDirection;
configuration.PluginWaitBeforeFree = this.pluginWaitBeforeFree;
configuration.DoPluginTest = this.doPluginTest;
configuration.ThirdRepoList = this.thirdRepoList.Select(x => x.Clone()).ToList();
configuration.DevPluginLoadLocations = this.devPluginLocations.Select(x => x.Clone()).ToList();
configuration.PrintPluginsWelcomeMsg = this.printPluginsWelcomeMsg;
configuration.AutoUpdatePlugins = this.autoUpdatePlugins;
configuration.DoButtonsSystemMenu = this.doButtonsSystemMenu;
configuration.DisableRmtFiltering = this.disableRmtFiltering;
configuration.QueueSave();
_ = Service<PluginManager>.Get().ReloadPluginMastersAsync();
Service<InterfaceManager>.Get().RebuildFonts();
}
}

View file

@ -43,7 +43,7 @@ internal partial class PluginManager : IDisposable, IServiceType
/// <summary>
/// Default time to wait between plugin unload and plugin assembly unload.
/// </summary>
public const int PluginWaitBeforeFreeDefault = 500;
public const int PluginWaitBeforeFreeDefault = 1000; // upped from 500ms, seems more stable
private const string DevPluginsDisclaimerFilename = "DONT_USE_THIS_FOLDER.txt";

View file

@ -14,12 +14,15 @@ public static class EnumExtensions
/// <typeparam name="TAttribute">The type of attribute to get.</typeparam>
/// <param name="value">The enum value that has an attached attribute.</param>
/// <returns>The attached attribute, if any.</returns>
public static TAttribute GetAttribute<TAttribute>(this Enum value)
public static TAttribute? GetAttribute<TAttribute>(this Enum value)
where TAttribute : Attribute
{
var type = value.GetType();
var name = Enum.GetName(type, value);
return type.GetField(name) // I prefer to get attributes this way
if (name.IsNullOrEmpty())
return null;
return type.GetField(name)?
.GetCustomAttributes(false)
.OfType<TAttribute>()
.SingleOrDefault();