diff --git a/Dalamud/Game/Gui/GameGui.cs b/Dalamud/Game/Gui/GameGui.cs index 6b9be88b4..18f59c75a 100644 --- a/Dalamud/Game/Gui/GameGui.cs +++ b/Dalamud/Game/Gui/GameGui.cs @@ -363,7 +363,7 @@ public sealed unsafe class GameGui : IDisposable, IServiceType /// /// The addon address. /// A pointer to the agent interface. - 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(); } + /// + /// Indicates if the game is on the title screen. + /// + /// A value indicating whether or not the game is on the title screen. + 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.Get().IsLoggedIn; + } + /// /// Set the current background music. /// /// The background music key. - 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); /// /// Reset the stored "UI hide" state. diff --git a/Dalamud/Interface/Internal/DalamudCommands.cs b/Dalamud/Interface/Internal/DalamudCommands.cs index 2d49a8163..7855f9c54 100644 --- a/Dalamud/Interface/Internal/DalamudCommands.cs +++ b/Dalamud/Interface/Internal/DalamudCommands.cs @@ -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.Get().TogglePluginInstallerWindow(); } - private void OnOpenCreditsCommand(string command, string arguments) - { - Service.Get().ToggleCreditsWindow(); - } - private void OnSetLanguageCommand(string command, string arguments) { var chatGui = Service.Get(); diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs index 68393bfa5..14d8f10de 100644 --- a/Dalamud/Interface/Internal/DalamudInterface.cs +++ b/Dalamud/Interface/Internal/DalamudInterface.cs @@ -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); } /// @@ -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 /// public void OpenComponentDemoWindow() => this.componentDemoWindow.IsOpen = true; - /// - /// Opens the . - /// - public void OpenCreditsWindow() => this.creditsWindow.IsOpen = true; - /// /// Opens the . /// @@ -313,11 +314,6 @@ internal class DalamudInterface : IDisposable, IServiceType /// public void ToggleComponentDemoWindow() => this.componentDemoWindow.Toggle(); - /// - /// Toggles the . - /// - public void ToggleCreditsWindow() => this.creditsWindow.Toggle(); - /// /// Toggles the . /// @@ -388,6 +384,18 @@ internal class DalamudInterface : IDisposable, IServiceType #endregion + /// + /// Toggle the screen darkening effect used for the credits. + /// + /// Whether or not to turn the effect on. + 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.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(); diff --git a/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs b/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs index 0d19a340a..d2d51b8d6 100644 --- a/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs +++ b/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs @@ -52,7 +52,7 @@ internal class ConsoleWindow : Window, IDisposable /// Initializes a new instance of the class. /// public ConsoleWindow() - : base("Dalamud Console") + : base("Dalamud Console", ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse) { var configuration = Service.Get(); diff --git a/Dalamud/Interface/Internal/Windows/Settings/SettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/SettingsEntry.cs new file mode 100644 index 000000000..5e1dc7884 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/SettingsEntry.cs @@ -0,0 +1,52 @@ +using System; + +namespace Dalamud.Interface.Internal.Windows.Settings; + +/// +/// Basic, drawable settings entry. +/// +public abstract class SettingsEntry +{ + /// + /// Gets or sets the public, searchable name of this settings entry. + /// + public string? Name { get; protected set; } + + /// + /// Gets or sets a value indicating whether or not this entry is valid. + /// + public virtual bool IsValid { get; protected set; } = true; + + /// + /// Gets or sets a value indicating whether or not this entry is visible. + /// + public virtual bool IsVisible { get; protected set; } = true; + + /// + /// Gets the ID of this settings entry, used for ImGui uniqueness. + /// + protected Guid Id { get; } = Guid.NewGuid(); + + /// + /// Load this setting. + /// + public abstract void Load(); + + /// + /// Save this setting. + /// + public abstract void Save(); + + /// + /// Draw this setting control. + /// + public abstract void Draw(); + + /// + /// Function to be called when the tab is closed. + /// + public virtual void OnClose() + { + // ignored + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/SettingsTab.cs b/Dalamud/Interface/Internal/Windows/Settings/SettingsTab.cs new file mode 100644 index 000000000..16b7749cb --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/SettingsTab.cs @@ -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(); + } + } + + /// + public virtual void Dispose() + { + // ignored + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs new file mode 100644 index 000000000..24423b48c --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/SettingsWindow.cs @@ -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; + +/// +/// The window that allows for general configuration of Dalamud itself. +/// +internal class SettingsWindow : Window +{ + private readonly SettingsTab[] tabs = + { + new SettingsTabGeneral(), + new SettingsTabLook(), + new SettingsTabDtr(), + new SettingsTabExperimental(), + new SettingsTabAbout(), + }; + + private string searchInput = string.Empty; + + /// + /// Initializes a new instance of the class. + /// + 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; + } + + /// + public override void OnOpen() + { + foreach (var settingsTab in this.tabs) + { + settingsTab.Load(); + } + + this.searchInput = string.Empty; + + base.OnOpen(); + } + + /// + public override void OnClose() + { + var configuration = Service.Get(); + var interfaceManager = Service.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; + } + } + + /// + 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.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.Get(); + di.CloseGamepadModeNotifierWindow(); + } + else + { + ImGui.GetIO().BackendFlags |= ImGuiBackendFlags.HasGamepad; + ImGui.GetIO().ConfigFlags |= ImGuiConfigFlags.NavEnableSetMousePos; + } + + configuration.QueueSave(); + + _ = Service.Get().ReloadPluginMastersAsync(); + Service.Get().RebuildFonts(); + } +} diff --git a/Dalamud/Interface/Internal/Windows/CreditsWindow.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs similarity index 70% rename from Dalamud/Interface/Internal/Windows/CreditsWindow.cs rename to Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs index 83857a826..3ad67a841 100644 --- a/Dalamud/Interface/Internal/Windows/CreditsWindow.cs +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabAbout.cs @@ -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; -/// -/// A window documenting contributors to the project. -/// -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; - /// - /// Initializes a new instance of the class. - /// - public CreditsWindow() - : base("Dalamud Credits", ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoTitleBar, true) + public SettingsTabAbout() { var dalamud = Service.Get(); var interfaceManager = Service.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"); + /// 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.Get().SetBgm(833); + var gg = Service.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.Get(); this.thankYouFont = gfm.NewFontRef(new GameFontStyle(GameFontFamilyAndSize.TrumpGothic34)); } + + this.resetNow = true; + + Service.Get().SetCreditsDarkeningAnimation(true); } /// public override void OnClose() { this.creditsThrottler.Reset(); - Service.Get().SetBgm(9999); + + var gg = Service.Get(); + if (!gg.IsOnTitleScreen()) + gg.SetBgm(9999); + + Service.Get().SetCreditsDarkeningAnimation(false); } - /// - public override void PreDraw() - { - ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 0)); - - base.PreDraw(); - } - - /// - public override void PostDraw() - { - ImGui.PopStyleVar(); - - base.PostDraw(); - } - - /// 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(); } /// /// Disposes of managed and unmanaged resources. /// - public void Dispose() + public override void Dispose() { this.logoTexture?.Dispose(); this.thankYouFont?.Dispose(); diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabDtr.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabDtr.cs new file mode 100644 index 000000000..85cb8219f --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabDtr.cs @@ -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? dtrOrder; + private List? dtrIgnore; + private int dtrSpacing; + private bool dtrSwapDirection; + + public override SettingsEntry[] Entries { get; } = Array.Empty(); + + 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.Get(); + var dtrBar = Service.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.Get(); + configuration.DtrOrder = this.dtrOrder; + configuration.DtrIgnore = this.dtrIgnore; + + base.OnClose(); + } + + public override void Load() + { + var configuration = Service.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.Get(); + + configuration.DtrSpacing = this.dtrSpacing; + configuration.DtrSwapDirection = this.dtrSwapDirection; + + this.dtrOrder = configuration.DtrOrder; + this.dtrIgnore = configuration.DtrIgnore; + + base.Save(); + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs new file mode 100644 index 000000000..a1c2c3336 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabExperimental.cs @@ -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( + 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.Get().HiddenPluginInternalName.Clear(); + Service.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))); + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabGeneral.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabGeneral.cs new file mode 100644 index 000000000..7e5c9dd98 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabGeneral.cs @@ -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( + 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( + 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( + 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( + 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( + 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( + 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( + 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( + 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( + 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( + 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"); +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs new file mode 100644 index 000000000..8b9ef9952 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Tabs/SettingsTabLook.cs @@ -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.Get().OpenStyleEditor()), + + new GapSettingsEntry(5), + + new SettingsEntry( + 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.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( + 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( + 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( + 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( + 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( + 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( + 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( + 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( + 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.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.Get().GlobalUiScale; + this.fontGamma = Service.Get().FontGammaLevel; + + base.Load(); + } + + public override void Save() + { + Service.Get().GlobalUiScale = this.globalUiScale; + + base.Save(); + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/ButtonSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/ButtonSettingsEntry.cs new file mode 100644 index 000000000..9c635fb99 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/ButtonSettingsEntry.cs @@ -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); + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs new file mode 100644 index 000000000..b1a231335 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/DevPluginsSettingsEntry.cs @@ -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 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.Get().DevPluginLoadLocations.Select(x => x.Clone()).ToList(); + } + + public override void Load() + { + this.devPluginLocations = + Service.Get().DevPluginLoadLocations.Select(x => x.Clone()).ToList(); + this.devPluginLocationsChanged = false; + } + + public override void Save() + { + Service.Get().DevPluginLoadLocations = this.devPluginLocations.Select(x => x.Clone()).ToList(); + + if (this.devPluginLocationsChanged) + { + Service.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); + } + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/GapSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/GapSettingsEntry.cs new file mode 100644 index 000000000..bc5c2fd0a --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/GapSettingsEntry.cs @@ -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); + } + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/HintSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/HintSettingsEntry.cs new file mode 100644 index 000000000..d1eb43c1f --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/HintSettingsEntry.cs @@ -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); + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/LanguageChooserSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/LanguageChooserSettingsEntry.cs new file mode 100644 index 000000000..0bb373576 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/LanguageChooserSettingsEntry.cs @@ -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 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.Get().EffectiveLanguage); + if (this.langIndex == -1) + this.langIndex = 0; + } + + public override void Save() + { + Service.Get().SetupWithLangCode(this.languages[this.langIndex]); + Service.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.")); + } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/SettingsEntry{T}.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/SettingsEntry{T}.cs new file mode 100644 index 000000000..c08eb99f6 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/SettingsEntry{T}.cs @@ -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 : SettingsEntry +{ + private readonly LoadSettingDelegate load; + private readonly SaveSettingDelegate save; + private readonly Action? change; + + private object? valueBacking; + + public SettingsEntry(string name, string description, LoadSettingDelegate load, SaveSettingDelegate save, Action? change = null, Func? warning = null, Func? 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? CheckValidity { get; init; } + + public Func? CheckWarning { get; init; } + + public Func? 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().ToDictionary(x => x, x => x.GetAttribute() ?? 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.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.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; } +} diff --git a/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs b/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs new file mode 100644 index 000000000..e410b3482 --- /dev/null +++ b/Dalamud/Interface/Internal/Windows/Settings/Widgets/ThirdRepoSettingsEntry.cs @@ -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 thirdRepoList = new(); + private bool thirdRepoListChanged; + private string thirdRepoTempUrl = string.Empty; + private string thirdRepoAddError = string.Empty; + + public override void OnClose() + { + this.thirdRepoList = + Service.Get().ThirdRepoList.Select(x => x.Clone()).ToList(); + } + + public override void Load() + { + this.thirdRepoList = + Service.Get().ThirdRepoList.Select(x => x.Clone()).ToList(); + this.thirdRepoListChanged = false; + } + + public override void Save() + { + Service.Get().ThirdRepoList = + this.thirdRepoList.Select(x => x.Clone()).ToList(); + + if (this.thirdRepoListChanged) + { + _ = Service.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); + } + } +} diff --git a/Dalamud/Interface/Internal/Windows/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/SettingsWindow.cs deleted file mode 100644 index 72292faa3..000000000 --- a/Dalamud/Interface/Internal/Windows/SettingsWindow.cs +++ /dev/null @@ -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; - -/// -/// The window that allows for general configuration of Dalamud itself. -/// -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? dtrOrder; - private List? dtrIgnore; - private int dtrSpacing; - private bool dtrSwapDirection; - - private int? pluginWaitBeforeFree; - - private List thirdRepoList; - private bool thirdRepoListChanged; - private string thirdRepoTempUrl = string.Empty; - private string thirdRepoAddError = string.Empty; - - private List 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 - - /// - /// Initializes a new instance of the class. - /// - public SettingsWindow() - : base(Loc.Localize("DalamudSettingsHeader", "Dalamud Settings") + "###XlSettings2", ImGuiWindowFlags.NoCollapse) - { - var configuration = Service.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 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 OnOpen() - { - this.thirdRepoListChanged = false; - this.devPluginLocationsChanged = false; - - var configuration = Service.Get(); - this.dtrOrder = configuration.DtrOrder; - this.dtrIgnore = configuration.DtrIgnore; - } - - /// - public override void OnClose() - { - var configuration = Service.Get(); - var interfaceManager = Service.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(); - } - - /// - 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()) - { - 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.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.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.Get(); - var dtrBar = Service.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.Get(); - var pluginManager = Service.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.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.Get(); - var localization = Service.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.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.Get().ReloadPluginMastersAsync(); - Service.Get().RebuildFonts(); - } -} diff --git a/Dalamud/Plugin/Internal/PluginManager.cs b/Dalamud/Plugin/Internal/PluginManager.cs index 06cb52845..e03db5e91 100644 --- a/Dalamud/Plugin/Internal/PluginManager.cs +++ b/Dalamud/Plugin/Internal/PluginManager.cs @@ -43,7 +43,7 @@ internal partial class PluginManager : IDisposable, IServiceType /// /// Default time to wait between plugin unload and plugin assembly unload. /// - 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"; diff --git a/Dalamud/Utility/EnumExtensions.cs b/Dalamud/Utility/EnumExtensions.cs index 8868e4c1f..b4c58d95c 100644 --- a/Dalamud/Utility/EnumExtensions.cs +++ b/Dalamud/Utility/EnumExtensions.cs @@ -14,12 +14,15 @@ public static class EnumExtensions /// The type of attribute to get. /// The enum value that has an attached attribute. /// The attached attribute, if any. - public static TAttribute GetAttribute(this Enum value) + public static TAttribute? GetAttribute(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() .SingleOrDefault();