diff --git a/Dalamud/Configuration/Internal/DalamudConfiguration.cs b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
index 4b36b8288..390d9c9e5 100644
--- a/Dalamud/Configuration/Internal/DalamudConfiguration.cs
+++ b/Dalamud/Configuration/Internal/DalamudConfiguration.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO;
using Dalamud.Game.Text;
+using Dalamud.Interface.Internal.Windows.StyleEditor;
using Newtonsoft.Json;
using Serilog;
using Serilog.Events;
@@ -195,6 +196,16 @@ namespace Dalamud.Configuration.Internal
///
public bool PluginSafeMode { get; set; }
+ ///
+ /// Gets or sets a list of saved styles.
+ ///
+ public List? SavedStyles { get; set; }
+
+ ///
+ /// Gets or sets the name of the currently chosen style.
+ ///
+ public string ChosenStyle { get; set; } = "Dalamud Standard";
+
///
/// Gets or sets a value indicating whether or not Dalamud RMT filtering should be disabled.
///
diff --git a/Dalamud/Interface/Internal/DalamudInterface.cs b/Dalamud/Interface/Internal/DalamudInterface.cs
index c989b4393..cfccedd39 100644
--- a/Dalamud/Interface/Internal/DalamudInterface.cs
+++ b/Dalamud/Interface/Internal/DalamudInterface.cs
@@ -1,7 +1,9 @@
using System;
+using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Numerics;
+using System.Reflection;
using System.Runtime.InteropServices;
using Dalamud.Configuration.Internal;
@@ -11,12 +13,14 @@ using Dalamud.Game.Internal;
using Dalamud.Interface.Internal.ManagedAsserts;
using Dalamud.Interface.Internal.Windows;
using Dalamud.Interface.Internal.Windows.SelfTest;
+using Dalamud.Interface.Internal.Windows.StyleEditor;
using Dalamud.Interface.Windowing;
using Dalamud.Logging;
using Dalamud.Logging.Internal;
using Dalamud.Plugin.Internal;
using Dalamud.Utility;
using ImGuiNET;
+using Newtonsoft.Json;
using PInvoke;
using Serilog.Events;
@@ -42,6 +46,7 @@ namespace Dalamud.Interface.Internal
private readonly ScratchpadWindow scratchpadWindow;
private readonly SettingsWindow settingsWindow;
private readonly SelfTestWindow selfTestWindow;
+ private readonly StyleEditorWindow styleEditorWindow;
private ulong frameCount = 0;
@@ -75,6 +80,7 @@ namespace Dalamud.Interface.Internal
this.scratchpadWindow = new ScratchpadWindow() { IsOpen = false };
this.settingsWindow = new SettingsWindow() { IsOpen = false };
this.selfTestWindow = new SelfTestWindow() { IsOpen = false };
+ this.styleEditorWindow = new StyleEditorWindow() { IsOpen = false };
this.WindowSystem.AddWindow(this.changelogWindow);
this.WindowSystem.AddWindow(this.colorDemoWindow);
@@ -89,12 +95,11 @@ namespace Dalamud.Interface.Internal
this.WindowSystem.AddWindow(this.scratchpadWindow);
this.WindowSystem.AddWindow(this.settingsWindow);
this.WindowSystem.AddWindow(this.selfTestWindow);
+ this.WindowSystem.AddWindow(this.styleEditorWindow);
ImGuiManagedAsserts.AssertsEnabled = true;
Service.Get().Draw += this.OnDraw;
-
- Log.Information("Windows added");
}
///
@@ -208,6 +213,11 @@ namespace Dalamud.Interface.Internal
///
public void OpenSelfTest() => this.selfTestWindow.IsOpen = true;
+ ///
+ /// Opens the .
+ ///
+ public void OpenStyleEditor() => this.styleEditorWindow.IsOpen = true;
+
#endregion
#region Close
@@ -299,6 +309,11 @@ namespace Dalamud.Interface.Internal
///
public void ToggleSelfTestWindow() => this.selfTestWindow.Toggle();
+ ///
+ /// Toggles the .
+ ///
+ public void ToggleStyleEditorWindow() => this.selfTestWindow.Toggle();
+
#endregion
private void OnDraw()
@@ -448,6 +463,11 @@ namespace Dalamud.Interface.Internal
this.OpenSelfTest();
}
+ if (ImGui.MenuItem("Open Style Editor"))
+ {
+ this.OpenStyleEditor();
+ }
+
ImGui.Separator();
if (ImGui.MenuItem("Unload Dalamud"))
@@ -496,6 +516,38 @@ namespace Dalamud.Interface.Internal
ImGui.SetWindowFocus(null);
}
+ if (ImGui.MenuItem("Dump style"))
+ {
+ var info = string.Empty;
+ var style = StyleModel.Get();
+
+ foreach (var propertyInfo in typeof(StyleModel).GetProperties(BindingFlags.Public | BindingFlags.Instance))
+ {
+ if (propertyInfo.PropertyType == typeof(Vector2))
+ {
+ var vec2 = (Vector2)propertyInfo.GetValue(style);
+ info += $"{propertyInfo.Name} = new Vector2({vec2.X}, {vec2.Y}),\n";
+ }
+ else
+ {
+ info += $"{propertyInfo.Name} = {propertyInfo.GetValue(style)},\n";
+ }
+ }
+
+ info += "Colors = new Dictionary()\n";
+ info += "{\n";
+
+ foreach (var color in style.Colors)
+ {
+ info +=
+ $"{{\"{color.Key}\", new Vector4({color.Value.X}, {color.Value.Y}, {color.Value.Z}, {color.Value.W})}},\n";
+ }
+
+ info += "},";
+
+ Log.Information(info);
+ }
+
ImGui.EndMenu();
}
diff --git a/Dalamud/Interface/Internal/InterfaceManager.cs b/Dalamud/Interface/Internal/InterfaceManager.cs
index cefa34f5e..83640c808 100644
--- a/Dalamud/Interface/Internal/InterfaceManager.cs
+++ b/Dalamud/Interface/Internal/InterfaceManager.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
+using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
@@ -17,6 +18,7 @@ using Dalamud.Hooking;
using Dalamud.Hooking.Internal;
using Dalamud.Interface.Internal.ManagedAsserts;
using Dalamud.Interface.Internal.Notifications;
+using Dalamud.Interface.Internal.Windows.StyleEditor;
using Dalamud.Interface.Windowing;
using Dalamud.Utility;
using ImGuiNET;
@@ -336,34 +338,14 @@ namespace Dalamud.Interface.Internal
this.SetupFonts();
- ImGui.GetStyle().GrabRounding = 3f;
- ImGui.GetStyle().FrameRounding = 4f;
- ImGui.GetStyle().WindowRounding = 4f;
- ImGui.GetStyle().WindowBorderSize = 0f;
- ImGui.GetStyle().WindowMenuButtonPosition = ImGuiDir.Right;
- ImGui.GetStyle().ScrollbarSize = 16f;
+ if (configuration.SavedStyles == null || configuration.SavedStyles.All(x => x.Name != StyleModel.DalamudStandard.Name))
+ {
+ configuration.SavedStyles = new List { StyleModel.DalamudStandard };
+ configuration.ChosenStyle = StyleModel.DalamudStandard.Name;
+ }
- ImGui.GetStyle().Colors[(int)ImGuiCol.WindowBg] = new Vector4(0.06f, 0.06f, 0.06f, 0.87f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.FrameBg] = new Vector4(0.29f, 0.29f, 0.29f, 0.54f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.FrameBgHovered] = new Vector4(0.54f, 0.54f, 0.54f, 0.40f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.FrameBgActive] = new Vector4(0.64f, 0.64f, 0.64f, 0.67f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.TitleBgActive] = new Vector4(0.29f, 0.29f, 0.29f, 1.00f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.CheckMark] = new Vector4(0.86f, 0.86f, 0.86f, 1.00f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.SliderGrab] = new Vector4(0.54f, 0.54f, 0.54f, 1.00f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.SliderGrabActive] = new Vector4(0.67f, 0.67f, 0.67f, 1.00f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.Button] = new Vector4(0.71f, 0.71f, 0.71f, 0.40f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.ButtonHovered] = new Vector4(0.47f, 0.47f, 0.47f, 1.00f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.ButtonActive] = new Vector4(0.74f, 0.74f, 0.74f, 1.00f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.Header] = new Vector4(0.59f, 0.59f, 0.59f, 0.31f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.HeaderHovered] = new Vector4(0.50f, 0.50f, 0.50f, 0.80f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.HeaderActive] = new Vector4(0.60f, 0.60f, 0.60f, 1.00f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.ResizeGrip] = new Vector4(0.79f, 0.79f, 0.79f, 0.25f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.ResizeGripHovered] = new Vector4(0.78f, 0.78f, 0.78f, 0.67f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.ResizeGripActive] = new Vector4(0.88f, 0.88f, 0.88f, 0.95f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.Tab] = new Vector4(0.23f, 0.23f, 0.23f, 0.86f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.TabHovered] = new Vector4(0.71f, 0.71f, 0.71f, 0.80f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.TabActive] = new Vector4(0.36f, 0.36f, 0.36f, 1.00f);
- ImGui.GetStyle().Colors[(int)ImGuiCol.ScrollbarBg] = Vector4.Zero;
+ var style = configuration.SavedStyles.FirstOrDefault(x => x.Name == configuration.ChosenStyle) ?? StyleModel.DalamudStandard;
+ style.Apply();
ImGui.GetIO().FontGlobalScale = configuration.GlobalUiScale;
diff --git a/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs b/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs
index e5d82346f..50a5e7ce8 100644
--- a/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/ConsoleWindow.cs
@@ -416,7 +416,7 @@ namespace Dalamud.Interface.Internal.Windows
private void AddAndFilter(string line, LogEventLevel level, DateTimeOffset offset, bool isMultiline)
{
- if (line.StartsWith("TROUBLESHOOTING:") || line.StartsWith("EXCEPTION:"))
+ if (line.StartsWith("TROUBLESHOOTING:") || line.StartsWith("LASTEXCEPTION:"))
return;
var entry = new LogEntry
diff --git a/Dalamud/Interface/Internal/Windows/SettingsWindow.cs b/Dalamud/Interface/Internal/Windows/SettingsWindow.cs
index b40971eb3..274d349a0 100644
--- a/Dalamud/Interface/Internal/Windows/SettingsWindow.cs
+++ b/Dalamud/Interface/Internal/Windows/SettingsWindow.cs
@@ -264,6 +264,15 @@ namespace Dalamud.Interface.Internal.Windows
ImGuiHelpers.ScaledDummy(10, 16);
+ if (ImGui.Button(Loc.Localize("DalamudSettingsOpenStyleEditor", "Open Style Editor")))
+ {
+ Service.Get().OpenStyleEditor();
+ }
+
+ ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingsStyleEditorHint", "Modify the look & feel of Dalamud windows."));
+
+ ImGuiHelpers.ScaledDummy(10, 16);
+
ImGui.TextColored(this.hintTextColor, Loc.Localize("DalamudSettingToggleUiHideOptOutNote", "Plugins may independently opt out of the settings below."));
ImGui.Checkbox(Loc.Localize("DalamudSettingToggleUiHide", "Hide plugin UI when the game UI is toggled off"), ref this.doToggleUiHide);
diff --git a/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs b/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs
new file mode 100644
index 000000000..aa62543aa
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/StyleEditor/StyleEditorWindow.cs
@@ -0,0 +1,348 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Numerics;
+
+using CheapLoc;
+using Dalamud.Configuration.Internal;
+using Dalamud.Data;
+using Dalamud.Interface.Colors;
+using Dalamud.Interface.Components;
+using Dalamud.Interface.Windowing;
+using ImGuiNET;
+using Lumina.Excel.GeneratedSheets;
+using Serilog;
+
+namespace Dalamud.Interface.Internal.Windows.StyleEditor
+{
+ ///
+ /// Window for the Dalamud style editor.
+ ///
+ public class StyleEditorWindow : Window
+ {
+ private ImGuiColorEditFlags alphaFlags = ImGuiColorEditFlags.None;
+ private StyleModel workStyle = StyleModel.DalamudStandard;
+
+ private int currentSel = 0;
+ private string initialStyle = string.Empty;
+ private bool didSave = false;
+
+ private string renameText = string.Empty;
+ private bool renameModalDrawing = false;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public StyleEditorWindow()
+ : base("Dalamud Style Editor")
+ {
+ this.IsOpen = true;
+ this.SizeConstraints = new WindowSizeConstraints
+ {
+ MinimumSize = new Vector2(890, 560),
+ MaximumSize = new Vector2(10000, 10000),
+ };
+ }
+
+ ///
+ public override void OnOpen()
+ {
+ this.didSave = false;
+
+ var config = Service.Get();
+ config.SavedStyles ??= new List();
+ this.currentSel = config.SavedStyles.FindIndex(x => x.Name == config.ChosenStyle);
+
+ this.initialStyle = config.ChosenStyle;
+
+ base.OnOpen();
+ }
+
+ ///
+ public override void OnClose()
+ {
+ if (!this.didSave)
+ {
+ var config = Service.Get();
+ var newStyle = config.SavedStyles.FirstOrDefault(x => x.Name == this.initialStyle);
+ newStyle?.Apply();
+ }
+
+ base.OnClose();
+ }
+
+ ///
+ public override void Draw()
+ {
+ var config = Service.Get();
+ var renameModalTitle = Loc.Localize("RenameStyleModalTitle", "Rename Style");
+
+ var appliedThisFrame = false;
+
+ var styleAry = config.SavedStyles.Select(x => x.Name).ToArray();
+ ImGui.Text(Loc.Localize("StyleEditorChooseStyle", "Choose Style:"));
+ if (ImGui.Combo("###styleChooserCombo", ref this.currentSel, styleAry, styleAry.Length))
+ {
+ var newStyle = config.SavedStyles[this.currentSel];
+ newStyle.Apply();
+ appliedThisFrame = true;
+ }
+
+ if (ImGui.Button(Loc.Localize("StyleEditorAddNew", "Add new style")))
+ {
+ var newStyle = StyleModel.DalamudStandard;
+ newStyle.Name = GetRandomName();
+ config.SavedStyles.Add(newStyle);
+
+ this.currentSel = config.SavedStyles.Count - 1;
+
+ newStyle.Apply();
+ appliedThisFrame = true;
+
+ config.Save();
+ }
+
+ ImGui.SameLine();
+
+ if (ImGuiComponents.IconButton(FontAwesomeIcon.Trash) && this.currentSel != 0)
+ {
+ this.currentSel--;
+ var newStyle = config.SavedStyles[this.currentSel];
+ newStyle.Apply();
+ appliedThisFrame = true;
+
+ config.SavedStyles.RemoveAt(this.currentSel + 1);
+
+ config.Save();
+ }
+
+ if (ImGui.IsItemHovered())
+ ImGui.SetTooltip(Loc.Localize("StyleEditorDeleteStyle", "Delete current style"));
+
+ ImGui.SameLine();
+
+ if (ImGuiComponents.IconButton(FontAwesomeIcon.Pen) && this.currentSel != 0)
+ {
+ var newStyle = config.SavedStyles[this.currentSel];
+ this.renameText = newStyle.Name;
+
+ this.renameModalDrawing = true;
+ ImGui.OpenPopup(renameModalTitle);
+ }
+
+ if (ImGui.IsItemHovered())
+ ImGui.SetTooltip(Loc.Localize("StyleEditorRenameStyle", "Rename style"));
+
+ ImGui.SameLine();
+
+ ImGuiHelpers.ScaledDummy(5);
+ ImGui.SameLine();
+
+ if (ImGuiComponents.IconButton(FontAwesomeIcon.FileExport))
+ {
+ var newStyle = config.SavedStyles[this.currentSel];
+ ImGui.SetClipboardText(newStyle.ToEncoded());
+ }
+
+ if (ImGui.IsItemHovered())
+ ImGui.SetTooltip(Loc.Localize("StyleEditorCopy", "Copy style to clipboard for sharing"));
+
+ ImGui.SameLine();
+
+ if (ImGuiComponents.IconButton(FontAwesomeIcon.FileImport))
+ {
+ var styleJson = ImGui.GetClipboardText();
+
+ try
+ {
+ var newStyle = StyleModel.FromEncoded(styleJson);
+
+ newStyle.Name ??= GetRandomName();
+
+ config.SavedStyles.Add(newStyle);
+ newStyle.Apply();
+ appliedThisFrame = true;
+
+ this.currentSel = config.SavedStyles.Count - 1;
+
+ config.Save();
+ }
+ catch (Exception ex)
+ {
+ Log.Error(ex, "Could not import style");
+ }
+ }
+
+ if (ImGui.IsItemHovered())
+ ImGui.SetTooltip(Loc.Localize("StyleEditorImport", "Import style from clipboard"));
+
+ ImGui.Separator();
+
+ ImGui.PushItemWidth(ImGui.GetWindowWidth() * 0.50f);
+
+ if (this.currentSel == 0)
+ {
+ ImGui.TextColored(ImGuiColors.DalamudRed, Loc.Localize("StyleEditorNotAllowed", "You cannot edit the \"Dalamud Standard\" style. Please add a new style first."));
+ }
+ else if (appliedThisFrame)
+ {
+ ImGui.Text(Loc.Localize("StyleEditorApplying", "Applying style..."));
+ }
+ else if (ImGui.BeginTabBar("StyleEditorTabs"))
+ {
+ var style = ImGui.GetStyle();
+
+ if (ImGui.BeginTabItem("Variables"))
+ {
+ ImGui.BeginChild($"ScrollingVars", ImGuiHelpers.ScaledVector2(0, -32), true, ImGuiWindowFlags.HorizontalScrollbar | ImGuiWindowFlags.NoBackground);
+
+ ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 5);
+
+ ImGui.SliderFloat2("WindowPadding", ref style.WindowPadding, 0.0f, 20.0f, "%.0f");
+ ImGui.SliderFloat2("FramePadding", ref style.FramePadding, 0.0f, 20.0f, "%.0f");
+ ImGui.SliderFloat2("CellPadding", ref style.CellPadding, 0.0f, 20.0f, "%.0f");
+ ImGui.SliderFloat2("ItemSpacing", ref style.ItemSpacing, 0.0f, 20.0f, "%.0f");
+ ImGui.SliderFloat2("ItemInnerSpacing", ref style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
+ ImGui.SliderFloat2("TouchExtraPadding", ref style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
+ ImGui.SliderFloat("IndentSpacing", ref style.IndentSpacing, 0.0f, 30.0f, "%.0f");
+ ImGui.SliderFloat("ScrollbarSize", ref style.ScrollbarSize, 1.0f, 20.0f, "%.0f");
+ ImGui.SliderFloat("GrabMinSize", ref style.GrabMinSize, 1.0f, 20.0f, "%.0f");
+ ImGui.Text("Borders");
+ ImGui.SliderFloat("WindowBorderSize", ref style.WindowBorderSize, 0.0f, 1.0f, "%.0f");
+ ImGui.SliderFloat("ChildBorderSize", ref style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
+ ImGui.SliderFloat("PopupBorderSize", ref style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
+ ImGui.SliderFloat("FrameBorderSize", ref style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
+ ImGui.SliderFloat("TabBorderSize", ref style.TabBorderSize, 0.0f, 1.0f, "%.0f");
+ ImGui.Text("Rounding");
+ ImGui.SliderFloat("WindowRounding", ref style.WindowRounding, 0.0f, 12.0f, "%.0f");
+ ImGui.SliderFloat("ChildRounding", ref style.ChildRounding, 0.0f, 12.0f, "%.0f");
+ ImGui.SliderFloat("FrameRounding", ref style.FrameRounding, 0.0f, 12.0f, "%.0f");
+ ImGui.SliderFloat("PopupRounding", ref style.PopupRounding, 0.0f, 12.0f, "%.0f");
+ ImGui.SliderFloat("ScrollbarRounding", ref style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
+ ImGui.SliderFloat("GrabRounding", ref style.GrabRounding, 0.0f, 12.0f, "%.0f");
+ ImGui.SliderFloat("LogSliderDeadzone", ref style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
+ ImGui.SliderFloat("TabRounding", ref style.TabRounding, 0.0f, 12.0f, "%.0f");
+ ImGui.Text("Alignment");
+ ImGui.SliderFloat2("WindowTitleAlign", ref style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
+ var windowMenuButtonPosition = (int)style.WindowMenuButtonPosition + 1;
+ if (ImGui.Combo("WindowMenuButtonPosition", ref windowMenuButtonPosition, "None\0Left\0Right\0"))
+ style.WindowMenuButtonPosition = (ImGuiDir)(windowMenuButtonPosition - 1);
+ ImGui.SliderFloat2("ButtonTextAlign", ref style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
+ ImGui.SameLine();
+ ImGuiComponents.HelpMarker("Alignment applies when a button is larger than its text content.");
+ ImGui.SliderFloat2("SelectableTextAlign", ref style.SelectableTextAlign, 0.0f, 1.0f, "%.2f");
+ ImGui.SameLine();
+ ImGuiComponents.HelpMarker("Alignment applies when a selectable is larger than its text content.");
+ ImGui.SliderFloat2("DisplaySafeAreaPadding", ref style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f");
+ ImGui.SameLine();
+ ImGuiComponents.HelpMarker(
+ "Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
+ ImGui.EndTabItem();
+
+ ImGui.EndChild();
+
+ ImGui.EndTabItem();
+ }
+
+ if (ImGui.BeginTabItem("Colors"))
+ {
+ ImGui.BeginChild("ScrollingColors", ImGuiHelpers.ScaledVector2(0, -30), true, ImGuiWindowFlags.HorizontalScrollbar | ImGuiWindowFlags.NoBackground);
+
+ ImGui.SetCursorPosY(ImGui.GetCursorPosY() - 5);
+
+ if (ImGui.RadioButton("Opaque", this.alphaFlags == ImGuiColorEditFlags.None))
+ this.alphaFlags = ImGuiColorEditFlags.None;
+ ImGui.SameLine();
+ if (ImGui.RadioButton("Alpha", this.alphaFlags == ImGuiColorEditFlags.AlphaPreview))
+ this.alphaFlags = ImGuiColorEditFlags.AlphaPreview;
+ ImGui.SameLine();
+ if (ImGui.RadioButton("Both", this.alphaFlags == ImGuiColorEditFlags.AlphaPreviewHalf))
+ this.alphaFlags = ImGuiColorEditFlags.AlphaPreviewHalf;
+ ImGui.SameLine();
+
+ ImGuiComponents.HelpMarker(
+ "In the color list:\n" +
+ "Left-click on color square to open color picker,\n" +
+ "Right-click to open edit options menu.");
+
+ foreach (var imGuiCol in Enum.GetValues())
+ {
+ if (imGuiCol == ImGuiCol.COUNT)
+ continue;
+
+ ImGui.PushID(imGuiCol.ToString());
+
+ ImGui.ColorEdit4("##color", ref style.Colors[(int)imGuiCol], ImGuiColorEditFlags.AlphaBar | this.alphaFlags);
+
+ ImGui.SameLine(0.0f, style.ItemInnerSpacing.X);
+ ImGui.TextUnformatted(imGuiCol.ToString());
+
+ ImGui.PopID();
+ }
+
+ ImGui.EndChild();
+
+ ImGui.EndTabItem();
+ }
+
+ ImGui.EndTabBar();
+ }
+
+ ImGui.PopItemWidth();
+
+ ImGui.Separator();
+
+ if (ImGui.Button(Loc.Localize("Close", "Close")))
+ {
+ this.IsOpen = false;
+ }
+
+ ImGui.SameLine();
+
+ if (ImGui.Button(Loc.Localize("SaveAndClose", "Save and Close")))
+ {
+ config.ChosenStyle = config.SavedStyles[this.currentSel].Name;
+
+ var newStyle = StyleModel.Get();
+ newStyle.Name = config.ChosenStyle;
+ config.SavedStyles[this.currentSel] = newStyle;
+ newStyle.Apply();
+
+ config.Save();
+ this.didSave = true;
+
+ this.IsOpen = false;
+ }
+
+ if (ImGui.BeginPopupModal(renameModalTitle, ref this.renameModalDrawing, ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoScrollbar))
+ {
+ ImGui.Text(Loc.Localize("StyleEditorEnterName", "Please enter the new name for this style."));
+ ImGui.Spacing();
+
+ ImGui.InputText("###renameModalInput", ref this.renameText, 255);
+
+ const float buttonWidth = 120f;
+ ImGui.SetCursorPosX((ImGui.GetWindowWidth() - buttonWidth) / 2);
+
+ if (ImGui.Button("OK", new Vector2(buttonWidth, 40)))
+ {
+ config.SavedStyles[this.currentSel].Name = this.renameText;
+ config.Save();
+
+ ImGui.CloseCurrentPopup();
+ }
+
+ ImGui.EndPopup();
+ }
+ }
+
+ private static string GetRandomName()
+ {
+ var data = Service.Get();
+ var names = data.GetExcelSheet(ClientLanguage.English);
+ var rng = new Random();
+
+ return names.ElementAt(rng.Next(0, names.Count() - 1)).Singular.RawString;
+ }
+ }
+}
diff --git a/Dalamud/Interface/Internal/Windows/StyleEditor/StyleModel.cs b/Dalamud/Interface/Internal/Windows/StyleEditor/StyleModel.cs
new file mode 100644
index 000000000..c8d43e775
--- /dev/null
+++ b/Dalamud/Interface/Internal/Windows/StyleEditor/StyleModel.cs
@@ -0,0 +1,329 @@
+using System;
+using System.Collections.Generic;
+using System.Numerics;
+
+using Dalamud.Utility;
+using ImGuiNET;
+using Newtonsoft.Json;
+
+namespace Dalamud.Interface.Internal.Windows.StyleEditor
+{
+ ///
+ /// Class representing a serializable ImGui style.
+ ///
+ public class StyleModel
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ private StyleModel()
+ {
+ this.Colors = new Dictionary();
+ this.Name = "Unknown";
+ }
+
+ ///
+ /// Gets the standard Dalamud look.
+ ///
+ public static StyleModel DalamudStandard => new()
+ {
+ Name = "Dalamud Standard",
+
+ Alpha = 1,
+ WindowPadding = new Vector2(8, 8),
+ WindowRounding = 4,
+ WindowBorderSize = 0,
+ WindowTitleAlign = new Vector2(0, 0.5f),
+ WindowMenuButtonPosition = ImGuiDir.Right,
+ ChildRounding = 0,
+ ChildBorderSize = 1,
+ PopupRounding = 0,
+ FramePadding = new Vector2(4, 3),
+ FrameRounding = 4,
+ FrameBorderSize = 0,
+ ItemSpacing = new Vector2(8, 4),
+ ItemInnerSpacing = new Vector2(4, 4),
+ CellPadding = new Vector2(4, 2),
+ TouchExtraPadding = new Vector2(0, 0),
+ IndentSpacing = 21,
+ ScrollbarSize = 16,
+ ScrollbarRounding = 9,
+ GrabMinSize = 10,
+ GrabRounding = 3,
+ LogSliderDeadzone = 4,
+ TabRounding = 4,
+ TabBorderSize = 0,
+ ButtonTextAlign = new Vector2(0.5f, 0.5f),
+ SelectableTextAlign = new Vector2(0, 0),
+ DisplaySafeAreaPadding = new Vector2(3, 3),
+
+ Colors = new Dictionary
+ {
+ { "Text", new Vector4(1, 1, 1, 1) },
+ { "TextDisabled", new Vector4(0.5f, 0.5f, 0.5f, 1) },
+ { "WindowBg", new Vector4(0.06f, 0.06f, 0.06f, 0.87f) },
+ { "ChildBg", new Vector4(0, 0, 0, 0) },
+ { "PopupBg", new Vector4(0.08f, 0.08f, 0.08f, 0.94f) },
+ { "Border", new Vector4(0.43f, 0.43f, 0.5f, 0.5f) },
+ { "BorderShadow", new Vector4(0, 0, 0, 0) },
+ { "FrameBg", new Vector4(0.29f, 0.29f, 0.29f, 0.54f) },
+ { "FrameBgHovered", new Vector4(0.54f, 0.54f, 0.54f, 0.4f) },
+ { "FrameBgActive", new Vector4(0.64f, 0.64f, 0.64f, 0.67f) },
+ { "TitleBg", new Vector4(0.04f, 0.04f, 0.04f, 1) },
+ { "TitleBgActive", new Vector4(0.29f, 0.29f, 0.29f, 1) },
+ { "TitleBgCollapsed", new Vector4(0, 0, 0, 0.51f) },
+ { "MenuBarBg", new Vector4(0.14f, 0.14f, 0.14f, 1) },
+ { "ScrollbarBg", new Vector4(0, 0, 0, 0) },
+ { "ScrollbarGrab", new Vector4(0.31f, 0.31f, 0.31f, 1) },
+ { "ScrollbarGrabHovered", new Vector4(0.41f, 0.41f, 0.41f, 1) },
+ { "ScrollbarGrabActive", new Vector4(0.51f, 0.51f, 0.51f, 1) },
+ { "CheckMark", new Vector4(0.86f, 0.86f, 0.86f, 1) },
+ { "SliderGrab", new Vector4(0.54f, 0.54f, 0.54f, 1) },
+ { "SliderGrabActive", new Vector4(0.67f, 0.67f, 0.67f, 1) },
+ { "Button", new Vector4(0.71f, 0.71f, 0.71f, 0.4f) },
+ { "ButtonHovered", new Vector4(0.47f, 0.47f, 0.47f, 1) },
+ { "ButtonActive", new Vector4(0.74f, 0.74f, 0.74f, 1) },
+ { "Header", new Vector4(0.59f, 0.59f, 0.59f, 0.31f) },
+ { "HeaderHovered", new Vector4(0.5f, 0.5f, 0.5f, 0.8f) },
+ { "HeaderActive", new Vector4(0.6f, 0.6f, 0.6f, 1) },
+ { "Separator", new Vector4(0.43f, 0.43f, 0.5f, 0.5f) },
+ { "SeparatorHovered", new Vector4(0.1f, 0.4f, 0.75f, 0.78f) },
+ { "SeparatorActive", new Vector4(0.1f, 0.4f, 0.75f, 1) },
+ { "ResizeGrip", new Vector4(0.79f, 0.79f, 0.79f, 0.25f) },
+ { "ResizeGripHovered", new Vector4(0.78f, 0.78f, 0.78f, 0.67f) },
+ { "ResizeGripActive", new Vector4(0.88f, 0.88f, 0.88f, 0.95f) },
+ { "Tab", new Vector4(0.23f, 0.23f, 0.23f, 0.86f) },
+ { "TabHovered", new Vector4(0.71f, 0.71f, 0.71f, 0.8f) },
+ { "TabActive", new Vector4(0.36f, 0.36f, 0.36f, 1) },
+ { "TabUnfocused", new Vector4(0.068f, 0.10199998f, 0.14800003f, 0.9724f) },
+ { "TabUnfocusedActive", new Vector4(0.13599998f, 0.26199996f, 0.424f, 1) },
+ { "DockingPreview", new Vector4(0.26f, 0.59f, 0.98f, 0.7f) },
+ { "DockingEmptyBg", new Vector4(0.2f, 0.2f, 0.2f, 1) },
+ { "PlotLines", new Vector4(0.61f, 0.61f, 0.61f, 1) },
+ { "PlotLinesHovered", new Vector4(1, 0.43f, 0.35f, 1) },
+ { "PlotHistogram", new Vector4(0.9f, 0.7f, 0, 1) },
+ { "PlotHistogramHovered", new Vector4(1, 0.6f, 0, 1) },
+ { "TableHeaderBg", new Vector4(0.19f, 0.19f, 0.2f, 1) },
+ { "TableBorderStrong", new Vector4(0.31f, 0.31f, 0.35f, 1) },
+ { "TableBorderLight", new Vector4(0.23f, 0.23f, 0.25f, 1) },
+ { "TableRowBg", new Vector4(0, 0, 0, 0) },
+ { "TableRowBgAlt", new Vector4(1, 1, 1, 0.06f) },
+ { "TextSelectedBg", new Vector4(0.26f, 0.59f, 0.98f, 0.35f) },
+ { "DragDropTarget", new Vector4(1, 1, 0, 0.9f) },
+ { "NavHighlight", new Vector4(0.26f, 0.59f, 0.98f, 1) },
+ { "NavWindowingHighlight", new Vector4(1, 1, 1, 0.7f) },
+ { "NavWindowingDimBg", new Vector4(0.8f, 0.8f, 0.8f, 0.2f) },
+ { "ModalWindowDimBg", new Vector4(0.8f, 0.8f, 0.8f, 0.35f) },
+ },
+ };
+
+#pragma warning disable SA1600
+
+ [JsonProperty("name")]
+ public string Name { get; set; }
+
+ [JsonProperty("a")]
+ public float Alpha { get; set; }
+
+ [JsonProperty("b")]
+ public Vector2 WindowPadding { get; set; }
+
+ [JsonProperty("c")]
+ public float WindowRounding { get; set; }
+
+ [JsonProperty("d")]
+ public float WindowBorderSize { get; set; }
+
+ [JsonProperty("e")]
+ public Vector2 WindowTitleAlign { get; set; }
+
+ [JsonProperty("f")]
+ public ImGuiDir WindowMenuButtonPosition { get; set; }
+
+ [JsonProperty("g")]
+ public float ChildRounding { get; set; }
+
+ [JsonProperty("h")]
+ public float ChildBorderSize { get; set; }
+
+ [JsonProperty("i")]
+ public float PopupRounding { get; set; }
+
+ [JsonProperty("j")]
+ public Vector2 FramePadding { get; set; }
+
+ [JsonProperty("k")]
+ public float FrameRounding { get; set; }
+
+ [JsonProperty("l")]
+ public float FrameBorderSize { get; set; }
+
+ [JsonProperty("m")]
+ public Vector2 ItemSpacing { get; set; }
+
+ [JsonProperty("n")]
+ public Vector2 ItemInnerSpacing { get; set; }
+
+ [JsonProperty("o")]
+ public Vector2 CellPadding { get; set; }
+
+ [JsonProperty("p")]
+ public Vector2 TouchExtraPadding { get; set; }
+
+ [JsonProperty("q")]
+ public float IndentSpacing { get; set; }
+
+ [JsonProperty("r")]
+ public float ScrollbarSize { get; set; }
+
+ [JsonProperty("s")]
+ public float ScrollbarRounding { get; set; }
+
+ [JsonProperty("t")]
+ public float GrabMinSize { get; set; }
+
+ [JsonProperty("u")]
+ public float GrabRounding { get; set; }
+
+ [JsonProperty("v")]
+ public float LogSliderDeadzone { get; set; }
+
+ [JsonProperty("w")]
+ public float TabRounding { get; set; }
+
+ [JsonProperty("x")]
+ public float TabBorderSize { get; set; }
+
+ [JsonProperty("y")]
+ public Vector2 ButtonTextAlign { get; set; }
+
+ [JsonProperty("z")]
+ public Vector2 SelectableTextAlign { get; set; }
+
+ [JsonProperty("aa")]
+ public Vector2 DisplaySafeAreaPadding { get; set; }
+
+#pragma warning restore SA1600
+
+ ///
+ /// Gets or sets a dictionary mapping ImGui color names to colors.
+ ///
+ [JsonProperty("col")]
+ public Dictionary Colors { get; set; }
+
+ ///
+ /// Get a instance via ImGui.
+ ///
+ /// The newly created instance.
+ public static StyleModel Get()
+ {
+ var model = new StyleModel();
+ var style = ImGui.GetStyle();
+
+ model.Alpha = style.Alpha;
+ model.WindowPadding = style.WindowPadding;
+ model.WindowRounding = style.WindowRounding;
+ model.WindowBorderSize = style.WindowBorderSize;
+ model.WindowTitleAlign = style.WindowTitleAlign;
+ model.WindowMenuButtonPosition = style.WindowMenuButtonPosition;
+ model.ChildRounding = style.ChildRounding;
+ model.ChildBorderSize = style.ChildBorderSize;
+ model.PopupRounding = style.PopupRounding;
+ model.FramePadding = style.FramePadding;
+ model.FrameRounding = style.FrameRounding;
+ model.FrameBorderSize = style.FrameBorderSize;
+ model.ItemSpacing = style.ItemSpacing;
+ model.ItemInnerSpacing = style.ItemInnerSpacing;
+ model.CellPadding = style.CellPadding;
+ model.TouchExtraPadding = style.TouchExtraPadding;
+ model.IndentSpacing = style.IndentSpacing;
+ model.ScrollbarSize = style.ScrollbarSize;
+ model.ScrollbarRounding = style.ScrollbarRounding;
+ model.GrabMinSize = style.GrabMinSize;
+ model.GrabRounding = style.GrabRounding;
+ model.LogSliderDeadzone = style.LogSliderDeadzone;
+ model.TabRounding = style.TabRounding;
+ model.TabBorderSize = style.TabBorderSize;
+ model.ButtonTextAlign = style.ButtonTextAlign;
+ model.SelectableTextAlign = style.SelectableTextAlign;
+ model.DisplaySafeAreaPadding = style.DisplaySafeAreaPadding;
+
+ model.Colors = new Dictionary();
+
+ foreach (var imGuiCol in Enum.GetValues())
+ {
+ if (imGuiCol == ImGuiCol.COUNT)
+ {
+ continue;
+ }
+
+ model.Colors[imGuiCol.ToString()] = style.Colors[(int)imGuiCol];
+ }
+
+ return model;
+ }
+
+ ///
+ /// Get a instance from a compressed base64 string.
+ ///
+ /// The string to decode.
+ /// A decompressed .
+ public static StyleModel? FromEncoded(string data)
+ {
+ var json = Util.DecompressString(Convert.FromBase64String(data.Substring(3)));
+ return JsonConvert.DeserializeObject(json);
+ }
+
+ ///
+ /// Get this instance as a encoded base64 string.
+ ///
+ /// The encoded base64 string.
+ public string ToEncoded() => "DS1" + Convert.ToBase64String(Util.CompressString(JsonConvert.SerializeObject(this)));
+
+ ///
+ /// Apply this StyleModel via ImGui.
+ ///
+ public void Apply()
+ {
+ var style = ImGui.GetStyle();
+
+ style.Alpha = this.Alpha;
+ style.WindowPadding = this.WindowPadding;
+ style.WindowRounding = this.WindowRounding;
+ style.WindowBorderSize = this.WindowBorderSize;
+ style.WindowTitleAlign = this.WindowTitleAlign;
+ style.WindowMenuButtonPosition = this.WindowMenuButtonPosition;
+ style.ChildRounding = this.ChildRounding;
+ style.ChildBorderSize = this.ChildBorderSize;
+ style.PopupRounding = this.PopupRounding;
+ style.FramePadding = this.FramePadding;
+ style.FrameRounding = this.FrameRounding;
+ style.FrameBorderSize = this.FrameBorderSize;
+ style.ItemSpacing = this.ItemSpacing;
+ style.ItemInnerSpacing = this.ItemInnerSpacing;
+ style.CellPadding = this.CellPadding;
+ style.TouchExtraPadding = this.TouchExtraPadding;
+ style.IndentSpacing = this.IndentSpacing;
+ style.ScrollbarSize = this.ScrollbarSize;
+ style.ScrollbarRounding = this.ScrollbarRounding;
+ style.GrabMinSize = this.GrabMinSize;
+ style.GrabRounding = this.GrabRounding;
+ style.LogSliderDeadzone = this.LogSliderDeadzone;
+ style.TabRounding = this.TabRounding;
+ style.TabBorderSize = this.TabBorderSize;
+ style.ButtonTextAlign = this.ButtonTextAlign;
+ style.SelectableTextAlign = this.SelectableTextAlign;
+ style.DisplaySafeAreaPadding = this.DisplaySafeAreaPadding;
+
+ foreach (var imGuiCol in Enum.GetValues())
+ {
+ if (imGuiCol == ImGuiCol.COUNT)
+ {
+ continue;
+ }
+
+ style.Colors[(int)imGuiCol] = this.Colors[imGuiCol.ToString()];
+ }
+ }
+ }
+}
diff --git a/Dalamud/Utility/Util.cs b/Dalamud/Utility/Util.cs
index db0056ec0..cded71473 100644
--- a/Dalamud/Utility/Util.cs
+++ b/Dalamud/Utility/Util.cs
@@ -1,5 +1,7 @@
using System;
using System.Diagnostics;
+using System.IO;
+using System.IO.Compression;
using System.Linq;
using System.Reflection;
using System.Text;
@@ -205,6 +207,60 @@ namespace Dalamud.Utility
return text;
}
+ ///
+ /// Compress a string using GZip.
+ ///
+ /// The input string.
+ /// The compressed output bytes.
+ public static byte[] CompressString(string str)
+ {
+ var bytes = Encoding.UTF8.GetBytes(str);
+
+ using (var msi = new MemoryStream(bytes))
+ using (var mso = new MemoryStream())
+ {
+ using (var gs = new GZipStream(mso, CompressionMode.Compress))
+ {
+ CopyTo(msi, gs);
+ }
+
+ return mso.ToArray();
+ }
+ }
+
+ ///
+ /// Decompress a string using GZip.
+ ///
+ /// The input bytes.
+ /// The compressed output string.
+ public static string DecompressString(byte[] bytes)
+ {
+ using (var msi = new MemoryStream(bytes))
+ using (var mso = new MemoryStream())
+ {
+ using (var gs = new GZipStream(msi, CompressionMode.Decompress))
+ {
+ CopyTo(gs, mso);
+ }
+
+ return Encoding.UTF8.GetString(mso.ToArray());
+ }
+ }
+
+ ///
+ /// Copy one stream to another.
+ ///
+ /// The source stream.
+ /// The destination stream.
+ /// The maximum length to copy.
+ public static void CopyTo(Stream src, Stream dest, int len = 4069)
+ {
+ var bytes = new byte[len];
+ int cnt;
+
+ while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0) dest.Write(bytes, 0, cnt);
+ }
+
// TODO: Someone implement GetUTF8String with some IntPtr overloads.
// while(Marshal.ReadByte(0, sz) != 0) { sz++; }
}
diff --git a/lib/FFXIVClientStructs b/lib/FFXIVClientStructs
index ed5d30106..a33bfbc1e 160000
--- a/lib/FFXIVClientStructs
+++ b/lib/FFXIVClientStructs
@@ -1 +1 @@
-Subproject commit ed5d30106f4b2deaa225d6a91db09a268c9cb77d
+Subproject commit a33bfbc1e81f0baa42827e952742289e32854308