diff --git a/LMeter/ACT/DataStructures/ActEvent.cs b/LMeter/ACT/DataStructures/ActEvent.cs index e5ae9dd..586365f 100644 --- a/LMeter/ACT/DataStructures/ActEvent.cs +++ b/LMeter/ACT/DataStructures/ActEvent.cs @@ -1,11 +1,21 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using LMeter.Helpers; using Newtonsoft.Json; namespace LMeter.Act.DataStructures { - public class ActEvent + public class ActEvent : IActData { + [JsonIgnore] + public static string[] TextTags { get; } = + typeof(ActEvent).GetMembers().Where(x => Attribute.IsDefined(x, typeof(TextTagAttribute))).Select(x => $"[{x.Name.ToLower()}]").ToArray(); + + private static readonly Dictionary _textTagMembers = + typeof(ActEvent).GetMembers().Where(x => Attribute.IsDefined(x, typeof(TextTagAttribute))).ToDictionary((x) => x.Name.ToLower()); + private bool _parsedActive; private bool _active; @@ -23,6 +33,11 @@ public class ActEvent [JsonProperty("Combatant")] public Dictionary? Combatants { get; set; } + + public string GetFormattedString(string format, string numberFormat) + { + return TextTagFormatter.TextTagRegex.Replace(format, new TextTagFormatter(this, numberFormat, _textTagMembers).Evaluate); + } public bool IsEncounterActive() { @@ -31,8 +46,7 @@ public bool IsEncounterActive() return _active; } - bool.TryParse(this.IsActive, out _active); - _parsedActive = true; + _parsedActive = bool.TryParse(this.IsActive, out _active); return _active; } @@ -64,11 +78,34 @@ public bool Equals(ActEvent? actEvent) public static ActEvent GetTestData() { - return new ActEvent() + Dictionary mockCombatants = new() + { + { "1", GetCombatant("GNB", "DRK", "WAR", "PLD") }, + { "2", GetCombatant("GNB", "DRK", "WAR", "PLD") }, + { "3", GetCombatant("WHM", "AST", "SCH", "SGE") }, + { "4", GetCombatant("WHM", "AST", "SCH", "SGE") }, + { "5", GetCombatant("SAM", "DRG", "MNK", "NIN", "RPR", "VPR") }, + { "6", GetCombatant("SAM", "DRG", "MNK", "NIN", "RPR", "VPR") }, + { "7", GetCombatant("BLM", "SMN", "RDM", "PCT") }, + { "8", GetCombatant("DNC", "MCH", "BRD") }, + { "9", GetCombatant("SAM", "DRG", "MNK", "NIN", "RPR", "VPR") }, + { "10", GetCombatant("SAM", "DRG", "MNK", "NIN", "RPR", "VPR") }, + { "11", GetCombatant("BLM", "SMN", "RDM", "PCT") }, + { "12", GetCombatant("DNC", "MCH", "BRD") } + }; + + return new() { Encounter = Encounter.GetTestData(), - Combatants = Combatant.GetTestData() + Combatants = mockCombatants }; } + + private static Combatant GetCombatant(params string[] jobs) + { + Combatant combatant = Combatant.GetTestData(); + combatant.Job = Enum.Parse(jobs[IActData.Random.Next(jobs.Length)]); + return combatant; + } } } \ No newline at end of file diff --git a/LMeter/ACT/DataStructures/Combatant.cs b/LMeter/ACT/DataStructures/Combatant.cs index afc1eba..608c9f8 100644 --- a/LMeter/ACT/DataStructures/Combatant.cs +++ b/LMeter/ACT/DataStructures/Combatant.cs @@ -7,32 +7,45 @@ namespace LMeter.Act.DataStructures; -public class Combatant +public class Combatant : IActData { [JsonIgnore] - public static string[] TextTags { get; } = typeof(Combatant).GetFields().Select(x => $"[{x.Name.ToLower()}]").ToArray(); - - // TODO: move this to a global place so it can be shared between encounter and combatant - private static readonly Random _rand = new(); - private static readonly Dictionary _members = typeof(Combatant).GetMembers().ToDictionary((x) => x.Name.ToLower()); + public static string[] TextTags { get; } = + typeof(Combatant).GetMembers().Where(x => Attribute.IsDefined(x, typeof(TextTagAttribute))).Select(x => $"[{x.Name.ToLower()}]").ToArray(); + private static readonly Dictionary _textTagMembers = + typeof(Combatant).GetMembers().Where(x => Attribute.IsDefined(x, typeof(TextTagAttribute))).ToDictionary((x) => x.Name.ToLower()); + [JsonProperty("name")] public string OriginalName { get; set; } = string.Empty; public string? NameOverwrite { get; set; } = null; +// These have to be here because newtonsoft and overlayplugin suck +#pragma warning disable 0169 + [JsonProperty("ENCDPS")] + private readonly string? _encdps; + [JsonProperty("ENCHPS")] + private readonly string? _enchps; +#pragma warning restore 0169 + + [TextTag] [JsonIgnore] public string Name => NameOverwrite ?? OriginalName; + [TextTag] [JsonIgnore] public LazyString? Name_First; + [TextTag] [JsonIgnore] public LazyString? Name_Last; + [TextTag] [JsonIgnore] public string Rank = string.Empty; + [TextTag] [JsonProperty("Job")] [JsonConverter(typeof(JobConverter))] public Job Job { get; set; } @@ -40,79 +53,87 @@ public class Combatant [JsonIgnore] public LazyString? JobName; + [TextTag] [JsonProperty("duration")] public string DurationRaw { get; set; } = string.Empty; + [TextTag] [JsonIgnore] public LazyString? Duration; - + [TextTag] [JsonProperty("encdps")] [JsonConverter(typeof(LazyFloatConverter))] - public LazyFloat? EncDps { get; set; } - - [JsonProperty("dps")] - [JsonConverter(typeof(LazyFloatConverter))] public LazyFloat? Dps { get; set; } + [TextTag] [JsonProperty("damage")] [JsonConverter(typeof(LazyFloatConverter))] public LazyFloat? DamageTotal { get; set; } + [TextTag] [JsonProperty("damage%")] public string DamagePct { get; set; } = string.Empty; + [TextTag] [JsonProperty("crithit%")] public string CritHitPct { get; set; } = string.Empty; + [TextTag] [JsonProperty("DirectHitPct")] public string DirectHitPct { get; set; } = string.Empty; + [TextTag] [JsonProperty("CritDirectHitPct")] public string CritDirectHitPct { get; set; } = string.Empty; + [TextTag] [JsonProperty("enchps")] [JsonConverter(typeof(LazyFloatConverter))] - public LazyFloat? EncHps { get; set; } - - [JsonProperty("hps")] - [JsonConverter(typeof(LazyFloatConverter))] public LazyFloat? Hps { get; set; } + [TextTag] public LazyFloat? EffectiveHealing { get; set; } + [TextTag] [JsonProperty("healed")] [JsonConverter(typeof(LazyFloatConverter))] public LazyFloat? HealingTotal { get; set; } + [TextTag] [JsonProperty("healed%")] public string HealingPct { get; set; }= string.Empty; + [TextTag] [JsonProperty("overHeal")] [JsonConverter(typeof(LazyFloatConverter))] public LazyFloat? OverHeal { get; set; } + [TextTag] [JsonProperty("OverHealPct")] public string OverHealPct { get; set; }= string.Empty; + [TextTag] [JsonProperty("damagetaken")] [JsonConverter(typeof(LazyFloatConverter))] public LazyFloat? DamageTaken { get; set; } + [TextTag] [JsonProperty("deaths")] public string Deaths { get; set; }= string.Empty; + [TextTag] [JsonProperty("kills")] public string Kills { get; set; }= string.Empty; + [TextTag] [JsonProperty("maxhit")] public string MaxHit { get; set; } = string.Empty; - [JsonProperty("MAXHIT")] - private string _maxHit { get; set; } = string.Empty; - + [TextTag] public LazyString MaxHitName { get; set; } + [TextTag] public LazyFloat? MaxHitValue { get; set; } public Combatant() @@ -128,54 +149,31 @@ public Combatant() public string GetFormattedString(string format, string numberFormat) { - return TextTagFormatter.TextTagRegex.Replace(format, new TextTagFormatter(this, numberFormat, _members).Evaluate); - } - - public static Dictionary GetTestData() - { - Dictionary mockCombatants = new() - { - { "1", GetCombatant("GNB", "DRK", "WAR", "PLD") }, - { "2", GetCombatant("GNB", "DRK", "WAR", "PLD") }, - { "3", GetCombatant("WHM", "AST", "SCH", "SGE") }, - { "4", GetCombatant("WHM", "AST", "SCH", "SGE") }, - { "5", GetCombatant("SAM", "DRG", "MNK", "NIN", "RPR") }, - { "6", GetCombatant("SAM", "DRG", "MNK", "NIN", "RPR") }, - { "7", GetCombatant("BLM", "SMN", "RDM") }, - { "8", GetCombatant("DNC", "MCH", "BRD") }, - { "9", GetCombatant("SAM", "DRG", "MNK", "NIN", "RPR") }, - { "10", GetCombatant("SAM", "DRG", "MNK", "NIN", "RPR") }, - { "11", GetCombatant("BLM", "SMN", "RDM") }, - { "12", GetCombatant("DNC", "MCH", "BRD") } - }; - - return mockCombatants; + return TextTagFormatter.TextTagRegex.Replace(format, new TextTagFormatter(this, numberFormat, _textTagMembers).Evaluate); } - private static Combatant GetCombatant(params string[] jobs) + public static Combatant GetTestData() { - int damage = _rand.Next(212345); - int healing = _rand.Next(41234); + float damage = IActData.Random.Next(212345); + float healing = IActData.Random.Next(41234); return new Combatant() { OriginalName = "Firstname Lastname", DurationRaw = "00:30", - Job = Enum.Parse(jobs[_rand.Next(jobs.Length)]), + Job = (Job)IActData.Random.Next(Enum.GetNames(typeof(Job)).Length - 1) + 1, DamageTotal = new LazyFloat(damage.ToString()), Dps = new LazyFloat((damage / 30).ToString()), - EncDps = new LazyFloat((damage / 30).ToString()), HealingTotal = new LazyFloat(healing.ToString()), OverHeal = new LazyFloat(5000), Hps = new LazyFloat((healing / 30).ToString()), - EncHps = new LazyFloat((healing / 30).ToString()), - DamagePct = "100%", + DamagePct = IActData.Random.Next(100) + "%", HealingPct = "100%", - CritHitPct = "20%", - DirectHitPct = "25%", - CritDirectHitPct = "5%", + CritHitPct = $"{IActData.Random.Next(50)}%", + DirectHitPct = $"{IActData.Random.Next(50)}%", + CritDirectHitPct = $"{IActData.Random.Next(10)}%", DamageTaken = new LazyFloat((damage / 20).ToString()), - Deaths = _rand.Next(2).ToString(), + Deaths = IActData.Random.Next(4).ToString(), MaxHit = "Full Thrust-42069" }; } diff --git a/LMeter/ACT/DataStructures/Encounter.cs b/LMeter/ACT/DataStructures/Encounter.cs index e75e578..f247641 100644 --- a/LMeter/ACT/DataStructures/Encounter.cs +++ b/LMeter/ACT/DataStructures/Encounter.cs @@ -6,51 +6,71 @@ namespace LMeter.Act.DataStructures; -public class Encounter +public class Encounter : IActData { [JsonIgnore] - public static string[] TextTags { get; } = typeof(Encounter).GetFields().Select(x => $"[{x.Name.ToLower()}]").ToArray(); + public static string[] TextTags { get; } = + typeof(Encounter).GetMembers().Where(x => Attribute.IsDefined(x, typeof(TextTagAttribute))).Select(x => $"[{x.Name.ToLower()}]").ToArray(); - private static readonly Random _rand = new(); - private static readonly Dictionary _members = typeof(Encounter).GetMembers().ToDictionary((x) => x.Name.ToLower()); + private static readonly Dictionary _textTagMembers = + typeof(Encounter).GetMembers().Where(x => Attribute.IsDefined(x, typeof(TextTagAttribute))).ToDictionary((x) => x.Name.ToLower()); public string GetFormattedString(string format, string numberFormat) { - return TextTagFormatter.TextTagRegex.Replace(format, new TextTagFormatter(this, numberFormat, _members).Evaluate); + return TextTagFormatter.TextTagRegex.Replace(format, new TextTagFormatter(this, numberFormat, _textTagMembers).Evaluate); } + +// These have to be here because newtonsoft and overlayplugin suck +#pragma warning disable 0169 + [JsonProperty("ENCDPS")] + private readonly string? _encdps; + [JsonProperty("ENCHPS")] + private readonly string? _enchps; +#pragma warning restore 0169 + + [TextTag] [JsonProperty("title")] public string Title { get; set; } = string.Empty; + [TextTag] [JsonProperty("duration")] public string DurationRaw { get; set; } = string.Empty; + [TextTag] [JsonIgnore] public LazyString? Duration; + [TextTag] [JsonProperty("encdps")] [JsonConverter(typeof(LazyFloatConverter))] public LazyFloat? Dps { get; set; } + [TextTag] [JsonProperty("damage")] [JsonConverter(typeof(LazyFloatConverter))] public LazyFloat? DamageTotal { get; set; } + [TextTag] [JsonProperty("enchps")] [JsonConverter(typeof(LazyFloatConverter))] public LazyFloat? Hps { get; set; } + [TextTag] [JsonProperty("healed")] [JsonConverter(typeof(LazyFloatConverter))] public LazyFloat? HealingTotal { get; set; } + [TextTag] [JsonProperty("damagetaken")] [JsonConverter(typeof(LazyFloatConverter))] public LazyFloat? DamageTaken { get; set; } + [TextTag] [JsonProperty("deaths")] public string? Deaths { get; set; } + [TextTag] [JsonProperty("kills")] public string? Kills { get; set; } @@ -61,8 +81,8 @@ public Encounter() public static Encounter GetTestData() { - float damage = _rand.Next(212345 * 8); - float healing = _rand.Next(41234 * 8); + float damage = IActData.Random.Next(212345 * 12); + float healing = IActData.Random.Next(41234 * 12); return new Encounter() { diff --git a/LMeter/ACT/DataStructures/IActData.cs b/LMeter/ACT/DataStructures/IActData.cs new file mode 100644 index 0000000..244ee47 --- /dev/null +++ b/LMeter/ACT/DataStructures/IActData.cs @@ -0,0 +1,14 @@ +using System; + +namespace LMeter.Act.DataStructures +{ + public interface IActData + { + static readonly Random Random = new(); + + static abstract string[] TextTags { get; } + static abstract T GetTestData(); + + string GetFormattedString(string format, string numberFormat); + } +} \ No newline at end of file diff --git a/LMeter/ACT/LazyFloat.cs b/LMeter/ACT/LazyFloat.cs index 63d3f46..4db4636 100644 --- a/LMeter/ACT/LazyFloat.cs +++ b/LMeter/ACT/LazyFloat.cs @@ -8,35 +8,34 @@ public class LazyFloat private readonly Func? _getStringInput; private readonly Func? _getFloatInput; private float _value = 0; + private string? _input; - public string? Input { get; private set; } - - public bool WasGenerated { get; private set; } + public bool Generated { get; private set; } public float Value { get { - if (this.WasGenerated) + if (this.Generated) { return _value; } - if (this.Input is null) + if (_input is null) { if (_getFloatInput is not null) { _value = _getFloatInput.Invoke(); - this.WasGenerated = true; + this.Generated = true; return _value; } else if (_getStringInput is not null) { - this.Input = _getStringInput.Invoke(); + _input = _getStringInput.Invoke(); } } - if (float.TryParse(this.Input, NumberStyles.Float, CultureInfo.InvariantCulture, out float parsed) && + if (float.TryParse(_input, NumberStyles.Float, CultureInfo.InvariantCulture, out float parsed) && !float.IsNaN(parsed)) { _value = parsed; @@ -46,20 +45,20 @@ public float Value _value = 0; } - this.WasGenerated = true; + this.Generated = true; return _value; } } public LazyFloat(string? input) { - this.Input = input; + _input = input; } public LazyFloat(float value) { _value = value; - this.WasGenerated = true; + this.Generated = true; } public LazyFloat(Func input) @@ -77,11 +76,9 @@ public LazyFloat(Func input) return this.Value.ToString(); } - public string? ToString(string format, bool kilo) => kilo switch - { - true => KiloFormat(this.Value, format), - false => this.Value.ToString(format, CultureInfo.InvariantCulture) - }; + public string? ToString(string format, bool kilo) => kilo + ? KiloFormat(this.Value, format) + : this.Value.ToString(format, CultureInfo.InvariantCulture); private static string KiloFormat(float num, string format) => num switch { diff --git a/LMeter/ACT/LazyFloatConverter.cs b/LMeter/ACT/LazyFloatConverter.cs index 84392bb..ac384a3 100644 --- a/LMeter/ACT/LazyFloatConverter.cs +++ b/LMeter/ACT/LazyFloatConverter.cs @@ -26,12 +26,12 @@ public override void WriteJson(JsonWriter writer, object? value, JsonSerializer return serializer.Deserialize(reader, objectType); } - if (reader.TokenType != JsonToken.String) + return reader.TokenType switch { - return new LazyFloat(0f); - } - - return new LazyFloat(serializer.Deserialize(reader, typeof(string))?.ToString()); + JsonToken.Float or JsonToken.Integer => serializer.Deserialize(reader), + JsonToken.String => new LazyFloat(serializer.Deserialize(reader)), + _ => new LazyFloat(0f) + }; } } } \ No newline at end of file diff --git a/LMeter/ACT/LazyString.cs b/LMeter/ACT/LazyString.cs index c0ee79f..fc769e6 100644 --- a/LMeter/ACT/LazyString.cs +++ b/LMeter/ACT/LazyString.cs @@ -3,11 +3,11 @@ namespace LMeter.Act { - public class LazyString + public class LazyString(Func getInput, Func converter) { private string _value = string.Empty; - private readonly Func _converter; - private readonly Func _getInput; + private readonly Func _converter = converter; + private readonly Func _getInput = getInput; public bool WasGenerated { get; private set; } @@ -26,12 +26,6 @@ public string Value } } - public LazyString(Func getInput, Func converter) - { - _getInput = getInput; - _converter = converter; - } - public override string? ToString() { return this.Value; @@ -148,6 +142,7 @@ public static string MaxHitValue(string? input) Job.NIN => "Ninja", Job.SAM => "Samurai", Job.RPR => "Reaper", + Job.VPR => "Viper", Job.ARC => "Archer", Job.BRD => "Bard", @@ -159,6 +154,7 @@ public static string MaxHitValue(string? input) Job.BLM => "Black Mage", Job.SMN => "Summoner", Job.RDM => "Red Mage", + Job.PCT => "Pictomancer", Job.BLU => "Blue Mage", Job.CRP => "Carpenter", diff --git a/LMeter/ACT/LogClient.cs b/LMeter/ACT/LogClient.cs index 839aa72..8cb9565 100644 --- a/LMeter/ACT/LogClient.cs +++ b/LMeter/ACT/LogClient.cs @@ -11,25 +11,18 @@ namespace LMeter.Act { - public abstract class LogClient : IPluginDisposable + public abstract class LogClient(ActConfig config) : IPluginDisposable { protected const string SubscriptionMessage = "{\"call\":\"subscribe\",\"events\":[\"CombatData\"]}"; - protected ActConfig Config { get; set; } + protected ActConfig Config { get; set; } = config; - public ConnectionStatus Status { get; protected set; } - public List PastEvents { get; protected init; } + public ConnectionStatus Status { get; protected set; } = ConnectionStatus.NotConnected; + public List PastEvents { get; protected init; } = []; private ActEvent? _lastEvent; private ActEvent? _currentEvent; - public LogClient(ActConfig config) - { - this.Config = config; - this.Status = ConnectionStatus.NotConnected; - this.PastEvents = []; - } - public abstract void Start(); public abstract void Shutdown(); public abstract void Reset(); diff --git a/LMeter/ACT/TextTagAttribute.cs b/LMeter/ACT/TextTagAttribute.cs new file mode 100644 index 0000000..caa4be3 --- /dev/null +++ b/LMeter/ACT/TextTagAttribute.cs @@ -0,0 +1,10 @@ +using System; + +namespace LMeter.Act +{ + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] + public class TextTagAttribute(string tagName = "") : Attribute + { + string TagName { get; } = tagName; + } +} \ No newline at end of file diff --git a/LMeter/ACT/TextTagFormatter.cs b/LMeter/ACT/TextTagFormatter.cs index 4f1bc86..1c3301f 100644 --- a/LMeter/ACT/TextTagFormatter.cs +++ b/LMeter/ACT/TextTagFormatter.cs @@ -5,25 +5,18 @@ namespace LMeter.Act { - public partial class TextTagFormatter + public partial class TextTagFormatter( + object source, + string format, + Dictionary members) { [GeneratedRegex(@"\[(\w*)(:k)?\.?(\d+)?\]", RegexOptions.Compiled)] private static partial Regex GeneratedRegex(); public static Regex TextTagRegex { get; } = GeneratedRegex(); - private readonly string _format; - private readonly Dictionary _members; - private readonly object _source; - - public TextTagFormatter( - object source, - string format, - Dictionary members) - { - _source = source; - _format = format; - _members = members; - } + private readonly object _source = source; + private readonly string _format = format; + private readonly Dictionary _members = members; public string Evaluate(Match m) { @@ -32,37 +25,30 @@ public string Evaluate(Match m) return m.Value; } - string format = string.IsNullOrEmpty(m.Groups[3].Value) - ? $"{_format}0" - : $"{_format}{m.Groups[3].Value}"; - - string? value = null; string key = m.Groups[1].Value; - if (!_members.TryGetValue(key, out MemberInfo? memberInfo)) { - return value ?? m.Value; + return m.Value; } object? memberValue = memberInfo?.MemberType switch { MemberTypes.Field => ((FieldInfo)memberInfo).GetValue(_source), MemberTypes.Property => ((PropertyInfo)memberInfo).GetValue(_source), - // Default should null because we don't want people accidentally trying to access a method and then throw an exception _ => null }; - if (memberValue is null) - { - return string.Empty; - } - + string? value = null; if (memberValue is LazyFloat lazyFloat) { + string format = string.IsNullOrEmpty(m.Groups[3].Value) + ? $"{_format}0" + : $"{_format}{m.Groups[3].Value}"; + bool kilo = !string.IsNullOrEmpty(m.Groups[2].Value); value = lazyFloat.ToString(format, kilo) ?? m.Value; } - else + else if (memberValue is not null) { value = memberValue.ToString(); if (!string.IsNullOrEmpty(value) && diff --git a/LMeter/ACT/WebSocketClient.cs b/LMeter/ACT/WebSocketClient.cs index a876593..e67e25e 100644 --- a/LMeter/ACT/WebSocketClient.cs +++ b/LMeter/ACT/WebSocketClient.cs @@ -10,18 +10,12 @@ namespace LMeter.Act { - public class WebSocketClient : LogClient + public class WebSocketClient(ActConfig config) : LogClient(config) { - private ClientWebSocket _socket; - private CancellationTokenSource _cancellationTokenSource; + private ClientWebSocket _socket = new ClientWebSocket(); + private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private Task? _receiveTask; - public WebSocketClient(ActConfig config) : base(config) - { - _socket = new ClientWebSocket(); - _cancellationTokenSource = new CancellationTokenSource(); - } - public override void Start() { if (this.Status != ConnectionStatus.NotConnected) diff --git a/LMeter/Config/AboutPage.cs b/LMeter/Config/AboutPage.cs index 81627a1..490860e 100644 --- a/LMeter/Config/AboutPage.cs +++ b/LMeter/Config/AboutPage.cs @@ -1,4 +1,5 @@ using System.Numerics; +using System.Text.Json.Serialization; using ImGuiNET; using LMeter.Helpers; @@ -6,35 +7,39 @@ namespace LMeter.Config { public class AboutPage : IConfigPage { + [JsonIgnore] + public bool Active { get; set; } + public string Name => "Changelog"; public IConfigPage GetDefault() => new AboutPage(); - public void DrawConfig(Vector2 size, float padX, float padY) + public void DrawConfig(Vector2 size, float padX, float padY, bool border = true) { - if (ImGui.BeginChild("##AboutPage", new Vector2(size.X, size.Y), true)) + if (ImGui.BeginChild("##AboutPage", new Vector2(size.X, size.Y), border)) { Vector2 headerSize = Vector2.Zero; - if (Plugin.IconTexture is not null) - { - Vector2 iconSize = new(Plugin.IconTexture.Width, Plugin.IconTexture.Height); - string versionText = $"LMeter v{Plugin.Version}"; - Vector2 textSize = ImGui.CalcTextSize(versionText); - headerSize = new Vector2(size.X, iconSize.Y + textSize.Y); + // if (Plugin.IconTexture is not null) + // { + // Vector2 iconSize = new(Plugin.IconTexture.Width, Plugin.IconTexture.Height); + // string versionText = $"LMeter v{Plugin.Version}"; + // Vector2 textSize = ImGui.CalcTextSize(versionText); + // headerSize = new Vector2(size.X, iconSize.Y + textSize.Y); - if (ImGui.BeginChild("##Icon", headerSize, false)) - { - ImDrawListPtr drawList = ImGui.GetWindowDrawList(); - Vector2 pos = ImGui.GetWindowPos().AddX(size.X / 2 - iconSize.X / 2); - drawList.AddImage(Plugin.IconTexture.ImGuiHandle, pos, pos + iconSize); - Vector2 textPos = ImGui.GetWindowPos().AddX(size.X / 2 - textSize.X / 2).AddY(iconSize.Y); - drawList.AddText(textPos, 0xFFFFFFFF, versionText); - ImGui.End(); - } - } + // if (ImGui.BeginChild("##Icon", headerSize, false)) + // { + // ImDrawListPtr drawList = ImGui.GetWindowDrawList(); + // Vector2 pos = ImGui.GetWindowPos().AddX(size.X / 2 - iconSize.X / 2); + // drawList.AddImage(Plugin.IconTexture.ImGuiHandle, pos, pos + iconSize); + // Vector2 textPos = ImGui.GetWindowPos().AddX(size.X / 2 - textSize.X / 2).AddY(iconSize.Y); + // drawList.AddText(textPos, 0xFFFFFFFF, versionText); + // ImGui.End(); + // } + // } - ImGui.SetCursorPosY(ImGui.GetCursorPosY() + headerSize.Y); - DrawHelpers.DrawSpacing(1); + // ImGui.SetCursorPosY(ImGui.GetCursorPosY() + headerSize.Y); + // DrawHelpers.DrawSpacing(1); + ImGui.Text("Changelog"); Vector2 changeLogSize = new(size.X - padX * 2, size.Y - ImGui.GetCursorPosY() - padY - 30); @@ -58,9 +63,9 @@ public void DrawConfig(Vector2 size, float padX, float padY) } ImGui.SameLine(); - if (ImGui.Button("Discord", buttonSize)) + if (ImGui.Button("Ko-fi", buttonSize)) { - Utils.OpenUrl("https://discord.gg/delvui"); + Utils.OpenUrl("https://ko-fi.com/lichie"); } ImGui.PopStyleVar(); diff --git a/LMeter/Config/ActConfig.cs b/LMeter/Config/ActConfig.cs index af72caf..a72b25d 100644 --- a/LMeter/Config/ActConfig.cs +++ b/LMeter/Config/ActConfig.cs @@ -19,10 +19,10 @@ public class ActConfig : IConfigPage [JsonIgnore] private DateTime? LastReconnectAttempt { get; set; } - public string Name => "ACT"; - - public IConfigPage GetDefault() => new ActConfig(); + [JsonIgnore] + public bool Active { get; set; } + public string Name => "ACT"; public string ActSocketAddress; public int EncounterHistorySize = 15; public bool AutoReconnect = false; @@ -37,9 +37,11 @@ public ActConfig() this.ActSocketAddress = _defaultSocketAddress; } - public void DrawConfig(Vector2 size, float padX, float padY) + public IConfigPage GetDefault() => new ActConfig(); + + public void DrawConfig(Vector2 size, float padX, float padY, bool border = true) { - if (ImGui.BeginChild($"##{this.Name}", new Vector2(size.X, size.Y), true)) + if (ImGui.BeginChild($"##{this.Name}", new Vector2(size.X, size.Y), border)) { int currentClientType = this.ClientType; ImGui.Text("ACT Client Type:"); diff --git a/LMeter/Config/BarColorsConfig.cs b/LMeter/Config/BarColorsConfig.cs index 47f2247..c3543de 100644 --- a/LMeter/Config/BarColorsConfig.cs +++ b/LMeter/Config/BarColorsConfig.cs @@ -1,4 +1,5 @@ using System.Numerics; +using System.Text.Json.Serialization; using ImGuiNET; using LMeter.Helpers; @@ -6,6 +7,9 @@ namespace LMeter.Config { public class BarColorsConfig : IConfigPage { + [JsonIgnore] + public bool Active { get; set; } + public string Name => "Colors"; public IConfigPage GetDefault() => new BarColorsConfig(); @@ -88,142 +92,52 @@ public class BarColorsConfig : IConfigPage _ => this.UKNColor }; - public void DrawConfig(Vector2 size, float padX, float padY) + public void DrawConfig(Vector2 size, float padX, float padY, bool border = true) { - if (ImGui.BeginChild($"##{this.Name}", new Vector2(size.X, size.Y), true)) + if (ImGui.BeginChild($"##{this.Name}", new Vector2(size.X, size.Y), border)) { - Vector4 vector = PLDColor.Vector; - ImGui.ColorEdit4("PLD", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.PLDColor.Vector = vector; - - vector = WARColor.Vector; - ImGui.ColorEdit4("WAR", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.WARColor.Vector = vector; - vector = DRKColor.Vector; - ImGui.ColorEdit4("DRK", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.DRKColor.Vector = vector; - - vector = GNBColor.Vector; - ImGui.ColorEdit4("GNB", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.GNBColor.Vector = vector; - + DrawHelpers.DrawColorSelector("PLD", ref this.PLDColor); + DrawHelpers.DrawColorSelector("WAR", ref this.WARColor); + DrawHelpers.DrawColorSelector("DRK", ref this.DRKColor); + DrawHelpers.DrawColorSelector("GNB", ref this.GNBColor); ImGui.NewLine(); - - vector = SCHColor.Vector; - ImGui.ColorEdit4("SCH", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.SCHColor.Vector = vector; - - vector = WHMColor.Vector; - ImGui.ColorEdit4("WHM", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.WHMColor.Vector = vector; - - vector = ASTColor.Vector; - ImGui.ColorEdit4("AST", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.ASTColor.Vector = vector; - - vector = SGEColor.Vector; - ImGui.ColorEdit4("SGE", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.SGEColor.Vector = vector; - + + DrawHelpers.DrawColorSelector("SCH", ref this.SCHColor); + DrawHelpers.DrawColorSelector("WHM", ref this.WHMColor); + DrawHelpers.DrawColorSelector("AST", ref this.ASTColor); + DrawHelpers.DrawColorSelector("SGE", ref this.SGEColor); ImGui.NewLine(); - vector = MNKColor.Vector; - ImGui.ColorEdit4("MNK", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.MNKColor.Vector = vector; - - vector = NINColor.Vector; - ImGui.ColorEdit4("NIN", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.NINColor.Vector = vector; - - vector = DRGColor.Vector; - ImGui.ColorEdit4("DRG", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.DRGColor.Vector = vector; - - vector = SAMColor.Vector; - ImGui.ColorEdit4("SAM", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.SAMColor.Vector = vector; - - vector = RPRColor.Vector; - ImGui.ColorEdit4("RPR", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.RPRColor.Vector = vector; - - vector = VPRColor.Vector; - ImGui.ColorEdit4("VPR", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.VPRColor.Vector = vector; - + DrawHelpers.DrawColorSelector("MNK", ref this.MNKColor); + DrawHelpers.DrawColorSelector("NIN", ref this.NINColor); + DrawHelpers.DrawColorSelector("DRG", ref this.DRGColor); + DrawHelpers.DrawColorSelector("SAM", ref this.SAMColor); + DrawHelpers.DrawColorSelector("RPR", ref this.RPRColor); + DrawHelpers.DrawColorSelector("VPR", ref this.VPRColor); ImGui.NewLine(); - vector = BRDColor.Vector; - ImGui.ColorEdit4("BRD", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.BRDColor.Vector = vector; - - vector = MCHColor.Vector; - ImGui.ColorEdit4("MCH", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.MCHColor.Vector = vector; - - vector = DNCColor.Vector; - ImGui.ColorEdit4("DNC", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.DNCColor.Vector = vector; - + DrawHelpers.DrawColorSelector("BRD", ref this.BRDColor); + DrawHelpers.DrawColorSelector("MCH", ref this.MCHColor); + DrawHelpers.DrawColorSelector("DNC", ref this.DNCColor); ImGui.NewLine(); - vector = BLMColor.Vector; - ImGui.ColorEdit4("BLM", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.BLMColor.Vector = vector; - - vector = SMNColor.Vector; - ImGui.ColorEdit4("SMN", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.SMNColor.Vector = vector; - - vector = RDMColor.Vector; - ImGui.ColorEdit4("RDM", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.RDMColor.Vector = vector; - - vector = PCTColor.Vector; - ImGui.ColorEdit4("PCT", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.PCTColor.Vector = vector; - - vector = BLUColor.Vector; - ImGui.ColorEdit4("BLU", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.BLUColor.Vector = vector; + DrawHelpers.DrawColorSelector("BLM", ref this.BLMColor); + DrawHelpers.DrawColorSelector("SMN", ref this.SMNColor); + DrawHelpers.DrawColorSelector("RDM", ref this.RDMColor); + DrawHelpers.DrawColorSelector("PCT", ref this.PCTColor); + DrawHelpers.DrawColorSelector("BLU", ref this.BLUColor); ImGui.NewLine(); - - vector = GLAColor.Vector; - ImGui.ColorEdit4("GLA", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.GLAColor.Vector = vector; - - vector = MRDColor.Vector; - ImGui.ColorEdit4("MRD", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.MRDColor.Vector = vector; - - vector = CNJColor.Vector; - ImGui.ColorEdit4("CNJ", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.CNJColor.Vector = vector; - - vector = PGLColor.Vector; - ImGui.ColorEdit4("PGL", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.PGLColor.Vector = vector; - - vector = ROGColor.Vector; - ImGui.ColorEdit4("ROG", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.ROGColor.Vector = vector; - - vector = LNCColor.Vector; - ImGui.ColorEdit4("LNC", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.LNCColor.Vector = vector; - - vector = ARCColor.Vector; - ImGui.ColorEdit4("ARC", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.ARCColor.Vector = vector; - - vector = THMColor.Vector; - ImGui.ColorEdit4("THM", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.THMColor.Vector = vector; - - vector = ACNColor.Vector; - ImGui.ColorEdit4("ACN", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.ACNColor.Vector = vector; + + DrawHelpers.DrawColorSelector("GLA", ref this.GLAColor); + DrawHelpers.DrawColorSelector("MRD", ref this.MRDColor); + DrawHelpers.DrawColorSelector("CNJ", ref this.CNJColor); + DrawHelpers.DrawColorSelector("PGL", ref this.PGLColor); + DrawHelpers.DrawColorSelector("ROG", ref this.ROGColor); + DrawHelpers.DrawColorSelector("LNC", ref this.LNCColor); + DrawHelpers.DrawColorSelector("ARC", ref this.ARCColor); + DrawHelpers.DrawColorSelector("THM", ref this.THMColor); + DrawHelpers.DrawColorSelector("ACN", ref this.ACNColor); } ImGui.EndChild(); diff --git a/LMeter/Config/BarConfig.cs b/LMeter/Config/BarConfig.cs index 1f0e188..c1714ce 100644 --- a/LMeter/Config/BarConfig.cs +++ b/LMeter/Config/BarConfig.cs @@ -1,28 +1,29 @@ -using System; using System.Numerics; -using System.Runtime.CompilerServices; +using System.Text.Json.Serialization; using ImGuiNET; -using LMeter.Act.DataStructures; using LMeter.Helpers; -using Newtonsoft.Json; namespace LMeter.Config { public class BarConfig : IConfigPage { [JsonIgnore] - private static readonly string[] _anchorOptions = Enum.GetNames(typeof(DrawAnchor)); - + public bool Active { get; set; } public string Name => "Bars"; private static readonly string[] _jobIconStyleOptions = ["Style 1", "Style 2"]; + public int BarHeightType = 0; public int BarCount = 8; public int BarGaps = 1; + public float BarHeight = 25; public bool ShowJobIcon = true; + public int JobIconSizeType = 0; + public Vector2 JobIconSize = new(25, 25); public int JobIconStyle = 0; public Vector2 JobIconOffset = new(0, 0); + public ConfigColor JobIconBackgroundColor = new(0, 0, 0, 0); public bool ThousandsSeparators = true; @@ -51,7 +52,7 @@ public class BarConfig : IConfigPage public int BarNameFontId = 0; public bool UseCharacterName = false; - public string RightTextFormat = "[damagetotal:k.1] ([encdps:k.1], [damagepct])"; + public string RightTextFormat = "[damagetotal:k.1] ([dps:k.1], [damagepct])"; public Vector2 RightTextOffset = new(0, 0); public bool RightTextJobColor = false; public ConfigColor BarDataColor = new(1, 1, 1, 1); @@ -60,6 +61,21 @@ public class BarConfig : IConfigPage public string BarDataFontKey = FontsManager.DalamudFontKey; public int BarDataFontId = 0; + public bool ShowColumnHeader; + public float ColumnHeaderHeight = 25; + public ConfigColor ColumnHeaderColor = new(0, 0, 0, 0.5f); + public bool UseColumnFont = true; + public ConfigColor ColumnHeaderTextColor = new(1, 1, 1, 1); + public bool ColumnHeaderShowOutline = true; + public ConfigColor ColumnHeaderOutlineColor = new(0, 0, 0, 0.5f); + public Vector2 ColumnHeaderOffset = new(); + public string ColumnHeaderFontKey = FontsManager.DalamudFontKey; + public int ColumnHeaderFontId = 0; + + public float BarFillHeight = 1f; + public ConfigColor BarBackgroundColor = new(.3f, .3f, .3f, 1f); + public int BarFillDirection = 0; + public IConfigPage GetDefault() { BarConfig defaultConfig = new() @@ -77,259 +93,102 @@ public IConfigPage GetDefault() return defaultConfig; } - public Vector2 DrawBar( - ImDrawListPtr drawList, - Vector2 localPos, - Vector2 size, - Combatant combatant, - ConfigColor jobColor, - ConfigColor barColor, - float top, - float current) + public void DrawConfig(Vector2 size, float padX, float padY, bool border = true) { - float barHeight = (size.Y - (this.BarCount - 1) * this.BarGaps) / this.BarCount; - Vector2 barSize = new(size.X, barHeight); - Vector2 barFillSize = new(size.X * (current / top), barHeight); - drawList.AddRectFilled(localPos, localPos + barFillSize, this.UseJobColor ? jobColor.Base : barColor.Base); - - float textOffset = 5f; - if (this.ShowJobIcon && combatant.Job != Job.UKN) + if (ImGui.BeginChild($"##{this.Name}", new Vector2(size.X, size.Y), border)) { - uint jobIconId = 62000u + (uint)combatant.Job + 100u * (uint)this.JobIconStyle; - Vector2 jobIconSize = Vector2.One * barHeight; - DrawHelpers.DrawIcon(jobIconId, localPos + this.JobIconOffset, jobIconSize, drawList); - textOffset = barHeight; - } + ImGui.Text("Bar Height Type"); + ImGui.RadioButton("Constant Bar Number", ref this.BarHeightType, 0); + ImGui.SameLine(); + ImGui.RadioButton("Constant Bar Height", ref this.BarHeightType, 1); - if (this.ShowRankText) - { - string rankText = combatant.GetFormattedString($"{this.RankTextFormat}", this.ThousandsSeparators ? "N" : "F"); - using (FontsManager.PushFont(this.RankTextFontKey)) + if (this.BarHeightType == 0) { - textOffset += ImGui.CalcTextSize("00.").X; - Vector2 rankTextSize = ImGui.CalcTextSize(rankText); - Vector2 rankTextPos = Utils.GetAnchoredPosition(localPos, -barSize, DrawAnchor.Left); - rankTextPos = Utils.GetAnchoredPosition(rankTextPos, rankTextSize, this.RankTextAlign) + this.RankTextOffset; - DrawHelpers.DrawText( - drawList, - rankText, - rankTextPos.AddX(textOffset), - this.RankTextJobColor ? jobColor.Base : this.RankTextColor.Base, - this.RankTextShowOutline, - this.RankTextOutlineColor.Base); + ImGui.DragInt("Num Bars to Display", ref this.BarCount, 1, 1, 48); + } + else if (this.BarHeightType == 1) + { + ImGui.DragFloat("Bar Height", ref this.BarHeight, .1f, 1, 100); } - } - - using (FontsManager.PushFont(this.BarNameFontKey)) - { - string leftText = combatant.GetFormattedString($" {this.LeftTextFormat} ", this.ThousandsSeparators ? "N" : "F"); - Vector2 nameTextSize = ImGui.CalcTextSize(leftText); - Vector2 namePos = Utils.GetAnchoredPosition(localPos, -barSize, DrawAnchor.Left); - namePos = Utils.GetAnchoredPosition(namePos, nameTextSize, DrawAnchor.Left) + this.LeftTextOffset; - DrawHelpers.DrawText( - drawList, - leftText, - namePos.AddX(textOffset), - this.LeftTextJobColor ? jobColor.Base : this.BarNameColor.Base, - this.BarNameShowOutline, - this.BarNameOutlineColor.Base); - } - - using (FontsManager.PushFont(this.BarDataFontKey)) - { - string rightText = combatant.GetFormattedString($" {this.RightTextFormat} ", this.ThousandsSeparators ? "N" : "F"); - Vector2 dataTextSize = ImGui.CalcTextSize(rightText); - Vector2 dataPos = Utils.GetAnchoredPosition(localPos, -barSize, DrawAnchor.Right); - dataPos = Utils.GetAnchoredPosition(dataPos, dataTextSize, DrawAnchor.Right) + this.RightTextOffset; - DrawHelpers.DrawText( - drawList, - rightText, - dataPos, - this.RightTextJobColor ? jobColor.Base : this.BarDataColor.Base, - this.BarDataShowOutline, - this.BarDataOutlineColor.Base); - } - - return localPos.AddY(barHeight + this.BarGaps); - } - - public void DrawConfig(Vector2 size, float padX, float padY) - { - string[] fontOptions = FontsManager.GetFontList(); - if (fontOptions.Length == 0) - { - return; - } - if (ImGui.BeginChild($"##{this.Name}", new Vector2(size.X, size.Y), true)) - { - ImGui.DragInt("Num Bars to Display", ref this.BarCount, 1, 1, 48); ImGui.DragInt("Bar Gap Size", ref this.BarGaps, 1, 0, 20); + ImGui.NewLine(); + ImGui.DragFloat("Bar Fill Height (% of Bar Height)", ref this.BarFillHeight, .1f, 0, 1f); + ImGui.Combo("Bar Fill Direction", ref this.BarFillDirection, ["Up", "Down"], 2); + DrawHelpers.DrawColorSelector("Bar Background Color", ref this.BarBackgroundColor); + + ImGui.NewLine(); ImGui.Checkbox("Show Job Icon", ref this.ShowJobIcon); if (this.ShowJobIcon) { + DrawHelpers.DrawNestIndicator(1); + ImGui.SameLine(); + ImGui.RadioButton("Automatic Size", ref this.JobIconSizeType, 0); + ImGui.SameLine(); + ImGui.RadioButton("Manual Size", ref this.JobIconSizeType, 1); + + if (this.JobIconSizeType == 1) + { + DrawHelpers.DrawNestIndicator(1); + ImGui.DragFloat2("Size##JobIconSize", ref this.JobIconSize); + } + DrawHelpers.DrawNestIndicator(1); ImGui.DragFloat2("Job Icon Offset", ref this.JobIconOffset); DrawHelpers.DrawNestIndicator(1); ImGui.Combo("Job Icon Style", ref this.JobIconStyle, _jobIconStyleOptions, _jobIconStyleOptions.Length); + DrawHelpers.DrawNestIndicator(1); + DrawHelpers.DrawColorSelector("Background Color##JobIcon", ref this.JobIconBackgroundColor); } + ImGui.NewLine(); ImGui.Checkbox("Use Job Colors for Bars", ref this.UseJobColor); - Vector4 vector = Vector4.Zero; if (!this.UseJobColor) { DrawHelpers.DrawNestIndicator(1); - vector = this.BarColor.Vector; - ImGui.ColorEdit4("Bar Color", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.BarColor.Vector = vector; + DrawHelpers.DrawColorSelector("Bar Color", ref this.BarColor); } - ImGui.Checkbox("Use Thousands Separators for Numbers", ref this.ThousandsSeparators); + ImGui.Checkbox("Use your name instead of 'YOU'", ref this.UseCharacterName); + if (this.BarHeight == 0) + { + ImGui.Checkbox("Always show your own bar", ref this.AlwaysShowSelf); + } ImGui.NewLine(); - ImGui.Checkbox("Show Rank Text", ref this.ShowRankText); - if (this.ShowRankText) + ImGui.Checkbox("Show Column Header Bar", ref this.ShowColumnHeader); + if (this.ShowColumnHeader) { DrawHelpers.DrawNestIndicator(1); - ImGui.InputText("Rank Text Format", ref this.RankTextFormat, 128); - - if (ImGui.IsItemHovered()) - { - ImGui.SetTooltip(Utils.GetTagsTooltip(Combatant.TextTags)); - } + ImGui.DragFloat("Column Header Height", ref this.ColumnHeaderHeight); DrawHelpers.DrawNestIndicator(1); - ImGui.Combo("Rank Text Align", ref Unsafe.As(ref this.RankTextAlign), _anchorOptions, _anchorOptions.Length); + ImGui.DragFloat2("Text Offset", ref this.ColumnHeaderOffset); DrawHelpers.DrawNestIndicator(1); - ImGui.DragFloat2("Rank Text Offset", ref this.RankTextOffset); - - if (!FontsManager.ValidateFont(fontOptions, this.RankTextFontId, this.RankTextFontKey)) - { - this.RankTextFontId = 0; - for (int i = 0; i < fontOptions.Length; i++) - { - if (this.RankTextFontKey.Equals(fontOptions[i])) - { - this.RankTextFontId = i; - } - } - } + DrawHelpers.DrawColorSelector("Background Color", ref this.ColumnHeaderColor); DrawHelpers.DrawNestIndicator(1); - ImGui.Combo("Font##Rank", ref this.RankTextFontId, fontOptions, fontOptions.Length); - this.RankTextFontKey = fontOptions[this.RankTextFontId]; + DrawHelpers.DrawColorSelector("Text Color", ref this.ColumnHeaderTextColor); DrawHelpers.DrawNestIndicator(1); - ImGui.Checkbox("Use Job Color##RankTextJobColor", ref this.RankTextJobColor); - if (!this.RankTextJobColor) + ImGui.Checkbox("Use Font from Column", ref this.UseColumnFont); + if (!this.UseColumnFont) { DrawHelpers.DrawNestIndicator(2); - vector = this.RankTextColor.Vector; - ImGui.ColorEdit4("Text Color##Rank", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.RankTextColor.Vector = vector; + DrawHelpers.DrawFontSelector("Font##Column", ref this.ColumnHeaderFontKey, ref this.ColumnHeaderFontId); } DrawHelpers.DrawNestIndicator(1); - ImGui.Checkbox("Show Outline##Rank", ref this.RankTextShowOutline); - if (this.RankTextShowOutline) + ImGui.Checkbox("Show Outline", ref this.ColumnHeaderShowOutline); + if (this.ColumnHeaderShowOutline) { DrawHelpers.DrawNestIndicator(2); - vector = this.RankTextOutlineColor.Vector; - ImGui.ColorEdit4("Outline Color##Rank", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.RankTextOutlineColor.Vector = vector; - } - } - - ImGui.NewLine(); - ImGui.Checkbox("Use your name instead of 'YOU'", ref this.UseCharacterName); - ImGui.Checkbox("Always show your own bar", ref this.AlwaysShowSelf); - ImGui.InputText("Left Text Format", ref this.LeftTextFormat, 128); - - if (ImGui.IsItemHovered()) - { - ImGui.SetTooltip(Utils.GetTagsTooltip(Combatant.TextTags)); - } - - ImGui.DragFloat2("Left Text Offset", ref this.LeftTextOffset); - - if (!FontsManager.ValidateFont(fontOptions, this.BarNameFontId, this.BarNameFontKey)) - { - this.BarNameFontId = 0; - for (int i = 0; i < fontOptions.Length; i++) - { - if (this.BarNameFontKey.Equals(fontOptions[i])) - { - this.BarNameFontId = i; - } - } - } - - ImGui.Combo("Font##Name", ref this.BarNameFontId, fontOptions, fontOptions.Length); - this.BarNameFontKey = fontOptions[this.BarNameFontId]; - - ImGui.Checkbox("Use Job Color##LeftTextJobColor", ref this.LeftTextJobColor); - if (!this.LeftTextJobColor) - { - DrawHelpers.DrawNestIndicator(1); - vector = this.BarNameColor.Vector; - ImGui.ColorEdit4("Text Color##Name", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.BarNameColor.Vector = vector; - } - - ImGui.Checkbox("Show Outline##Name", ref this.BarNameShowOutline); - if (this.BarNameShowOutline) - { - DrawHelpers.DrawNestIndicator(1); - vector = this.BarNameOutlineColor.Vector; - ImGui.ColorEdit4("Outline Color##Name", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.BarNameOutlineColor.Vector = vector; - } - - ImGui.NewLine(); - ImGui.InputText("Right Text Format", ref this.RightTextFormat, 128); - - if (ImGui.IsItemHovered()) - { - ImGui.SetTooltip(Utils.GetTagsTooltip(Combatant.TextTags)); - } - - ImGui.DragFloat2("Right Text Offset", ref this.RightTextOffset); - - if (!FontsManager.ValidateFont(fontOptions, this.BarDataFontId, this.BarDataFontKey)) - { - this.BarDataFontId = 0; - for (int i = 0; i < fontOptions.Length; i++) - { - if (this.BarDataFontKey.Equals(fontOptions[i])) - { - this.BarDataFontId = i; - } + DrawHelpers.DrawColorSelector("Column Header Color", ref this.ColumnHeaderOutlineColor); } } - - ImGui.Combo("Font##Data", ref this.BarDataFontId, fontOptions, fontOptions.Length); - this.BarDataFontKey = fontOptions[this.BarDataFontId]; - - ImGui.Checkbox("Use Job Color##RightTextJobColor", ref this.RightTextJobColor); - if (!this.RightTextJobColor) - { - DrawHelpers.DrawNestIndicator(1); - vector = this.BarDataColor.Vector; - ImGui.ColorEdit4("Text Color##Data", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.BarDataColor.Vector = vector; - } - - ImGui.Checkbox("Show Outline##Data", ref this.BarDataShowOutline); - if (this.BarDataShowOutline) - { - DrawHelpers.DrawNestIndicator(1); - vector = this.BarDataOutlineColor.Vector; - ImGui.ColorEdit4("Outline Color##Data", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.BarDataOutlineColor.Vector = vector; - } } ImGui.EndChild(); diff --git a/LMeter/Config/BarTextConfig.cs b/LMeter/Config/BarTextConfig.cs new file mode 100644 index 0000000..e68e848 --- /dev/null +++ b/LMeter/Config/BarTextConfig.cs @@ -0,0 +1,385 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Numerics; +using System.Runtime.CompilerServices; +using Dalamud.Interface; +using Dalamud.Interface.ImGuiNotification; +using ImGuiNET; +using LMeter.Act.DataStructures; +using LMeter.Helpers; +using Newtonsoft.Json; + +namespace LMeter.Config +{ + public class TextListConfig(string name = "Texts") : IConfigPage where T : IActData + { + [JsonIgnore] + private string _textInput = string.Empty; + + [JsonIgnore] + private int _selectedIndex; + + [JsonIgnore] + public bool Active { get; set; } + + public string NameInternal = name; + public string Name => NameInternal; + + public bool Initialized = false; + public List Texts { get; init; } = []; + + public IConfigPage GetDefault() + { + return new TextListConfig() { NameInternal = this.NameInternal }; + } + + public void DrawConfig(Vector2 size, float padX, float padY, bool border = true) + { + + if (ImGui.BeginChild($"##TextListConfig", size, border)) + { + ImGui.Text(this.Name); + ImGuiTableFlags tableFlags = + ImGuiTableFlags.RowBg | + ImGuiTableFlags.Borders | + ImGuiTableFlags.BordersOuter | + ImGuiTableFlags.BordersInner | + ImGuiTableFlags.ScrollY | + ImGuiTableFlags.NoSavedSettings; + + if (ImGui.BeginTable($"##TextList_Table", 5, tableFlags, new Vector2(size.X - padX * 2, (size.Y - ImGui.GetCursorPosY() - padY * 2) / 3))) + { + Vector2 buttonSize = new(30, 0); + float actionsWidth = buttonSize.X * 3 + ImGui.GetStyle().ItemSpacing.X * 2; + float anchorComboWidth = 100f; + + ImGui.TableSetupColumn("Enabled", ImGuiTableColumnFlags.WidthFixed, 46, 0); + ImGui.TableSetupColumn("Text Name", ImGuiTableColumnFlags.WidthStretch, 0, 1); + ImGui.TableSetupColumn("Anchored To", ImGuiTableColumnFlags.WidthFixed, anchorComboWidth, 2); + ImGui.TableSetupColumn("Anchor Point", ImGuiTableColumnFlags.WidthFixed, anchorComboWidth, 3); + ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, actionsWidth, 4); + + ImGui.TableSetupScrollFreeze(0, 1); + ImGui.TableHeadersRow(); + + int i = 0; + for (; i < Texts.Count; i++) + { + ImGui.PushID(i.ToString()); + ImGui.TableNextRow(ImGuiTableRowFlags.None, 28); + + Text text = this.Texts[i]; + if (ImGui.TableSetColumnIndex(0)) + { + ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(11f, 1f)); + ImGui.Checkbox($"##Text_{i}_EnabledCheckbox", ref text.Enabled); + } + + if (ImGui.TableSetColumnIndex(1)) + { + ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 1f); + ImGui.Text(text.Name); + } + + if (ImGui.TableSetColumnIndex(2)) + { + string[] anchorOptions = ["Bar", .. this.Texts.Select(x => x.Name)]; + ImGui.PushItemWidth(anchorComboWidth); + ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 1f); + if (ImGui.Combo($"##Text_{i}_AnchorToCombo", ref text.AnchorParent, anchorOptions, anchorOptions.Length)) + { + // Check for circular dependency + int parent = text.AnchorParent; + Text t = this.Texts[Math.Clamp(parent - 1, 0, this.Texts.Count - 1)]; + for (int j = 0; j < this.Texts.Count; j++) + { + parent = t.AnchorParent; + if (parent == 0) + { + break; + } + + t = this.Texts[Math.Clamp(parent - 1, 0, this.Texts.Count - 1)]; + } + + if (parent != 0) + { + text.AnchorParent = 0; + DrawHelpers.DrawNotification( + $"Cannot Anchor to {this.Texts[parent - 1].Name}, anchor chain must eventually anchor to Bar.", + NotificationType.Error); + } + } + + ImGui.PopItemWidth(); + } + + if (ImGui.TableSetColumnIndex(3)) + { + ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 1f); + ImGui.PushItemWidth(anchorComboWidth); + ImGui.Combo($"##Text_{i}_AnchorPointCombo", ref Unsafe.As(ref text.AnchorPoint), Utils.AnchorOptions, Utils.AnchorOptions.Length); + + ImGui.PopItemWidth(); + } + + if (ImGui.TableSetColumnIndex(4)) + { + ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 1f); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Pen, () => SelectText(i), "Edit", buttonSize); + + ImGui.SameLine(); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Upload, () => ExportText(text), "Export", buttonSize); + + ImGui.SameLine(); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Trash, () => DeleteText(i), "Delete", buttonSize); + } + } + + ImGui.PushID((i + 1).ToString()); + ImGui.TableNextRow(ImGuiTableRowFlags.None, 28); + if (ImGui.TableSetColumnIndex(1)) + { + ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 1f); + ImGui.PushItemWidth(ImGui.GetColumnWidth()); + ImGui.InputTextWithHint($"##NewTextInput", "New Text Name", ref _textInput, 10000); + ImGui.PopItemWidth(); + } + + if (ImGui.TableSetColumnIndex(4)) + { + ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 1f); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Plus, () => AddText(_textInput), "Create Text", buttonSize); + + ImGui.SameLine(); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Download, () => ImportText(), "Import Text", buttonSize); + } + + ImGui.EndTable(); + } + + if (this.Texts.Count != 0) + { + ImGui.Text($"Edit {this.Texts[_selectedIndex].Name}"); + if (ImGui.BeginChild($"##SelectedText_Edit", new(size.X - padX * 2, size.Y - ImGui.GetCursorPosY() - padY * 2), true)) + { + this.Texts[_selectedIndex].DrawConfig(); + ImGui.EndChild(); + } + } + + ImGui.EndChild(); + } + } + + public void AddText(string name) + { + if (!string.IsNullOrEmpty(name)) + { + this.Texts.Add(new Text(name)); + } + + _textInput = string.Empty; + } + + public void AddText(Text text) + { + this.Texts.Add(text); + _selectedIndex = this.Texts.Count - 1; + } + + private void SelectText(int i) + { + _selectedIndex = i; + } + + private void ImportText() + { + string importString; + try + { + importString = ImGui.GetClipboardText(); + } + catch + { + DrawHelpers.DrawNotification("Failed to read from clipboard!", NotificationType.Error); + return; + } + + Text? newElement = ConfigHelpers.GetFromImportString(importString); + + if (newElement is Text text) + { + this.AddText(text); + } + else + { + DrawHelpers.DrawNotification("Failed to Import Element!", NotificationType.Error); + } + + _textInput = string.Empty; + } + + private void ExportText(Text text) + { + ConfigHelpers.ExportToClipboard(text); + } + + private void DeleteText(int index) + { + foreach (Text text in this.Texts) + { + if (text.AnchorParent - 1 == index) + { + DrawHelpers.DrawNotification( + $"Cannot delete {this.Texts[index].Name} while other texts are anchored to it.", + NotificationType.Error); + return; + } + } + + for (int i = 0; i < this.Texts.Count; i++) + { + if (this.Texts[i].AnchorParent > index) + { + this.Texts[i].AnchorParent -= 1; + } + } + + this.Texts.RemoveAt(index); + _selectedIndex = Math.Clamp(_selectedIndex, 0, this.Texts.Count - 1); + } + } + + public class Text(string name = "Text") + { + public string Name = name; + public bool Enabled = true; + public string TextFormat = ""; + public Vector2 TextOffset = new(); + public int AnchorParent = 0; + public DrawAnchor AnchorPoint = DrawAnchor.Left; + public DrawAnchor TextAlignment = DrawAnchor.Left; + public bool ThousandsSeparators = true; + public bool TextJobColor = false; + public ConfigColor TextColor = new(1, 1, 1, 1); + public bool ShowOutline = true; + public ConfigColor OutlineColor = new(0, 0, 0, 0.5f); + public string FontKey = FontsManager.DefaultSmallFontKey; + public int FontId = 0; + public bool FixedTextWidth; + public float TextWidth = 60; + public bool UseEllipsis = true; + public bool ShowSeparator = false; + public float SeparatorWidth = 2f; + public float SeparatorHeight = .75f; + public Vector2 SeparatorOffset = new(); + public ConfigColor SeparatorColor = new(0f, 0f, 0f, 0.5f); + public bool UseBackground = false; + public ConfigColor BackgroundColor = new(0f, 0f, 0f, 0.5f); + + public Text Clone() + { + // hot path so don't clone via serialization + return new() + { + Name = this.Name, + Enabled = this.Enabled, + TextFormat = this.TextFormat, + TextOffset = this.TextOffset, + AnchorParent = this.AnchorParent, + AnchorPoint = this.AnchorPoint, + TextAlignment = this.TextAlignment, + ThousandsSeparators = this.ThousandsSeparators, + TextJobColor = this.TextJobColor, + TextColor = this.TextColor, + ShowOutline = this.ShowOutline, + OutlineColor = this.OutlineColor, + FontKey = this.FontKey, + FontId = this.FontId, + FixedTextWidth = this.FixedTextWidth, + TextWidth = this.TextWidth, + UseEllipsis = this.UseEllipsis, + ShowSeparator = this.ShowSeparator, + SeparatorWidth = this.SeparatorWidth, + SeparatorHeight = this.SeparatorHeight, + SeparatorOffset = this.SeparatorOffset, + SeparatorColor = this.SeparatorColor, + UseBackground = this.UseBackground, + BackgroundColor = this.BackgroundColor + }; + } + + public void DrawConfig() where T : IActData + { + ImGui.InputText("Text Name", ref this.Name, 512); + ImGui.InputText("Text Format", ref this.TextFormat, 512); + + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip(Utils.GetTagsTooltip()); + } + + ImGui.SameLine(); + string? selectedTag = DrawHelpers.DrawTextTagsList(T.TextTags); + if (selectedTag is not null) + { + this.TextFormat += selectedTag; + } + + DrawHelpers.DrawFontSelector("Font##Name", ref this.FontKey, ref this.FontId); + ImGui.DragFloat2("Text Offset", ref this.TextOffset); + ImGui.Checkbox("Fixed Text Width", ref this.FixedTextWidth); + if (this.FixedTextWidth) + { + DrawHelpers.DrawNestIndicator(1); + ImGui.DragFloat("Text Width", ref this.TextWidth, .1f, 0f, 10000f); + DrawHelpers.DrawNestIndicator(1); + ImGui.Combo("Text Alignment", ref Unsafe.As(ref this.TextAlignment), Utils.AnchorOptions, Utils.AnchorOptions.Length); + DrawHelpers.DrawNestIndicator(1); + ImGui.Checkbox("Add ellipsis (...) to truncated text", ref this.UseEllipsis); + } + + ImGui.Checkbox("Use Thousands Separator for Numbers", ref this.ThousandsSeparators); + if (this.AnchorParent != 0) + { + ImGui.Checkbox("Show Anchor Separator", ref this.ShowSeparator); + if (this.ShowSeparator) + { + DrawHelpers.DrawNestIndicator(1); + ImGui.DragFloat("Height (% of Bar height)", ref this.SeparatorHeight, .1f, 0f, 1f); + DrawHelpers.DrawNestIndicator(1); + ImGui.DragFloat("Width", ref this.SeparatorWidth, .1f, 0f, 100f); + DrawHelpers.DrawNestIndicator(1); + ImGui.DragFloat2("Offset", ref this.SeparatorOffset); + DrawHelpers.DrawNestIndicator(1); + DrawHelpers.DrawColorSelector("Color", ref this.SeparatorColor); + } + } + + ImGui.NewLine(); + ImGui.Checkbox("Use Job Color", ref this.TextJobColor); + if (!this.TextJobColor) + { + DrawHelpers.DrawNestIndicator(1); + DrawHelpers.DrawColorSelector("Text Color", ref this.TextColor); + } + + ImGui.Checkbox("Show Outline", ref this.ShowOutline); + if (this.ShowOutline) + { + DrawHelpers.DrawNestIndicator(1); + DrawHelpers.DrawColorSelector("Outline Color", ref this.OutlineColor); + } + + ImGui.NewLine(); + ImGui.Checkbox("Use Custom Background Color", ref this.UseBackground); + if (this.UseBackground) + { + DrawHelpers.DrawNestIndicator(1); + DrawHelpers.DrawColorSelector("Background Color", ref this.BackgroundColor); + } + } + } +} diff --git a/LMeter/Config/FontConfig.cs b/LMeter/Config/FontConfig.cs index 0f731f4..30fe1bd 100644 --- a/LMeter/Config/FontConfig.cs +++ b/LMeter/Config/FontConfig.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Numerics; using Dalamud.Interface; @@ -11,14 +10,15 @@ namespace LMeter.Config { public class FontConfig : IConfigPage { + [JsonIgnore] + public bool Active { get; set; } + public string Name => "Fonts"; - public IConfigPage GetDefault() => new FontConfig(); - [JsonIgnore] private static readonly string? _fontPath = FontsManager.GetUserFontPath(); [JsonIgnore] private int _selectedFont = 0; [JsonIgnore] private int _selectedSize = 23; - [JsonIgnore] private string[] _fonts = FontsManager.GetFontNamesFromPath(FontsManager.GetUserFontPath()); + [JsonIgnore] private string[] _fontPaths = FontsManager.GetFontPaths(FontsManager.GetUserFontPath()); [JsonIgnore] private readonly string[] _sizes = Enumerable.Range(1, 40).Select(i => i.ToString()).ToArray(); [JsonIgnore] private bool _chinese = false; [JsonIgnore] private bool _korean = false; @@ -30,26 +30,22 @@ public FontConfig() RefreshFontList(); this.Fonts = []; - foreach (string fontKey in FontsManager.DefaultFontKeys) + foreach (FontData font in FontsManager.GetDefaultFontData()) { - string[] splits = fontKey.Split("_", StringSplitOptions.RemoveEmptyEntries); - if (splits.Length == 2 && int.TryParse(splits[1], out int size)) - { - FontData newFont = new(splits[0], size, false, false); - string key = FontsManager.GetFontKey(newFont); - this.Fonts.Add(key, newFont); - } + this.Fonts.Add(FontsManager.GetFontKey(font), font); } } - public void DrawConfig(Vector2 size, float padX, float padY) + public IConfigPage GetDefault() => new FontConfig(); + + public void DrawConfig(Vector2 size, float padX, float padY, bool border = true) { - if (_fonts.Length == 0) + if (_fontPaths.Length == 0) { RefreshFontList(); } - if (ImGui.BeginChild("##FontConfig", new Vector2(size.X, size.Y), true)) + if (ImGui.BeginChild("##FontConfig", new Vector2(size.X, size.Y), border)) { if (_fontPath is not null) { @@ -62,7 +58,8 @@ public void DrawConfig(Vector2 size, float padX, float padY) ImGui.SetCursorPosY(cursorY); DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Copy, () => ImGui.SetClipboardText(_fontPath), null, buttonSize); - ImGui.Combo("Font", ref _selectedFont, _fonts, _fonts.Length); + string[] fontNames = _fontPaths.Select(x => FontsManager.GetFontName(_fontPath, x)).ToArray(); + ImGui.Combo("Font", ref _selectedFont, fontNames, fontNames.Length); ImGui.SameLine(); DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Sync, () => RefreshFontList(), "Reload Font List", buttonSize); @@ -149,17 +146,16 @@ public void DrawConfig(Vector2 size, float padX, float padY) public void RefreshFontList() { - _fonts = FontsManager.GetFontNamesFromPath(FontsManager.GetUserFontPath()); + _fontPaths = FontsManager.GetFontPaths(FontsManager.GetUserFontPath()); } private void AddFont(int fontIndex, int size) { - FontData newFont = new(_fonts[fontIndex], size + 1, _chinese, _korean); + FontData newFont = new(FontsManager.GetFontName(_fontPath, _fontPaths[fontIndex]), _fontPaths[fontIndex], size + 1, _chinese, _korean); string key = FontsManager.GetFontKey(newFont); - if (!this.Fonts.ContainsKey(key)) + if (this.Fonts.TryAdd(key, newFont)) { - this.Fonts.Add(key, newFont); Singletons.Get().UpdateFonts(this.Fonts.Values); } } diff --git a/LMeter/Config/GeneralConfig.cs b/LMeter/Config/GeneralConfig.cs index 4f6da93..33c283a 100644 --- a/LMeter/Config/GeneralConfig.cs +++ b/LMeter/Config/GeneralConfig.cs @@ -14,11 +14,12 @@ public class GeneralConfig : IConfigPage [JsonIgnore] public bool Preview = false; - + + [JsonIgnore] + public bool Active { get; set; } + public string Name => "General"; - - public IConfigPage GetDefault() => new GeneralConfig(); - + public Vector2 Position = Vector2.Zero; public Vector2 Size = new(ImGui.GetMainViewport().Size.Y * 16 / 90, ImGui.GetMainViewport().Size.Y / 10); public bool Lock = false; @@ -31,9 +32,11 @@ public class GeneralConfig : IConfigPage public MeterDataType DataType = MeterDataType.Damage; public bool ReturnToCurrent = true; - public void DrawConfig(Vector2 size, float padX, float padY) + public IConfigPage GetDefault() => new GeneralConfig(); + + public void DrawConfig(Vector2 size, float padX, float padY, bool border = true) { - if (ImGui.BeginChild($"##{this.Name}", new Vector2(size.X, size.Y), true)) + if (ImGui.BeginChild($"##{this.Name}", new Vector2(size.X, size.Y), border)) { Vector2 screenSize = ImGui.GetMainViewport().Size; ImGui.DragFloat2("Position", ref this.Position, 1, -screenSize.X / 2, screenSize.X / 2); @@ -43,9 +46,7 @@ public void DrawConfig(Vector2 size, float padX, float padY) ImGui.Checkbox("Preview", ref this.Preview); ImGui.NewLine(); - Vector4 vector = this.BackgroundColor.Vector; - ImGui.ColorEdit4("Background Color", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.BackgroundColor.Vector = vector; + DrawHelpers.DrawColorSelector("Background Color", ref this.BackgroundColor); ImGui.Checkbox("Show Border", ref this.ShowBorder); if (this.ShowBorder) @@ -54,9 +55,7 @@ public void DrawConfig(Vector2 size, float padX, float padY) ImGui.DragInt("Border Thickness", ref this.BorderThickness, 1, 1, 20); DrawHelpers.DrawNestIndicator(1); - vector = this.BorderColor.Vector; - ImGui.ColorEdit4("Border Color", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.BorderColor.Vector = vector; + DrawHelpers.DrawColorSelector("Border Color", ref this.BorderColor); DrawHelpers.DrawNestIndicator(1); ImGui.Checkbox("Hide border around Header", ref this.BorderAroundBars); diff --git a/LMeter/Config/HeaderConfig.cs b/LMeter/Config/HeaderConfig.cs index 399b3e3..7fb150b 100644 --- a/LMeter/Config/HeaderConfig.cs +++ b/LMeter/Config/HeaderConfig.cs @@ -1,24 +1,25 @@ -using System; using System.Numerics; -using System.Runtime.CompilerServices; +using System.Text.Json.Serialization; using ImGuiNET; -using LMeter.Act.DataStructures; using LMeter.Helpers; -using Newtonsoft.Json; namespace LMeter.Config { public class HeaderConfig : IConfigPage { [JsonIgnore] - private static readonly string[] _anchorOptions = Enum.GetNames(typeof(DrawAnchor)); - - public string Name => "Header"; + public bool Active { get; set; } + + public string Name => "Header/Footer"; public bool ShowHeader = true; public int HeaderHeight = 25; public ConfigColor BackgroundColor = new(30f / 255f, 30f / 255f, 30f / 255f, 230 / 255f); + public bool ShowFooter = false; + public int FooterHeight = 25; + public ConfigColor FooterBackgroundColor = new(0, 0, 0, .5f); + public bool ShowEncounterDuration = true; public ConfigColor DurationColor = new(0f / 255f, 190f / 255f, 225f / 255f, 1f); public bool DurationShowOutline = true; @@ -26,7 +27,7 @@ public class HeaderConfig : IConfigPage public DrawAnchor DurationAlign = DrawAnchor.Left; public Vector2 DurationOffset = new(0, 0); public int DurationFontId = 0; - public string DurationFontKey = FontsManager.DalamudFontKey; + public string DurationFontKey = FontsManager.DefaultSmallFontKey; public bool ShowEncounterName = true; public ConfigColor NameColor = new(1, 1, 1, 1); @@ -35,7 +36,7 @@ public class HeaderConfig : IConfigPage public DrawAnchor NameAlign = DrawAnchor.Left; public Vector2 NameOffset = new(0, 0); public int NameFontId = 0; - public string NameFontKey = FontsManager.DalamudFontKey; + public string NameFontKey = FontsManager.DefaultSmallFontKey; public bool ShowRaidStats = true; public ConfigColor RaidStatsColor = new(0.5f, 0.5f, 0.5f, 1f); @@ -44,10 +45,18 @@ public class HeaderConfig : IConfigPage public DrawAnchor StatsAlign = DrawAnchor.Right; public Vector2 StatsOffset = new(0, 0); public int StatsFontId = 0; - public string StatsFontKey = FontsManager.DalamudFontKey; + public string StatsFontKey = FontsManager.DefaultSmallFontKey; public string RaidStatsFormat = "[dps]rdps [hps]rhps Deaths: [deaths]"; public bool ThousandsSeparators = true; + public bool ShowVersion = true; + public Vector2 VersionOffset = new(0, 0); + public int VersionFontId = 0; + public ConfigColor VersionColor = new(0f / 255f, 190f / 255f, 225f / 255f, 1f); + public bool VersionShowOutline = true; + public ConfigColor VersionOutlineColor = new(0, 0, 0, 0.5f); + public string VersionFontKey = FontsManager.DefaultSmallFontKey; + public IConfigPage GetDefault() { HeaderConfig defaultConfig = new() @@ -65,238 +74,56 @@ public IConfigPage GetDefault() return defaultConfig; } - public (Vector2, Vector2) DrawHeader(Vector2 pos, Vector2 size, Encounter? encounter, ImDrawListPtr drawList) - { - if (!this.ShowHeader) - { - return (pos, size); - } - - Vector2 headerSize = new(size.X, this.HeaderHeight); - drawList.AddRectFilled(pos, pos + headerSize, this.BackgroundColor.Base); - - Vector2 durationPos = pos; - Vector2 durationSize = Vector2.Zero; - if (this.ShowEncounterDuration) - { - using (FontsManager.PushFont(this.DurationFontKey)) - { - string duration = encounter is null ? $" LMeter v{Plugin.Version}" : $" {encounter.Duration}"; - durationSize = ImGui.CalcTextSize(duration); - durationPos = Utils.GetAnchoredPosition(durationPos, -headerSize, DrawAnchor.Left); - durationPos = Utils.GetAnchoredPosition(durationPos, durationSize, this.DurationAlign) + this.DurationOffset; - DrawHelpers.DrawText(drawList, duration, durationPos, this.DurationColor.Base, this.DurationShowOutline, this.DurationOutlineColor.Base); - } - } - - Vector2 raidStatsSize = Vector2.Zero; - if (this.ShowRaidStats && encounter is not null) - { - string text = encounter.GetFormattedString($" {this.RaidStatsFormat} ", this.ThousandsSeparators ? "N" : "F"); - - if (!string.IsNullOrEmpty(text)) - { - using (FontsManager.PushFont(this.StatsFontKey)) - { - raidStatsSize = ImGui.CalcTextSize(text); - Vector2 statsPos = Utils.GetAnchoredPosition(pos + this.StatsOffset, -headerSize, DrawAnchor.Right); - statsPos = Utils.GetAnchoredPosition(statsPos, raidStatsSize, this.StatsAlign); - DrawHelpers.DrawText(drawList, text, statsPos, this.RaidStatsColor.Base, this.StatsShowOutline, this.StatsOutlineColor.Base); - } - } - } - - if (this.ShowEncounterName && encounter is not null && !string.IsNullOrEmpty(encounter.Title)) - { - using (FontsManager.PushFont(this.NameFontKey)) - { - string name = $" {encounter.Title}"; - Vector2 nameSize = ImGui.CalcTextSize(name); - - if (durationSize.X + raidStatsSize.X + nameSize.X > size.X) - { - float elipsesWidth = ImGui.CalcTextSize("... ").X; - do - { - name = name.AsSpan(0, name.Length - 1).ToString(); - nameSize = ImGui.CalcTextSize(name); - } - while (durationSize.X + raidStatsSize.X + nameSize.X + elipsesWidth > size.X && name.Length > 1); - name += "... "; - } - - Vector2 namePos = Utils.GetAnchoredPosition(pos.AddX(durationSize.X), -headerSize, DrawAnchor.Left); - namePos = Utils.GetAnchoredPosition(namePos, nameSize, this.NameAlign) + this.NameOffset; - DrawHelpers.DrawText(drawList, name, namePos, this.NameColor.Base, this.NameShowOutline, this.NameOutlineColor.Base); - } - } - - return (pos.AddY(this.HeaderHeight), size.AddY(-this.HeaderHeight)); - } - - public void DrawConfig(Vector2 size, float padX, float padY) + public void DrawConfig(Vector2 size, float padX, float padY, bool border = true) { - string[] fontOptions = FontsManager.GetFontList(); - if (fontOptions.Length == 0) - { - return; - } - - if (ImGui.BeginChild($"##{this.Name}", new Vector2(size.X, size.Y), true)) + if (ImGui.BeginChild($"##{this.Name}", size, border)) { ImGui.Checkbox("Show Header", ref this.ShowHeader); if (this.ShowHeader) { DrawHelpers.DrawNestIndicator(1); - ImGui.DragInt("Header Height", ref this.HeaderHeight, 1, 0, 100); + ImGui.DragInt("Height##Header", ref this.HeaderHeight, 1, 0, 100); DrawHelpers.DrawNestIndicator(1); - Vector4 vector = this.BackgroundColor.Vector; - ImGui.ColorEdit4("Background Color", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.BackgroundColor.Vector = vector; + DrawHelpers.DrawColorSelector("Background Color##Header", ref this.BackgroundColor); - ImGui.NewLine(); DrawHelpers.DrawNestIndicator(1); - ImGui.Checkbox("Show Encounter Duration", ref this.ShowEncounterDuration); - if (this.ShowEncounterDuration) + ImGui.Checkbox("Show LMeter Version when Cleared", ref this.ShowVersion); + if (this.ShowVersion) { DrawHelpers.DrawNestIndicator(2); - ImGui.DragFloat2("Position Offset##Duration", ref this.DurationOffset); - - if (!FontsManager.ValidateFont(fontOptions, this.DurationFontId, this.DurationFontKey)) - { - this.DurationFontId = 0; - for (int i = 0; i < fontOptions.Length; i++) - { - if (this.DurationFontKey.Equals(fontOptions[i])) - { - this.DurationFontId = i; - } - } - } + ImGui.DragFloat2("Offset##Version", ref this.VersionOffset); DrawHelpers.DrawNestIndicator(2); - ImGui.Combo("Font##Duration", ref this.DurationFontId, fontOptions, fontOptions.Length); - this.DurationFontKey = fontOptions[this.DurationFontId]; + DrawHelpers.DrawFontSelector("Font##Version", ref this.VersionFontKey, ref this.VersionFontId); DrawHelpers.DrawNestIndicator(2); - ImGui.Combo("Text Align##Duration", ref Unsafe.As(ref this.DurationAlign), _anchorOptions, _anchorOptions.Length); + DrawHelpers.DrawColorSelector("Text Color##Version", ref this.VersionColor); DrawHelpers.DrawNestIndicator(2); - vector = this.DurationColor.Vector; - ImGui.ColorEdit4("Text Color##Duration", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.DurationColor.Vector = vector; - - DrawHelpers.DrawNestIndicator(2); - ImGui.Checkbox("Show Outline##Duration", ref this.DurationShowOutline); - if (this.DurationShowOutline) + ImGui.Checkbox("Show Outline##Version", ref this.VersionShowOutline); + if (this.VersionShowOutline) { DrawHelpers.DrawNestIndicator(3); - vector = this.DurationOutlineColor.Vector; - ImGui.ColorEdit4("Outline Color##Duration", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.DurationOutlineColor.Vector = vector; + DrawHelpers.DrawColorSelector("Outline Color##Version", ref this.VersionOutlineColor); } } ImGui.NewLine(); - DrawHelpers.DrawNestIndicator(1); - ImGui.Checkbox("Show Encounter Name", ref this.ShowEncounterName); - if (this.ShowEncounterName) - { - DrawHelpers.DrawNestIndicator(2); - ImGui.DragFloat2("Position Offset##Name", ref this.NameOffset); - - if (!FontsManager.ValidateFont(fontOptions, this.NameFontId, this.NameFontKey)) - { - this.NameFontId = 0; - for (int i = 0; i < fontOptions.Length; i++) - { - if (this.NameFontKey.Equals(fontOptions[i])) - { - this.NameFontId = i; - } - } - } - - DrawHelpers.DrawNestIndicator(2); - ImGui.Combo("Font##Name", ref this.NameFontId, fontOptions, fontOptions.Length); - this.NameFontKey = fontOptions[this.NameFontId]; - - DrawHelpers.DrawNestIndicator(2); - ImGui.Combo("Text Align##Name", ref Unsafe.As(ref this.NameAlign), _anchorOptions, _anchorOptions.Length); - - DrawHelpers.DrawNestIndicator(2); - vector = this.NameColor.Vector; - ImGui.ColorEdit4("Text Color##Name", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.NameColor.Vector = vector; - - DrawHelpers.DrawNestIndicator(2); - ImGui.Checkbox("Show Outline##Name", ref this.NameShowOutline); - if (this.NameShowOutline) - { - DrawHelpers.DrawNestIndicator(3); - vector = this.NameOutlineColor.Vector; - ImGui.ColorEdit4("Outline Color##Name", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.NameOutlineColor.Vector = vector; - } - } + } - ImGui.NewLine(); + ImGui.Checkbox("Show Footer", ref this.ShowFooter); + if (this.ShowFooter) + { DrawHelpers.DrawNestIndicator(1); - ImGui.Checkbox("Show Raid Stats", ref this.ShowRaidStats); - if (this.ShowRaidStats) - { - DrawHelpers.DrawNestIndicator(2); - ImGui.InputText("Raid Stats Format", ref this.RaidStatsFormat, 128); - if (ImGui.IsItemHovered()) - { - ImGui.SetTooltip(Utils.GetTagsTooltip(Encounter.TextTags)); - } - - DrawHelpers.DrawNestIndicator(2); - ImGui.Checkbox("Use Thousands Separators for Numbers", ref this.ThousandsSeparators); - - DrawHelpers.DrawNestIndicator(2); - ImGui.DragFloat2("Position Offset##Stats", ref this.StatsOffset); - - if (!FontsManager.ValidateFont(fontOptions, this.StatsFontId, this.StatsFontKey)) - { - this.StatsFontId = 0; - for (int i = 0; i < fontOptions.Length; i++) - { - if (this.StatsFontKey.Equals(fontOptions[i])) - { - this.StatsFontId = i; - } - } - } - - DrawHelpers.DrawNestIndicator(2); - ImGui.Combo("Font##Stats", ref this.StatsFontId, fontOptions, fontOptions.Length); - this.StatsFontKey = fontOptions[this.StatsFontId]; + ImGui.DragInt("Height##Footer", ref this.FooterHeight, 1, 0, 100); - DrawHelpers.DrawNestIndicator(2); - ImGui.Combo("Text Align##Stats", ref Unsafe.As(ref this.StatsAlign), _anchorOptions, _anchorOptions.Length); - - DrawHelpers.DrawNestIndicator(2); - vector = this.RaidStatsColor.Vector; - ImGui.ColorEdit4("Text Color##Stats", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.RaidStatsColor.Vector = vector; - - DrawHelpers.DrawNestIndicator(2); - ImGui.Checkbox("Show Outline##Stats", ref this.StatsShowOutline); - if (this.StatsShowOutline) - { - DrawHelpers.DrawNestIndicator(3); - vector = this.StatsOutlineColor.Vector; - ImGui.ColorEdit4("Outline Color##Stats", ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); - this.StatsOutlineColor.Vector = vector; - } - } + DrawHelpers.DrawNestIndicator(1); + DrawHelpers.DrawColorSelector("Background Color##Footer", ref this.FooterBackgroundColor); } + + ImGui.EndChild(); } - - ImGui.EndChild(); } } } diff --git a/LMeter/Config/IConfigPage.cs b/LMeter/Config/IConfigPage.cs index f815243..9e62aed 100644 --- a/LMeter/Config/IConfigPage.cs +++ b/LMeter/Config/IConfigPage.cs @@ -5,8 +5,9 @@ namespace LMeter.Config public interface IConfigPage { string Name { get; } - + bool Active { get; set; } + IConfigPage GetDefault(); - void DrawConfig(Vector2 size, float padX, float padY); + void DrawConfig(Vector2 size, float padX, float padY, bool border = true); } } diff --git a/LMeter/Config/LMeterConfig.cs b/LMeter/Config/LMeterConfig.cs index 9eb767a..7e154c2 100644 --- a/LMeter/Config/LMeterConfig.cs +++ b/LMeter/Config/LMeterConfig.cs @@ -8,25 +8,21 @@ namespace LMeter.Config [JsonObject] public class LMeterConfig : IConfigurable, IPluginDisposable { - public string Name - { + public bool FirstLoad = true; + public string Version => Plugin.Version; + public string Name + { get => "LMeter"; set {} } - public string Version => Plugin.Version; - - public bool FirstLoad = true; + [JsonIgnore] + private AboutPage AboutPage { get; } = new AboutPage(); public MeterListConfig MeterList { get; init; } - public ActConfig ActConfig { get; init; } - public FontConfig FontConfig { get; init; } - [JsonIgnore] - private AboutPage AboutPage { get; } = new AboutPage(); - public LMeterConfig() { this.MeterList = new MeterListConfig(); diff --git a/LMeter/Config/MeterListConfig.cs b/LMeter/Config/MeterListConfig.cs index 90ec18e..f62c6ab 100644 --- a/LMeter/Config/MeterListConfig.cs +++ b/LMeter/Config/MeterListConfig.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Numerics; +using System.Runtime.CompilerServices; using Dalamud.Interface; using Dalamud.Interface.ImGuiNotification; using ImGuiNET; @@ -12,12 +13,19 @@ namespace LMeter.Config { public class MeterListConfig : IConfigPage { + [JsonIgnore] + private string _input = string.Empty; + + [JsonIgnore] + private MeterDataType _meterDataType = MeterDataType.Damage; + private const float MenuBarHeight = 40; - [JsonIgnore] private string _input = string.Empty; + [JsonIgnore] + public bool Active { get; set; } public string Name => "Profiles"; - + public List Meters { get; set; } public MeterListConfig() @@ -27,34 +35,47 @@ public MeterListConfig() public IConfigPage GetDefault() => new MeterListConfig(); - public void DrawConfig(Vector2 size, float padX, float padY) + public void DrawConfig(Vector2 size, float padX, float padY, bool border = true) { this.DrawCreateMenu(size, padX); this.DrawMeterTable(size.AddY(-padY), padX); } - public void ToggleMeter(int meterIndex, bool? toggle = null) + public void ToggleMeter(int? meterIndex) { - if (meterIndex >= 0 && meterIndex < this.Meters.Count) + if (meterIndex is null) { - this.Meters[meterIndex].VisibilityConfig.AlwaysHide = toggle.HasValue - ? !toggle.Value - : !this.Meters[meterIndex].VisibilityConfig.AlwaysHide; + foreach (MeterWindow meter in this.Meters) + { + meter.VisibilityConfig.AlwaysHide ^= true; + } + } + else if (meterIndex >= 0 && meterIndex < this.Meters.Count) + { + this.Meters[meterIndex.Value].VisibilityConfig.AlwaysHide ^= true; } } - public void ToggleClickThrough(int meterIndex) + public void ToggleClickThrough(int? meterIndex) { - if (meterIndex >= 0 && meterIndex < this.Meters.Count) + if (meterIndex is null) { - this.Meters[meterIndex].GeneralConfig.ClickThrough ^= true; + foreach (MeterWindow meter in this.Meters) + { + meter.GeneralConfig.ClickThrough ^= true; + } + } + else if (meterIndex >= 0 && meterIndex < this.Meters.Count) + { + this.Meters[meterIndex.Value].GeneralConfig.ClickThrough ^= true; } } private void DrawCreateMenu(Vector2 size, float padX) { Vector2 buttonSize = new(40, 0); - float textInputWidth = size.X - buttonSize.X * 2 - padX * 4; + float meterTypeWidth = 100f; + float textInputWidth = size.X - meterTypeWidth - buttonSize.X * 2 - padX * 5; if (ImGui.BeginChild("##Buttons", new Vector2(size.X, MenuBarHeight), true)) { @@ -62,8 +83,13 @@ private void DrawCreateMenu(Vector2 size, float padX) ImGui.InputTextWithHint("##Input", "Profile Name/Import String", ref _input, 10000); ImGui.PopItemWidth(); + ImGui.PushItemWidth(meterTypeWidth); + ImGui.SameLine(); + ImGui.Combo("", ref Unsafe.As(ref _meterDataType), ["Damage", "Healing"], 2); + ImGui.PopItemWidth(); + ImGui.SameLine(); - DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Plus, () => CreateMeter(_input), "Create new Meter", buttonSize); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Plus, () => CreateMeter(_input, _meterDataType), "Create new Meter", buttonSize); ImGui.SameLine(); DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Download, () => ImportMeter(_input), "Import new Meter", buttonSize); @@ -88,7 +114,7 @@ private void DrawMeterTable(Vector2 size, float padX) Vector2 buttonsize = new(30, 0); float actionsWidth = buttonsize.X * 3 + padX * 2; - ImGui.TableSetupColumn(" #", ImGuiTableColumnFlags.WidthFixed, 18, 0); + ImGui.TableSetupColumn("Enabled", ImGuiTableColumnFlags.WidthFixed, 46, 0); ImGui.TableSetupColumn("Profile Name", ImGuiTableColumnFlags.WidthStretch, 0, 1); ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, actionsWidth, 2); @@ -110,12 +136,8 @@ private void DrawMeterTable(Vector2 size, float padX) if (ImGui.TableSetColumnIndex(0)) { - string num = $" {i + 1}."; - float columnWidth = ImGui.GetColumnWidth(); - Vector2 cursorPos = ImGui.GetCursorPos(); - Vector2 textSize = ImGui.CalcTextSize(num); - ImGui.SetCursorPos(new Vector2(cursorPos.X + columnWidth - textSize.X, cursorPos.Y + 3f)); - ImGui.Text(num); + ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(11f, 1f)); + ImGui.Checkbox($"##Text_{i}_EnabledCheckbox", ref meter.Enabled); } if (ImGui.TableSetColumnIndex(1)) @@ -141,11 +163,11 @@ private void DrawMeterTable(Vector2 size, float padX) } } - private void CreateMeter(string name) + private void CreateMeter(string name, MeterDataType dataType) { if (!string.IsNullOrEmpty(name)) { - this.Meters.Add(MeterWindow.GetDefaultMeter(name)); + this.Meters.Add(MeterWindow.GetDefaultMeter(dataType, name)); } _input = string.Empty; diff --git a/LMeter/Config/VisibilityConfig.cs b/LMeter/Config/VisibilityConfig.cs index 06cc3b3..0d7def3 100644 --- a/LMeter/Config/VisibilityConfig.cs +++ b/LMeter/Config/VisibilityConfig.cs @@ -1,8 +1,9 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; +using Dalamud.Interface; using ImGuiNET; using LMeter.Act; using LMeter.Helpers; @@ -10,84 +11,309 @@ namespace LMeter.Config { - public class VisibilityConfig : IConfigPage { - public string Name => "Visibility"; - - public IConfigPage GetDefault() => new VisibilityConfig(); + [JsonIgnore] public static readonly string[] OperatorOptions = [ "AND", "OR", "XOR" ]; + [JsonIgnore] public static readonly string[] ResultOptions = [ "Show", "Hide" ]; + [JsonIgnore] private int _swapX = -1; + [JsonIgnore] private int _swapY = -1; + [JsonIgnore] private int _selectedIndex = 0; + + [JsonIgnore] + public bool Active { get; set; } - [JsonIgnore] private string _customJobInput = string.Empty; + public string Name => "Visibility"; + public List VisibilityConditions = []; + public bool Initialized = false; public bool AlwaysHide = false; - public bool HideInCombat = false; - public bool HideOutsideCombat = false; - public bool HideOutsideDuty = false; - public bool HideWhilePerforming = false; - public bool HideInGoldenSaucer = false; - public bool HideIfNotConnected = false; public bool ShouldClip = true; + public bool ShowOnMouseover = false; + public bool HideIfNotConnected = false; + public int ResultOption = 0; - public JobType ShowForJobTypes = JobType.All; - public string CustomJobString = string.Empty; - public List CustomJobList = []; + public VisibilityConfig() + { + this.VisibilityConditions = [ new() ]; + } + + public IConfigPage GetDefault() => new VisibilityConfig(); public bool IsVisible() { - if (this.AlwaysHide) + if (this.VisibilityConditions.Count == 0) { return false; } - if (this.HideInCombat && CharacterState.IsInCombat()) + if (this.AlwaysHide) { return false; } - if (this.HideOutsideCombat && !CharacterState.IsInCombat()) + if (this.HideIfNotConnected && Singletons.Get().Status != ConnectionStatus.Connected) { return false; } - if (this.HideOutsideDuty && !CharacterState.IsInDuty()) + bool active = this.VisibilityConditions[0].IsActive(); + for (int i = 1; i < this.VisibilityConditions.Count; i++) { - return false; + VisibilityCondition option = this.VisibilityConditions[i]; + bool currentActive = option.IsActive(); + + active = option.Operator switch + { + BooleanOperator.And => active && currentActive, + BooleanOperator.Or => active || currentActive, + BooleanOperator.Xor => active ^ currentActive, + _ => false + }; } - if (this.HideWhilePerforming && CharacterState.IsPerforming()) + return active ^ this.ResultOption == 1; + } + + public void DrawConfig(Vector2 size, float padX, float padY, bool border = true) + { + if (this.VisibilityConditions.Count == 0) { - return false; + this.AddOption(new()); } - if (this.HideInGoldenSaucer && CharacterState.IsInGoldenSaucer()) + float posY = ImGui.GetCursorPosY(); + ImGui.Checkbox("Always Hide", ref this.AlwaysHide); + ImGui.Checkbox("Hide When Covered by Game UI Elements", ref this.ShouldClip); + ImGui.Checkbox("Always Show When Hovered by Mouse", ref this.ShowOnMouseover); + ImGui.Checkbox("Always Hide When Not Connected to ACT", ref this.HideIfNotConnected); + size = new(size.X, size.Y - (ImGui.GetCursorPosY() - posY)); + + if (ImGui.BeginChild("##VisibilityOptionConfig", new Vector2(size.X, size.Y), border)) { - return false; + ImGui.Text("Visibility Conditions"); + + ImGuiTableFlags tableFlags = + ImGuiTableFlags.RowBg | + ImGuiTableFlags.Borders | + ImGuiTableFlags.BordersOuter | + ImGuiTableFlags.BordersInner | + ImGuiTableFlags.ScrollY | + ImGuiTableFlags.NoSavedSettings; + + if (ImGui.BeginTable("##VisibilityOptions_Table", 4, tableFlags, new Vector2(size.X - padX * 2, (size.Y - ImGui.GetCursorPosY() - padY * 2) / 4))) + { + Vector2 buttonSize = new(30, 0); + int buttonCount = this.VisibilityConditions.Count > 1 ? 5 : 3; + float actionsWidth = buttonSize.X * buttonCount + padX * (buttonCount - 1); + ImGui.TableSetupColumn("Operator", ImGuiTableColumnFlags.WidthFixed, 60, 0); + ImGui.TableSetupColumn("Invert", ImGuiTableColumnFlags.WidthFixed, 35, 1); + ImGui.TableSetupColumn("Condition Type", ImGuiTableColumnFlags.WidthStretch, 0, 2); + ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, actionsWidth, 3); + ImGui.TableSetupScrollFreeze(0, 1); + ImGui.TableHeadersRow(); + + for (int i = 0; i < this.VisibilityConditions.Count; i++) + { + ImGui.PushID(i.ToString()); + ImGui.TableNextRow(ImGuiTableRowFlags.None, 28); + this.DrawOptionsRow(i); + } + + ImGui.PushID(this.VisibilityConditions.Count.ToString()); + ImGui.TableNextRow(ImGuiTableRowFlags.None, 28); + ImGui.TableSetColumnIndex(3); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Plus, () => this.AddOption(), "New Condition", buttonSize); + ImGui.SameLine(); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Download, () => this.ImportOption(), "Import Condition", buttonSize); + + ImGui.EndTable(); + + if (_swapX < this.VisibilityConditions.Count && _swapX >= 0 && + _swapY < this.VisibilityConditions.Count && _swapY >= 0) + { + VisibilityCondition temp = this.VisibilityConditions[_swapX]; + this.VisibilityConditions[_swapX] = this.VisibilityConditions[_swapY]; + this.VisibilityConditions[_swapY] = temp; + + _swapX = -1; + _swapY = -1; + } + } + + ImGui.Text("Action if result is true:"); + ImGui.SameLine(); + ImGui.PushItemWidth(100); + ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(0f, -2f)); + ImGui.Combo("##ResultCombo", ref this.ResultOption, ResultOptions, ResultOptions.Length); + ImGui.PopItemWidth(); + + ImGui.Text($"Edit Condition {_selectedIndex + 1}"); + if (ImGui.BeginChild("##ConditionEdit", new Vector2(size.X - padX * 2, size.Y - ImGui.GetCursorPosY() - padY * 2), true)) + { + VisibilityCondition selectedOption = this.VisibilityConditions[_selectedIndex]; + selectedOption.DrawConfig(ImGui.GetWindowSize(), padX, padX); + + ImGui.EndChild(); + } + + ImGui.EndChild(); } + } - if (this.HideIfNotConnected && Singletons.Get().Status != ConnectionStatus.Connected) + private void DrawOptionsRow(int i) + { + if (i >= this.VisibilityConditions.Count) { - return false; + return; + } + + VisibilityCondition condition = this.VisibilityConditions[i]; + if (ImGui.TableSetColumnIndex(0)) + { + ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (i == 0 ? 3f : 1f)); + if (i == 0) + { + ImGui.Text("IF"); + } + else + { + ImGui.PushItemWidth(ImGui.GetColumnWidth()); + ImGui.Combo("##CondCombo", ref Unsafe.As(ref condition.Operator), OperatorOptions, OperatorOptions.Length); + ImGui.PopItemWidth(); + } + } + + if (ImGui.TableSetColumnIndex(1)) + { + ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(6f, 1f)); + ImGui.Checkbox(string.Empty, ref condition.Inverted); + } + + if (ImGui.TableSetColumnIndex(2)) + { + ImGui.Text(condition.ConditionType == VisibilityConditionType.Zone ? $"Zone: {condition.Zone}" : $"{condition.ConditionType}"); } - return CharacterState.IsJobType(CharacterState.GetCharacterJob(), this.ShowForJobTypes, this.CustomJobList); + if (ImGui.TableSetColumnIndex(3)) + { + ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 1f); + Vector2 buttonSize = new(30, 0); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Pen, () => this.SelectOption(i), "Edit Condition", buttonSize); + + if (this.VisibilityConditions.Count > 1) + { + ImGui.SameLine(); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.ArrowUp, () => this.Swap(i, i - 1), "Move Up", buttonSize); + + ImGui.SameLine(); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.ArrowDown, () => this.Swap(i, i + 1), "Move Down", buttonSize); + } + + ImGui.SameLine(); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Upload, () => this.ExportOption(i), "Export Condition", buttonSize); + if (this.VisibilityConditions.Count > 1) + { + ImGui.SameLine(); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Trash, () => this.RemoveOption(i), "Remove Condition", buttonSize); + } + } } + private void SelectOption(int i) + { + _selectedIndex = i; + } + + private void AddOption(VisibilityCondition? newOption = null) + { + this.VisibilityConditions.Add(newOption ?? new VisibilityCondition()); + this.SelectOption(this.VisibilityConditions.Count - 1); + } + + private void ExportOption(int i) + { + if (i < this.VisibilityConditions.Count && i >= 0) + { + ConfigHelpers.ExportToClipboard(this.VisibilityConditions[i]); + } + } + + private void ImportOption() + { + string importString = ImGui.GetClipboardText(); + if (!string.IsNullOrEmpty(importString)) + { + VisibilityCondition? newOption = ConfigHelpers.GetFromImportString(importString); + if (newOption is not null) + { + this.AddOption(newOption); + } + } + } + + private void RemoveOption(int i) + { + if (i < this.VisibilityConditions.Count && i >= 0) + { + this.VisibilityConditions.RemoveAt(i); + _selectedIndex = Math.Clamp(_selectedIndex, 0, this.VisibilityConditions.Count - 1); + } + } + + private void Swap(int x, int y) + { + _swapX = x; + _swapY = y; + } + } + + public class VisibilityCondition + { + [JsonIgnore] private string _customJobInput = string.Empty; + + public bool Inverted = false; + public BooleanOperator Operator = BooleanOperator.And; + public VisibilityConditionType ConditionType = VisibilityConditionType.AlwaysTrue; + + public JobType ShowForJobTypes = JobType.All; + public string CustomJobString = string.Empty; + public List CustomJobList = []; + + public ZoneType Zone; + + public bool IsActive() => this.Inverted ^ this.ConditionType switch + { + VisibilityConditionType.AlwaysTrue => true, + VisibilityConditionType.InCombat => CharacterState.IsInCombat(), + VisibilityConditionType.InDuty => CharacterState.IsInDuty(), + VisibilityConditionType.Performing => CharacterState.IsPerforming(), + VisibilityConditionType.Zone => CharacterState.InZone(this.Zone), + VisibilityConditionType.Job => CharacterState.IsJobType(CharacterState.GetCharacterJob(), this.ShowForJobTypes, this.CustomJobList), + _ => true + }; + public void DrawConfig(Vector2 size, float padX, float padY) { - if (ImGui.BeginChild($"##{this.Name}", new Vector2(size.X, size.Y), true)) - { - ImGui.Checkbox("Always Hide", ref this.AlwaysHide); - ImGui.Checkbox("Hide In Combat", ref this.HideInCombat); - ImGui.Checkbox("Hide Outside Combat", ref this.HideOutsideCombat); - ImGui.Checkbox("Hide Outside Duty", ref this.HideOutsideDuty); - ImGui.Checkbox("Hide While Performing", ref this.HideWhilePerforming); - ImGui.Checkbox("Hide In Golden Saucer", ref this.HideInGoldenSaucer); - ImGui.Checkbox("Hide While Not Connected to ACT", ref this.HideIfNotConnected); - ImGui.Checkbox("Hide When Covered by Game UI Window", ref this.ShouldClip); - - DrawHelpers.DrawSpacing(1); + ImGui.RadioButton("Always True", ref Unsafe.As(ref this.ConditionType), (int)VisibilityConditionType.AlwaysTrue); + ImGui.RadioButton("In Combat", ref Unsafe.As(ref this.ConditionType), (int)VisibilityConditionType.InCombat); + ImGui.RadioButton("In Duty", ref Unsafe.As(ref this.ConditionType), (int)VisibilityConditionType.InDuty); + ImGui.RadioButton("Performing", ref Unsafe.As(ref this.ConditionType), (int)VisibilityConditionType.Performing); + + ImGui.RadioButton("In Zone", ref Unsafe.As(ref this.ConditionType), (int)VisibilityConditionType.Zone); + if (this.ConditionType == VisibilityConditionType.Zone) + { + DrawHelpers.DrawNestIndicator(1); + ImGui.RadioButton("Gold Saucer", ref Unsafe.As(ref this.Zone), (int)ZoneType.GoldSaucer); + DrawHelpers.DrawNestIndicator(1); + ImGui.RadioButton("Player House", ref Unsafe.As(ref this.Zone), (int)ZoneType.PlayerHouse); + } + + ImGui.RadioButton("Job", ref Unsafe.As(ref this.ConditionType), (int)VisibilityConditionType.Job); + if (this.ConditionType == VisibilityConditionType.Job) + { + DrawHelpers.DrawNestIndicator(1); string[] jobTypeOptions = Enum.GetNames(typeof(JobType)); - ImGui.Combo("Show for Jobs", ref Unsafe.As(ref this.ShowForJobTypes), jobTypeOptions, jobTypeOptions.Length); + ImGui.Combo("Job Select", ref Unsafe.As(ref this.ShowForJobTypes), jobTypeOptions, jobTypeOptions.Length); if (this.ShowForJobTypes == JobType.Custom) { @@ -96,6 +322,7 @@ public void DrawConfig(Vector2 size, float padX, float padY) _customJobInput = this.CustomJobString.ToUpper(); } + DrawHelpers.DrawNestIndicator(1); if (ImGui.InputTextWithHint("Custom Job List", "Comma Separated List (ex: WAR, SAM, BLM)", ref _customJobInput, 100, ImGuiInputTextFlags.EnterReturnsTrue)) { IEnumerable jobStrings = _customJobInput.Split(',').Select(j => j.Trim()); @@ -120,8 +347,6 @@ public void DrawConfig(Vector2 size, float padX, float padY) } } } - - ImGui.EndChild(); } } } \ No newline at end of file diff --git a/LMeter/Config/VisibilityConfig2.cs b/LMeter/Config/VisibilityConfig2.cs deleted file mode 100644 index 87f9bee..0000000 --- a/LMeter/Config/VisibilityConfig2.cs +++ /dev/null @@ -1,365 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Numerics; -using System.Runtime.CompilerServices; -using Dalamud.Interface; -using ImGuiNET; -using LMeter.Act; -using LMeter.Helpers; -using Newtonsoft.Json; - -namespace LMeter.Config -{ - public enum VisibilityOperator - { - And, - Or, - Xor - } - - public class VisibilityOption - { - [JsonIgnore] private string _customJobInput = string.Empty; - - public VisibilityOperator Operator = VisibilityOperator.And; - public bool Inverted = false; - - public bool AlwaysHide = false; - public bool HideOutsideCombat = false; - public bool HideOutsideDuty = false; - public bool HideWhilePerforming = false; - public bool HideInGoldenSaucer = false; - public bool HideIfNotConnected = false; - - public JobType ShowForJobTypes = JobType.All; - public string CustomJobString = string.Empty; - public List CustomJobList = []; - - public bool IsActive() - { - if (this.AlwaysHide) - { - return false; - } - - if (this.HideOutsideCombat && !CharacterState.IsInCombat()) - { - return false; - } - - if (this.HideOutsideDuty && !CharacterState.IsInDuty()) - { - return false; - } - - if (this.HideWhilePerforming && CharacterState.IsPerforming()) - { - return false; - } - - if (this.HideInGoldenSaucer && CharacterState.IsInGoldenSaucer()) - { - return false; - } - - if (this.HideIfNotConnected && Singletons.Get().Status != ConnectionStatus.Connected) - { - return false; - } - - return CharacterState.IsJobType(CharacterState.GetCharacterJob(), this.ShowForJobTypes, this.CustomJobList); - } - - public void DrawConfig(Vector2 size, float padX, float padY) - { - ImGui.Checkbox("Always Hide", ref this.AlwaysHide); - ImGui.Checkbox("Hide Outside Combat", ref this.HideOutsideCombat); - ImGui.Checkbox("Hide Outside Duty", ref this.HideOutsideDuty); - ImGui.Checkbox("Hide While Performing", ref this.HideWhilePerforming); - ImGui.Checkbox("Hide In Golden Saucer", ref this.HideInGoldenSaucer); - ImGui.Checkbox("Hide While Not Connected to ACT", ref this.HideIfNotConnected); - - DrawHelpers.DrawSpacing(1); - string[] jobTypeOptions = Enum.GetNames(typeof(JobType)); - ImGui.Combo("Show for Jobs", ref Unsafe.As(ref this.ShowForJobTypes), jobTypeOptions, jobTypeOptions.Length); - - if (this.ShowForJobTypes == JobType.Custom) - { - if (string.IsNullOrEmpty(_customJobInput)) - { - _customJobInput = this.CustomJobString.ToUpper(); - } - - if (ImGui.InputTextWithHint("Custom Job List", "Comma Separated List (ex: WAR, SAM, BLM)", ref _customJobInput, 100, ImGuiInputTextFlags.EnterReturnsTrue)) - { - IEnumerable jobStrings = _customJobInput.Split(',').Select(j => j.Trim()); - List jobList = []; - foreach (string j in jobStrings) - { - if (Enum.TryParse(j, true, out Job parsed)) - { - jobList.Add(parsed); - } - else - { - jobList.Clear(); - _customJobInput = string.Empty; - break; - } - } - - _customJobInput = _customJobInput.ToUpper(); - this.CustomJobString = _customJobInput; - this.CustomJobList = jobList; - } - } - } - } - - public class VisibilityConfig2 : IConfigPage - { - [JsonIgnore] public static readonly string[] OperatorOptions = ["AND", "OR", "XOR"]; - [JsonIgnore] private int _swapX = -1; - [JsonIgnore] private int _swapY = -1; - [JsonIgnore] private int _selectedIndex = 0; - - public string Name => "Visibility"; - public IConfigPage GetDefault() => new VisibilityConfig2(); - - public bool Initialized = false; - public List VisibilityOptions = []; - public bool ShouldClip = true; - - public void SetOldConfig(VisibilityConfig oldConfig) - { - VisibilityOption newOption = new(); - this.Initialized = true; - this.ShouldClip = oldConfig.ShouldClip; - newOption.HideIfNotConnected = oldConfig.HideIfNotConnected; - - newOption.AlwaysHide = oldConfig.AlwaysHide; - newOption.HideOutsideCombat = oldConfig.HideOutsideCombat; - newOption.HideWhilePerforming = oldConfig.HideWhilePerforming; - newOption.HideOutsideDuty = oldConfig.HideOutsideDuty; - newOption.HideInGoldenSaucer = oldConfig.HideInGoldenSaucer; - - newOption.ShowForJobTypes = oldConfig.ShowForJobTypes; - newOption.CustomJobList = oldConfig.CustomJobList; - newOption.CustomJobString = oldConfig.CustomJobString; - this.AddOption(newOption); - } - - public bool IsVisible() - { - if (this.VisibilityOptions.Count == 0) - { - return false; - } - - bool active = this.VisibilityOptions[0].IsActive(); - for (int i = 1; i < this.VisibilityOptions.Count; i++) - { - VisibilityOption option = this.VisibilityOptions[i]; - bool currentActive = option.IsActive(); - - if (option.Inverted) - { - currentActive = !currentActive; - } - - active = option.Operator switch - { - VisibilityOperator.And => active && currentActive, - VisibilityOperator.Or => active || currentActive, - VisibilityOperator.Xor => active ^ currentActive, - _ => false - }; - } - - return active; - } - - public void DrawConfig(Vector2 size, float padX, float padY) - { - if (this.VisibilityOptions.Count == 0) - { - this.AddOption(new()); - } - - float posY = ImGui.GetCursorPosY(); - ImGui.Checkbox("Hide When Covered by Game UI Window", ref this.ShouldClip); - size = new(size.X, size.Y - (ImGui.GetCursorPosY() - posY)); - - if (ImGui.BeginChild("##VisibilityOptionConfig", new Vector2(size.X, size.Y), true)) - { - ImGui.Text("Visibility Options"); - ImGuiTableFlags tableFlags = - ImGuiTableFlags.RowBg | - ImGuiTableFlags.Borders | - ImGuiTableFlags.BordersOuter | - ImGuiTableFlags.BordersInner | - ImGuiTableFlags.ScrollY | - ImGuiTableFlags.NoSavedSettings; - - if (ImGui.BeginTable("##VisibilityOptions_Table", 4, tableFlags, new Vector2(size.X - padX * 2, (size.Y - ImGui.GetCursorPosY() - padY * 2) / 4))) - { - Vector2 buttonSize = new(30, 0); - int buttonCount = this.VisibilityOptions.Count > 1 ? 5 : 3; - float actionsWidth = buttonSize.X * buttonCount + padX * (buttonCount - 1); - ImGui.TableSetupColumn("Condition", ImGuiTableColumnFlags.WidthFixed, 60, 0); - ImGui.TableSetupColumn("Invert", ImGuiTableColumnFlags.WidthFixed, 35, 1); - ImGui.TableSetupColumn("Option Name", ImGuiTableColumnFlags.WidthStretch, 0, 2); - ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, actionsWidth, 3); - ImGui.TableSetupScrollFreeze(0, 1); - ImGui.TableHeadersRow(); - - for (int i = 0; i < this.VisibilityOptions.Count; i++) - { - ImGui.PushID(i.ToString()); - ImGui.TableNextRow(ImGuiTableRowFlags.None, 28); - - this.DrawOptionsRow(i); - } - - ImGui.PushID(this.VisibilityOptions.Count.ToString()); - ImGui.TableNextRow(ImGuiTableRowFlags.None, 28); - ImGui.TableSetColumnIndex(3); - DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Plus, () => this.AddOption(), "New Option", buttonSize); - ImGui.SameLine(); - DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Download, () => this.ImportOption(), "Import Option", buttonSize); - - ImGui.EndTable(); - - if (_swapX < this.VisibilityOptions.Count && _swapX >= 0 && - _swapY < this.VisibilityOptions.Count && _swapY >= 0) - { - VisibilityOption temp = this.VisibilityOptions[_swapX]; - this.VisibilityOptions[_swapX] = this.VisibilityOptions[_swapY]; - this.VisibilityOptions[_swapY] = temp; - - _swapX = -1; - _swapY = -1; - } - } - - ImGui.Text($"Edit Option {_selectedIndex + 1}"); - if (ImGui.BeginChild("##OptionEdit", new Vector2(size.X - padX * 2, size.Y - ImGui.GetCursorPosY() - padY * 2), true)) - { - VisibilityOption selectedOption = this.VisibilityOptions[_selectedIndex]; - selectedOption.DrawConfig(ImGui.GetWindowSize(), padX, padX); - - ImGui.EndChild(); - } - - ImGui.EndChild(); - } - } - - private void DrawOptionsRow(int i) - { - if (i >= this.VisibilityOptions.Count) - { - return; - } - - VisibilityOption option = this.VisibilityOptions[i]; - if (ImGui.TableSetColumnIndex(0)) - { - ImGui.SetCursorPosY(ImGui.GetCursorPosY() + (i == 0 ? 3f : 1f)); - if (i == 0) - { - ImGui.Text("IF"); - } - else - { - ImGui.PushItemWidth(ImGui.GetColumnWidth()); - ImGui.Combo("##CondCombo", ref Unsafe.As(ref option.Operator), OperatorOptions, OperatorOptions.Length); - ImGui.PopItemWidth(); - } - } - - if (ImGui.TableSetColumnIndex(1)) - { - ImGui.SetCursorPos(ImGui.GetCursorPos() + new Vector2(1f, 5f)); - ImGui.Checkbox(string.Empty, ref option.Inverted); - } - - if (ImGui.TableSetColumnIndex(2)) - { - ImGui.Text($"Option {i + 1}"); - } - - if (ImGui.TableSetColumnIndex(3)) - { - ImGui.SetCursorPosY(ImGui.GetCursorPosY() + 1f); - Vector2 buttonSize = new(30, 0); - DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Pen, () => this.SelectOption(i), "Edit Option", buttonSize); - - if (this.VisibilityOptions.Count > 1) - { - ImGui.SameLine(); - DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.ArrowUp, () => this.Swap(i, i - 1), "Move Up", buttonSize); - - ImGui.SameLine(); - DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.ArrowDown, () => this.Swap(i, i + 1), "Move Down", buttonSize); - } - - ImGui.SameLine(); - DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Upload, () => this.ExportOption(i), "Export Option", buttonSize); - if (this.VisibilityOptions.Count > 1) - { - ImGui.SameLine(); - DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Trash, () => this.RemoveOption(i), "Remove Option", buttonSize); - } - } - } - - private void SelectOption(int i) - { - _selectedIndex = i; - } - - private void AddOption(VisibilityOption? newOption = null) - { - this.VisibilityOptions.Add(newOption ?? new VisibilityOption()); - this.SelectOption(this.VisibilityOptions.Count - 1); - } - - private void ExportOption(int i) - { - if (i < this.VisibilityOptions.Count && i >= 0) - { - ConfigHelpers.ExportToClipboard(this.VisibilityOptions[i]); - } - } - - private void ImportOption() - { - string importString = ImGui.GetClipboardText(); - if (!string.IsNullOrEmpty(importString)) - { - VisibilityOption? newOption = ConfigHelpers.GetFromImportString(importString); - if (newOption is not null) - { - this.AddOption(newOption); - } - } - } - - private void RemoveOption(int i) - { - if (i < this.VisibilityOptions.Count && i >= 0) - { - this.VisibilityOptions.RemoveAt(i); - _selectedIndex = Math.Clamp(_selectedIndex, 0, this.VisibilityOptions.Count - 1); - } - } - - private void Swap(int x, int y) - { - _swapX = x; - _swapY = y; - } - } -} \ No newline at end of file diff --git a/LMeter/Helpers/CharacterState.cs b/LMeter/Helpers/CharacterState.cs index f8542d6..9f80e9f 100644 --- a/LMeter/Helpers/CharacterState.cs +++ b/LMeter/Helpers/CharacterState.cs @@ -10,7 +10,15 @@ namespace LMeter.Helpers { public static class CharacterState { - private static readonly uint[] _goldenSaucerIDs = [144, 388, 389, 390, 391, 579, 792, 899, 941]; + private static readonly uint[] _goldSaucerIds = [144, 388, 389, 390, 391, 579, 792, 899, 941]; + private static readonly ushort[] _houseIds = [ + // Small, Medium, Large, Chamber, Apartment + 282, 283, 284, 384, 608, // Mist + 342, 343, 344, 385, 609, // Lavender Beds + 345, 346, 347, 386, 610, // Goblet + 649, 650, 651, 652, 655, // Shirogane + 980, 981, 982, 983, 999, // Empyreum + ]; public static bool IsCharacterBusy() { @@ -24,28 +32,17 @@ public static bool IsCharacterBusy() condition[ConditionFlag.OccupiedSummoningBell]; } - public static bool IsInCombat() + public static bool IsInCombat() => Singletons.Get()[ConditionFlag.InCombat]; + public static bool IsInDuty() => Singletons.Get()[ConditionFlag.BoundByDuty]; + public static bool IsPerforming() => Singletons.Get()[ConditionFlag.Performing]; + public static bool IsEditingHouse() => Singletons.Get()[ConditionFlag.UsingHousingFunctions]; + public static bool IsInDeepDungeon() => Singletons.Get()[ConditionFlag.InDeepDungeon]; + public static bool InZone(ZoneType zone) => zone switch { - ICondition condition = Singletons.Get(); - return condition[ConditionFlag.InCombat]; - } - - public static bool IsInDuty() - { - ICondition condition = Singletons.Get(); - return condition[ConditionFlag.BoundByDuty]; - } - - public static bool IsPerforming() - { - ICondition condition = Singletons.Get(); - return condition[ConditionFlag.Performing]; - } - - public static bool IsInGoldenSaucer() - { - return _goldenSaucerIDs.Any(id => id == Singletons.Get().TerritoryType); - } + ZoneType.GoldSaucer => _goldSaucerIds.Any(id => id == Singletons.Get().TerritoryType), + ZoneType.PlayerHouse => _houseIds.Any(id => id == Singletons.Get().TerritoryType), + _ => false + }; public static Job GetCharacterJob() { diff --git a/LMeter/Helpers/ConfigHelpers.cs b/LMeter/Helpers/ConfigHelpers.cs index fbf1e9c..a029290 100644 --- a/LMeter/Helpers/ConfigHelpers.cs +++ b/LMeter/Helpers/ConfigHelpers.cs @@ -2,12 +2,13 @@ using System.Collections.Generic; using System.IO; using System.IO.Compression; +using System.Numerics; using System.Text; using Dalamud.Interface.ImGuiNotification; using Dalamud.Plugin.Services; using ImGuiNET; +using LMeter.Act.DataStructures; using LMeter.Config; -using LMeter.Meter; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; @@ -25,7 +26,7 @@ public static class ConfigHelpers public static void ExportToClipboard(T toExport) { - string? exportString = ConfigHelpers.GetExportString(toExport); + string? exportString = GetExportString(toExport); if (exportString is not null) { @@ -147,15 +148,110 @@ public static void SaveConfig(LMeterConfig config) } } - public static void ConvertOldConfigs(LMeterConfig config) + public static void ConvertOldConfig(LMeterConfig config) { - // Convert old visibility configs to new ones - foreach (MeterWindow meter in config.MeterList.Meters) - { - if (!meter.VisibilityConfig2.Initialized && - meter.VisibilityConfig2.VisibilityOptions.Count == 0) + foreach (var meter in config.MeterList.Meters) + { + Vector2 size = meter.GeneralConfig.Size; + size -= Vector2.One * meter.GeneralConfig.BorderThickness * 2; + size.AddY(-meter.HeaderConfig.HeaderHeight); + float barHeight = (size.Y - (meter.BarConfig.BarCount - 1) * meter.BarConfig.BarGaps) / meter.BarConfig.BarCount; + float rankTextOffset = meter.BarConfig.ShowRankText ? ImGui.CalcTextSize("00.").X : 0; + BarConfig barConfig = meter.BarConfig; + TextListConfig barTextConfig = meter.BarTextConfig; + + if (!barTextConfig.Initialized && + barTextConfig.Texts.Count == 0) { - meter.VisibilityConfig2.SetOldConfig(meter.VisibilityConfig); + barTextConfig.AddText(new Text("Name") + { + Enabled = true, + TextFormat = barConfig.LeftTextFormat.Replace("[encdps", "[dps"), + TextOffset = barConfig.LeftTextOffset.AddX(rankTextOffset + barHeight - 5f), + TextAlignment = DrawAnchor.Left, + AnchorPoint = DrawAnchor.Left, + TextJobColor = barConfig.LeftTextJobColor, + TextColor = barConfig.BarNameColor, + ShowOutline = barConfig.BarNameShowOutline, + OutlineColor = barConfig.BarNameOutlineColor, + FontKey = barConfig.BarNameFontKey, + FontId = barConfig.BarNameFontId, + ThousandsSeparators = barConfig.ThousandsSeparators + }); + + barTextConfig.AddText(new Text("Data") + { + Enabled = true, + TextFormat = barConfig.RightTextFormat.Replace("[encdps", "[dps"), + TextOffset = barConfig.RightTextOffset, + TextAlignment = DrawAnchor.Right, + AnchorPoint = DrawAnchor.Right, + TextJobColor = barConfig.RightTextJobColor, + TextColor = barConfig.BarDataColor, + ShowOutline = barConfig.BarDataShowOutline, + OutlineColor = barConfig.BarDataOutlineColor, + FontKey = barConfig.BarDataFontKey, + FontId = barConfig.BarDataFontId, + ThousandsSeparators = barConfig.ThousandsSeparators + }); + } + + + HeaderConfig headerConfig = meter.HeaderConfig; + TextListConfig headerTextConfig = meter.HeaderTextConfig; + if (!headerTextConfig.Initialized && + headerTextConfig.Texts.Count == 0) + { + headerTextConfig.AddText(new Text("Encounter Duration") + { + Enabled = true, + TextFormat = "[duration]", + AnchorParent = 0, + TextOffset = headerConfig.DurationOffset, + TextAlignment = DrawAnchor.Left, + AnchorPoint = DrawAnchor.Left, + TextJobColor = false, + TextColor = headerConfig.DurationColor, + ShowOutline = headerConfig.DurationShowOutline, + OutlineColor = headerConfig.DurationOutlineColor, + FontKey = headerConfig.DurationFontKey, + FontId = headerConfig.DurationFontId, + ThousandsSeparators = false + }); + + headerTextConfig.AddText(new Text("Encounter Name") + { + Enabled = true, + TextFormat = "[title]", + AnchorParent = 1, + TextOffset = headerConfig.DurationOffset - headerConfig.NameOffset, + TextAlignment = DrawAnchor.Left, + AnchorPoint = DrawAnchor.Right, + TextJobColor = false, + TextColor = headerConfig.NameColor, + ShowOutline = headerConfig.NameShowOutline, + OutlineColor = headerConfig.NameOutlineColor, + FontKey = headerConfig.NameFontKey, + FontId = headerConfig.NameFontId, + ThousandsSeparators = false + }); + + headerTextConfig.AddText(new Text("Raid Stats") + { + Enabled = true, + TextFormat = headerConfig.RaidStatsFormat, + AnchorParent = 0, + TextOffset = headerConfig.StatsOffset, + TextAlignment = DrawAnchor.Right, + AnchorPoint = DrawAnchor.Right, + TextJobColor = false, + TextColor = headerConfig.RaidStatsColor, + ShowOutline = headerConfig.StatsShowOutline, + OutlineColor = headerConfig.StatsOutlineColor, + FontKey = headerConfig.StatsFontKey, + FontId = headerConfig.StatsFontId, + ThousandsSeparators = false + }); } } } @@ -167,13 +263,18 @@ public static void ConvertOldConfigs(LMeterConfig config) /// public class LMeterSerializationBinder : ISerializationBinder { - // TODO: Make this automatic somehow? - private static List _configTypes = [ + private static readonly List _configTypes = + [ typeof(ActConfig) ]; - private readonly Dictionary typeToName = []; - private readonly Dictionary nameToType = []; + private static readonly Dictionary _typeNameConversions = new() + { + { "VisibilityConfig2", "VisibilityConfig" } + }; + + private readonly Dictionary _typeToName = []; + private readonly Dictionary _nameToType = []; public LMeterSerializationBinder() { @@ -181,15 +282,15 @@ public LMeterSerializationBinder() { if (type.FullName is not null) { - this.typeToName.Add(type, type.FullName.ToLower()); - this.nameToType.Add(type.FullName.ToLower(), type); + _typeToName.Add(type, type.FullName.ToLower()); + _nameToType.Add(type.FullName.ToLower(), type); } } } public void BindToName(Type serializedType, out string? assemblyName, out string? typeName) { - if (this.typeToName.TryGetValue(serializedType, out string? name)) + if (_typeToName.TryGetValue(serializedType, out string? name)) { assemblyName = null; typeName = name; @@ -203,12 +304,28 @@ public void BindToName(Type serializedType, out string? assemblyName, out string public Type BindToType(string? assemblyName, string? typeName) { - if (typeName is not null && - this.nameToType.TryGetValue(typeName.ToLower(), out Type? type)) + if (typeName is null) + { + throw new TypeLoadException("Type name was null."); + } + + if (_nameToType.TryGetValue(typeName.ToLower(), out Type? type)) { return type; } + Type? loadedType = Type.GetType($"{typeName}, {assemblyName}", false); + if (loadedType is null) + { + foreach (var entry in _typeNameConversions) + { + if (typeName.Contains(entry.Key)) + { + typeName = typeName.Replace(entry.Key, entry.Value); + } + } + } + return Type.GetType($"{typeName}, {assemblyName}", true) ?? throw new TypeLoadException($"Unable to load type '{typeName}' from assembly '{assemblyName}'"); } diff --git a/LMeter/Helpers/DefaultProfiles.cs b/LMeter/Helpers/DefaultProfiles.cs new file mode 100644 index 0000000..a60e99c --- /dev/null +++ b/LMeter/Helpers/DefaultProfiles.cs @@ -0,0 +1,8 @@ +namespace LMeter.Helpers +{ + public class DefaultProfiles + { + public const string DefaultDpsMeter = "7F1bc+I2FP4rjKcP7QyltsHc3rgkwC4hGWA33c0wrQNK8MTYjG12N+3wy/rQn9S/0KObLYO5bBZie9cvgI5k+ejo6NM50pH4759//5Z+8p6XSKpL/SvkIacgfN4a1sz+nM/RHCkvDfQFLtm+GeU4qYMs5Ohmy7YejEepvlUdzSiEigk13tiu4Rm2JT45enY9tCgMVgvkGFO38B5NPdtR8zmWceMYn3QPQdUO6hv3UMvvUl0uyHnpA/le56WR8Rf65ipLMq9ULSuk2r49fZLqD7rporzUMo3p03ju2KvHuU9s6tOnRyBZs5Zt2s5ugdAvUkgQB+XrMOelo4WRlz6y71v8ra2xdOb256btzOCVdc9ZYbZJqkEYb+qOG7SHZMTbFkWplEsVucyaFCRJy4IkaWBNVmpluYqbSXkfz6GbLORCm9S81NY9fUy4AYkMkbdyrLHdWjkOsjwuDKblTGUlqKmLdCKF/ToulhLkgKVNs/gLaKqLjMc5vFTVkqM2LxU1buOlbWNuuObQpNhISknNCLmwpsAlvLW9cnSKUbT7eDoZ/FdKmlyryhprRrWqFjW1ppHWYNRaBwzjVl2vPNOw0GZbGDnBXcI5bZjGI3SFIvD+8OAi78QzCK/80ra83kyqF8Okt+gZ3nPxZekAsnzWn/9QytKG2lAYCSAlTtkqrG0Kky35DhQEsxehHJicfMXAXAZKQXg+h0LgigVl4MndijDUjdnI0z2Xi9MnxCtMjTWKI0YIKgh/EapA6MnXBcImUwaVc30ObSA1C+rgp6P1we/6S9tZ6MCMdDdbuhMHPnJ3c/wLPnJtpHtzt567m5EfE3hwPLdXrm7N3BFa6gA/NrbNWJdAL71HjivMTCx5lhazuoU2M0pqpkHGb4R2c7klXr+FTohWtMbUMz4h3whjpiw1OH9jFppv0I7RF++QUYvL9A2XlftTubtj+fCmAramRyDCKdjRyC34Ux+Xy2Sy4Tz2cK4FRjXnKYfrdyG3Z4EfqJvgt82iufdL0u/63T6Ot31Wn7ecb87lgajfm/iFVA3wk8IAZeXIMIScs4yqhjWd286NTv0P2SfYBk4r9M0E0BaIU6IggUkMl35j3zMNFoipGaQRozP5w3L3eBTg8tL4gma4L26NmResGAiUMqn2nYsuTNNYukbQr1gqfncHVE5hz6v4cZ/IXS8QuyaQzzMd8toT3Ekg18D3TNOCzTr/UqgjhAMw5xmeiV4R45QNjFO/C4w74GD9OKgWqBgjKEWtUNpAtcCAzUAtA7WjQA17ULn20j1otS3d+lNBIa7V64Fa6aDhpu715RKJaXKhrILFprBW8wQBCp74ESEuM9wyw+0shhtd/zmAcFGLRKcDuV/Vr3BP1aNRLsmmWwZzR1pyFS1zTzP3dBvlJmQixUuLsS4oUhaOWVDcKPmyBcUEgPXXLCV+H252htWZSZoEv+HHcru7h93uOXe74Ud8a4mZ25253dl+SYZxaVta3Ot1qy8GucySS9/iYuZ1Z4bc0V53Uz8YlO4XEdQfaDQ4gEbCA6CQUuBpS/UqSXR0gDiWEYRwk/ACWOYHt7A3DaLOWBKfufBD6wXaN6MjffEH+mMd1O09m6GXndjgpEc+WN1JN+3JFsyeDSZwWAJnnp35wH0eZ1uKrC1F1pbi5nbSULeeMDT6MxknBHOyA5RJQQqyguBPTjmLH8Ir31oh4RkJDkbgLEbs2PkyS/zOXaAKu2NugxJssm2YkEvCm0fIfPD7rI8evLBaWWAZ4sU6nnMWHeKVb+kQjMyEHxhgHEZoEMtJvgIxRnfrj1CAqQ+AaGsOwDr1T3fwQU8m07CzoC/0R+TZnm4SpyGX+9l3IPI5lr2cepNfJOH582AVrz1K0fCKe7IVjewJRCoazkmFomFG9yoaL8BPE0BzgdnVwgofHBRpYbNMzEmwLPAIIpzixka1KuFTp8hqhE6K2clXzBC35wAe8QWB+rd1U1+sZjmiAtuF8BCQyaC4NEyTaznpB6AlxQ7fa7sy3tuGA5WR4znyrpMZ5LA1feTUm6cte3EPFMs7ZvMU3n/MzqlY7GXbpseEJHPr64Qzolo8y7GLBEfvZRHJO8P1FHqxQ3bQItsc/bZ4vZvRsXsGSQr8SGEocgZmu7YHtAzKsjiPE4Qedw8iGbFm54aHFy1eD85evvuZwdmreZPBRUCn2fPMQC0DtROAWmvYGx+CtaljvD6o4a2IDNS+1/NhW3CWnevP4GxvCAeotntUIEdQULxDs9+OOSZfIzd58Iul6K0eJdZgdktg6D664dt4Ga5ilipVzrBSIkzys60hXm8bw7h5JbcuRrOqgJwhvyJy3Bk04+W4RK95YRyXVJ6kHBNVCS2Xd/qNdOnv1bCdMp0YtboxXzqnasClyndNMIPlUjVqi+22e5WElSboeMKkf1fR9on3xmicEE5losD8mlaVq4PQ/52LmPsfXxyr1fhVAoLCbu6wDt4kRKiHuv9qEPcsVqypisZRoMwxQTAz+PWevUHMAEvFxy3tWlUG1lW+dYpbUa6G8Ko97MTLMYErxZ/EAh6pNmD+lXJohDVihS3gyVfYqGlXxuxDJ4TuWhvexGzb0HnX30vHs67C1cJHDOECx7j5lUMXopC77Ir4+joq4m2IuOn0UwIRw+tOyiCiP2ilDCKacZuNPgTQyxiJncgBokg7IMTwVdxWY6moFCtqYJj790V+DCm3MG/ErRTVkBqLdo6g4oIJOWylSyWa/ZinOTIrVKslPs2FZrkIjRhdxWz7hP9RAS87gFZzU502Ri2FoLgds4hrFH25hMPucJAUprnWOGaOQ3aEViHQvO+W2Wb/XTJWnSmrfJ6rRUDEuJuyEddopW3EvXsbM8dVakoEdhqGZR5aqkSYEtHBpHR9GIeTvjdc494wDe/50LLyZkmxeWLWjPxN0754z4jiQmU96xNyPCGi9HoJ/65DxEfC19kT/gFC+o8yDkQiYRK8F5dauZ69ABJEuRoWNErC8cOciONigb0JiM3GIdnyGn5GxbLSU0BdYxYIEN62Mmfwj05L8XLSa+sK4gqQDZz7JfFjvYeBjUNwLehdod4hclemd730Q35ZtwSCkdbr/wEAAP//AwA="; + public const string DefaultHpsMeter = "7F1bc+I2FP4rjKcP7QyltsHc3rgkwC4hGWA33c0wrYOV4ImxGdvsbtrhl/WhP6l/oUc3WwZz2SzEZtcvgI5k+ejo6NM50pH4759//5Z+8p8XSKpL/SvkI7cgfN6atuF8zudojpSXBvocl+zejHKc1EE2cnWr5dgP5qNU36iOZhQixYQabxzP9E3HFp8cPXs+mhcGyzlyzalXeI+mvuOq+RzLuHHNT7qPoGoX9c17qOV3qS4X5Lz0gXyv8tLI/At9c5UlmVeqlhVSbd+ZPkn1B93yUF5qWeb0aTxzneXjLCA29enTI5Bso+VYjrtdIPSLFBLEQfnaz3npYGHkpY/s+xZ/ayssnZnzuem4Bryy7rtLzDZJNQjjTd31wvaQjGTboiiVcqkil1mTwiRpWZgkDazJSq0sV3EzKe/jGXSTjTxok5qX2rqvjwk3Sl4aIn/p2mOntXRdZPtcGEzLmcpKUFMX6UQKu3VcLCXIAUubZvEX0FQXmY8zeKmqpUdtXipq3MZLx8HccM2hSbGRlHI2I+TCngKX8Nb20tUpRtHu4+l08F8paXKtKmusGdWqWtTUmkZag1FrFTKMW3W99C3TRuttYeQUdwnntGGZjzYZvgHvDw8e8o88g/DKLx3b7xlSvRglvUXP8J6LLwsXkOWz/vyHUpbW1IbCSAgpScpWYW1TmGzJd6ggmL0Y5cDk9CsG5jJUCsLzKRQCVywoA09uV4ShbhojX/c9Ls6AkKwwNdYojhgRqCD8xagCoadfFwibTBlUzvUptIHULKhDkI7Xh6DrLx13rgMz0p2x8CYufOTuZvgXfOTaSPdnXj13Z5AfE3hwPHOWnm4b3ggtdIAfB9tmrEugl94j1xNmJpY8SYtZ3UKbGeVspkHGb4x2c7mlXr+FTohXtMbUNz+hwAjjDhsxOH9jFlpg0I7RF3+fUYvL9E2PlftTubtj+fCmAramRyDCKdjRyCsEUx+Xy2Sy5jz2cK4NRjXnKYfr9yC3Z4MfqFvgtxnx3Acl6Xf9bhfHmz5rwFsuMOfyQNTvLfxCqgb4SWGAsnJkGELOSUZVw57OHPdGp/6HHBAcE6cV+mYCaHPEKXGQwCSGS79x7pkGC8SzGaQxozP9w3L7eBTg8tL8ggzcF7em4YcrBgKlTKp956ELyzIXnhn2K5ZK0N0hlVPY8yp+PCBy1wvErgnk00yHvPYUdxLINfQ9z2nBZpV/KdQRwh6Y803fQq+IccoaxqnfBcbtcbB+HFQLVYwRlKJWKK2hWmjAZqCWgdpBoIY9qFx34e2DM/Cj6k8FhThUrwdqpb2Gm7rTl0slpsmFsgoWm8JazRMEKHjiR4S4zHDLDLeTGG50/WcPwsUtEh0P5H5Vv8I9VQ9GuTSbbhnMHWjJVbTMPc3c002Um5CJFC8tJrqgSFk4ZEFxreTLFhRTANZfs5T4fbjZGVZnJmka/IYfZi0x3W73+lpi5nZnbne2X5Jh3Aswrr0f4wyOcfDjFb1u9cUgl1ly57e4mHndmSF3sNfd1PcGpQdFBPUHGg0OCCLhSSnwtKV6lSQ6OkAcywhDuEl4ASzzg1vYm4ZRZyyJz1zQCuUI7ZvRkb74A/2xCuv2n63Iy45scNIjH6zutJv2ZAtmxwYTOCyhM8/OfOA+T7ItRdaWImtLcX07aajbTxgag5mME8I52QXKpCCFWWHwJ6ecxA/hlW+skPCMFAcjcBZjduwCmaV+5y5Uhe0xt2EJNtk2LMgl4c0jZD0EfdZHD35UrWywDPFiHc85iQ7xyjd0CEZmyg8MMA5jNIjlpF+BGKPb9UcowNQHQLQ1A2CdBqc7+KAnk2nUWdDn+iPyHV+3iNOQy/0cOBD5HMteTP3JL5Lw/Gmwitcep2h4xT3dikb2BGIVDeechaJhRncqGi/ATxNAc4HZ5dyOHhwUaVGzTMxJsSzwCCKc4sbGtSrlU6fIaoxOitnpV8wIt6cAHvEFofq3dUufL40cUYHNQngIyGRQXJqWxbWc9APQ0mKH77RdGe9t04XKyPEcedvJDHLYmj5y7M3TljO/B4rtH7J5Cu8/ZOdULPaybdNDQpK59XXEGVEtnuTYRYqj97KI5K3hegq92CE7aJFtjn7T5mj3ZnTovmiaAj/OMBQ5A7Nt2wNaBmVZnMcRQo+7e3c/iTU7M328aPF6cPby3c8Mzl7NmwwvAjrOnmcGahmoHQHUWsPeeB+sTV3z9UENb0VkoPa9ng/bgLPsXH8GZztDOEC1vYMCOcKC4h2a/XbCMfkaucmDXyxFb/UosQazWwIj99EN3ybLcBWzVKlyhpUSYZKfbY3wetsYJs0ruXUxnlUF5Az5FZHjzqCZLMcles0L47ik8iTlmKhKZLm802+cl/5eDdtnphOjVjfhS+dUDbhU+a4JZrBcqsZtsd12r9Kw0gQdT5gM7iraPPHeGI1TwqlMFJhf06pydRD6v3ORcP/ji2O1Gr9KQFDY9R3WwZuUCHVf918Nkp7FijVV0TgKlDkmCGYGv96zN0gYYKn4uKVdq8rAusq3TnErytUIXrWHnWQ5JnClBJNYyCPVBsy/Uo6MsEaisAU8BQobN+3KmH3ohMhda8ObhG0bOu8Ge+l41lW4WgSIIVzgmDS/cuRCFHKXXRFfX0dFvAkRN53+mUDE8LpzZhDRH7TODCKaSZuNAQTQyxiJncgBokg7IMLwVdJWY6moFCtqaJgH90V+jCi3MG8krRTViBqLdo6g4oIJOWydl0o0+wlPc2RWqFZLfJqLzHIxGjG6Stj2if6jAl52AK3mpjptjFqKQHE7YRHXKPpyCUfd4TApTHOtccIcR+wIrUKgedcts83+u3SsOlNW+TxXi4GIcffMRlyjdW4j7t3bhDmuUlMitNMwLPPQUiXGlIgPJqXrwzic9L3pmfemZfrP+5aV10uKzROzDPI3TbviPWOKC5X17E/I9YWI0usF/LsOER8JX2dPBAcI6T/KuBCJhEnwXlxq6fnOHEgQ5Wra0CgJxw9zIo6LBfYmIDYHh2TLK/gZF8tKTwF1TSMUILxtaRnwj04L8XLSa/sK4gqQA5wHJfFjvYeBg0Nwbehdod4h8paWf70IQn5Zt4SCkVar/wEAAP//AwA="; + } +} \ No newline at end of file diff --git a/LMeter/Helpers/DrawHelpers.cs b/LMeter/Helpers/DrawHelpers.cs index 9f2606a..c888b7a 100644 --- a/LMeter/Helpers/DrawHelpers.cs +++ b/LMeter/Helpers/DrawHelpers.cs @@ -5,6 +5,7 @@ using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Plugin.Services; using ImGuiNET; +using LMeter.Config; namespace LMeter.Helpers { @@ -47,7 +48,8 @@ public static void DrawNotification( Title = title, Content = message, Type = type, - InitialDuration = TimeSpan.FromMilliseconds(durationInMs) + InitialDuration = TimeSpan.FromMilliseconds(durationInMs), + Minimized = false }; Singletons.Get().AddNotification(notification); @@ -59,11 +61,11 @@ public static void DrawNestIndicator(int depth) // Shift cursor to the right to pad for children with depth more than 1. // 26 is an arbitrary value I found to be around half the width of a checkbox Vector2 oldCursor = ImGui.GetCursorPos(); - Vector2 offset = new(26 * Math.Max((depth - 1), 0), 2); + Vector2 offset = new(26 * Math.Max(depth - 1, 0), 0); ImGui.SetCursorPos(oldCursor + offset); ImGui.TextColored(new Vector4(229f / 255f, 57f / 255f, 57f / 255f, 1f), "\u2002\u2514"); - ImGui.SameLine(); ImGui.SetCursorPosY(oldCursor.Y); + ImGui.SameLine(); } public static void DrawSpacing(int spacingSize) @@ -80,7 +82,7 @@ public static void DrawIcon( Vector2 size, ImDrawListPtr drawList) { - IDalamudTextureWrap? tex = Singletons.Get().GetTextureFromIconId(iconId, 0, true); + IDalamudTextureWrap? tex = TextureCache.GetTextureById(iconId); if (tex is null) { @@ -96,11 +98,10 @@ public static void DrawIcon( Vector2 size, bool cropIcon, int stackCount, - bool desaturate, float opacity, ImDrawListPtr drawList) { - IDalamudTextureWrap? tex = Singletons.Get().GetTextureFromIconId(iconId, (uint)stackCount, true, desaturate); + IDalamudTextureWrap? tex = TextureCache.GetTextureById(iconId, (uint)stackCount, true); if (tex is null) { @@ -113,6 +114,37 @@ public static void DrawIcon( drawList.AddImage(tex.ImGuiHandle, position, position + size, uv0, uv1, alpha); } + public static void DrawFontSelector(string label, ref string fontKey, ref int fontId) + { + string[] fontOptions = FontsManager.GetFontList(); + if (fontOptions.Length == 0) + { + return; + } + + if (!FontsManager.ValidateFont(fontOptions, fontId, fontKey)) + { + fontId = 0; + for (int i = 0; i < fontOptions.Length; i++) + { + if (fontKey.Equals(fontOptions[i])) + { + fontId = i; + } + } + } + + ImGui.Combo(label, ref fontId, fontOptions, fontOptions.Length); + fontKey = fontOptions[fontId]; + } + + public static void DrawColorSelector(string label, ref ConfigColor color) + { + Vector4 vector = color.Vector; + ImGui.ColorEdit4(label, ref vector, ImGuiColorEditFlags.AlphaPreview | ImGuiColorEditFlags.AlphaBar); + color.Vector = vector; + } + public static (Vector2, Vector2) GetTexCoordinates(IDalamudTextureWrap texture, Vector2 size, bool cropIcon = true) { if (texture == null) @@ -202,7 +234,6 @@ public static void DrawText( uint outlineColor = 0xFF000000, int thickness = 1) { - // outline if (outline) { for (int i = 1; i < thickness + 1; i++) @@ -218,8 +249,38 @@ public static void DrawText( } } - // text drawList.AddText(new Vector2(pos.X, pos.Y), color, text); } + + public static string? DrawTextTagsList(string[] tags) + { + string? selectedTag = null; + + if (ImGui.Button("Tags")) + { + ImGui.OpenPopup("LMeter_TextTagsPopup"); + } + + ImGui.SetNextWindowSize(new(210, 300)); + if (ImGui.BeginPopup("LMeter_TextTagsPopup", ImGuiWindowFlags.NoMove)) + { + if (ImGui.BeginChild("##LMeter_TextTags_List", new Vector2(195, 284), true)) + { + foreach (string tag in tags) + { + if (ImGui.Selectable(tag)) + { + selectedTag = tag; + } + } + + ImGui.EndChild(); + } + + ImGui.EndPopup(); + } + + return selectedTag; + } } } diff --git a/LMeter/Helpers/Enums.cs b/LMeter/Helpers/Enums.cs index 234b2fb..e6abce6 100644 --- a/LMeter/Helpers/Enums.cs +++ b/LMeter/Helpers/Enums.cs @@ -1,5 +1,28 @@ namespace LMeter.Helpers { + public enum BooleanOperator + { + And, + Or, + Xor + } + + public enum VisibilityConditionType + { + AlwaysTrue, + InCombat, + InDuty, + Performing, + Zone, + Job + } + + public enum ZoneType + { + GoldSaucer, + PlayerHouse + } + public enum MeterDataType { Damage, diff --git a/LMeter/Helpers/FontsManager.cs b/LMeter/Helpers/FontsManager.cs index 462d38b..249cf71 100644 --- a/LMeter/Helpers/FontsManager.cs +++ b/LMeter/Helpers/FontsManager.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Linq; using Dalamud.Interface; using Dalamud.Interface.ManagedFontAtlas; using Dalamud.Interface.Utility; @@ -9,27 +10,25 @@ namespace LMeter.Helpers { - public struct FontData + public struct FontData( + string name, + string path, + int size, + bool chinese, + bool korean) { - public string Name; - public int Size; - public bool Chinese; - public bool Korean; - - public FontData(string name, int size, bool chinese, bool korean) - { - Name = name; - Size = size; - Chinese = chinese; - Korean = korean; - } + public string Name = name; + public string Path = path; + public int Size = size; + public bool Chinese = chinese; + public bool Korean = korean; } public class FontScope : IDisposable { private readonly IFontHandle? _handle; - public FontScope(IFontHandle? handle) + public FontScope(IFontHandle? handle = null) { _handle = handle; _handle?.Push(); @@ -73,8 +72,8 @@ private void BuildFonts(IEnumerable fontData) foreach (FontData font in fontData) { - string fontPath = $"{fontDir}{font.Name}.ttf"; - if (!File.Exists(fontPath)) + string path = string.IsNullOrEmpty(font.Path) ? $"{fontDir}{font.Name}.ttf" : font.Path; + if (!File.Exists(path)) { continue; } @@ -87,7 +86,7 @@ private void BuildFonts(IEnumerable fontData) ( tk => tk.AddFontFromFile ( - fontPath, + path, new SafeFontConfig { SizePx = font.Size, @@ -101,7 +100,7 @@ private void BuildFonts(IEnumerable fontData) } catch (Exception ex) { - Singletons.Get().Error($"Failed to load font from path [{fontPath}]!"); + Singletons.Get().Error($"Failed to load font from path [{path}]!"); Singletons.Get().Error(ex.ToString()); } } @@ -109,6 +108,21 @@ private void BuildFonts(IEnumerable fontData) _fontList = [DalamudFontKey, .. _imGuiFonts.Keys]; } + public static FontData[] GetDefaultFontData() + { + FontData[] defaults = new FontData[DefaultFontKeys.Count]; + for (int i = 0; i < DefaultFontKeys.Count; i++) + { + string[] splits = DefaultFontKeys[i].Split("_", StringSplitOptions.RemoveEmptyEntries); + if (splits.Length == 2 && int.TryParse(splits[1], out int size)) + { + defaults[i] = new(splits[0], $"{GetUserFontPath()}{splits[0]}.ttf", size, false, false); + } + } + + return defaults; + } + public void UpdateFonts(IEnumerable fonts) { this.BuildFonts(fonts); @@ -179,7 +193,7 @@ public static FontScope PushFont(string fontKey) } } - return new FontScope(null); + return new FontScope(); } public static string[] GetFontList() @@ -222,7 +236,7 @@ public static void CopyPluginFontsToUserPath() string[] pluginFonts; try { - pluginFonts = Directory.GetFiles(pluginFontPath, "*.ttf"); + pluginFonts = Directory.GetFiles(pluginFontPath).Where(x => x.EndsWith(".ttf") || x.EndsWith(".otf")).ToArray(); } catch { @@ -266,7 +280,14 @@ public static string GetUserFontPath() return Path.Join(Plugin.ConfigFileDir, "\\Fonts\\"); } - public static string[] GetFontNamesFromPath(string? path) + public static string GetFontName(string? fontPath, string fontFile) + { + return fontFile.Replace(fontPath ?? string.Empty, string.Empty) + .Replace(".otf", string.Empty, StringComparison.OrdinalIgnoreCase) + .Replace(".ttf", string.Empty, StringComparison.OrdinalIgnoreCase); + } + + public static string[] GetFontPaths(string? path) { if (string.IsNullOrEmpty(path)) { @@ -276,20 +297,13 @@ public static string[] GetFontNamesFromPath(string? path) string[] fonts; try { - fonts = Directory.GetFiles(path, "*.ttf"); + fonts = Directory.GetFiles(path).Where(x => x.EndsWith(".ttf") || x.EndsWith(".otf")).ToArray(); } catch { fonts = []; } - for (int i = 0; i < fonts.Length; i++) - { - fonts[i] = fonts[i] - .Replace(path, string.Empty) - .Replace(".ttf", string.Empty, StringComparison.OrdinalIgnoreCase); - } - return fonts; } diff --git a/LMeter/Helpers/TexturesCache.cs b/LMeter/Helpers/TexturesCache.cs index b28fef7..a10fc44 100644 --- a/LMeter/Helpers/TexturesCache.cs +++ b/LMeter/Helpers/TexturesCache.cs @@ -1,85 +1,19 @@ using System; -using System.Collections.Generic; using Dalamud.Interface.Textures; using Dalamud.Interface.Textures.TextureWraps; using Dalamud.Plugin.Services; -using Dalamud.Utility; -using Lumina.Data.Files; namespace LMeter.Helpers { - public class TexturesCache : IPluginDisposable + public class TextureCache : IPluginDisposable { - private readonly Dictionary _desaturatedCache; - - public TexturesCache() - { - _desaturatedCache = []; - } - - public IDalamudTextureWrap? GetTextureFromIconId( + public static IDalamudTextureWrap? GetTextureById( uint iconId, uint stackCount = 0, - bool hdIcon = true, - bool greyScale = false) - { - if (!greyScale) - { - return Singletons.Get().GetFromGameIcon(iconId + stackCount).GetWrapOrDefault(); - } - - if (_desaturatedCache.TryGetValue(iconId + stackCount, out IDalamudTextureWrap? t)) - { - return t; - } - - string? path = Singletons.Get().GetIconPath(new GameIconLookup(iconId: iconId, hiRes: hdIcon)); - if (path != null) - { - path = Singletons.Get().GetSubstitutedPath(path); - IDalamudTextureWrap? texture = GetDesaturatedTextureWrap(path); - if (texture != null) - { - _desaturatedCache.Add(iconId + stackCount, texture); - } - - return texture; - } - - return null; - } - - private static IDalamudTextureWrap? GetDesaturatedTextureWrap(string path) + bool hdIcon = true) { - TexFile? file = Singletons.Get().GetFile(path); - if (file is null) - { - return null; - } - - byte[] bytes = file.GetRgbaImageData(); - DesaturateBytes(ref bytes); - return Singletons.Get().CreateFromRaw(RawImageSpecification.Rgba32(file.Header.Width, file.Header.Height), bytes); - } - - private static void DesaturateBytes(ref byte[] bytes) - { - if (bytes.Length % 4 != 0) - { - return; - } - - for (int i = 0; i < bytes.Length; i += 4) - { - int r = bytes[i] >> 2; - int g = bytes[i + 1] >> 1; - int b = bytes[i + 2] >> 3; - byte lum = (byte)(r + g + b); - - bytes[i] = lum; - bytes[i + 1] = lum; - bytes[i + 2] = lum; - } + string path = Singletons.Get().GetIconPath(new GameIconLookup(iconId: iconId + stackCount, hiRes: hdIcon)); + return Singletons.Get().GetFromGame(path).GetWrapOrDefault(); } public void Dispose() @@ -90,15 +24,6 @@ public void Dispose() protected virtual void Dispose(bool disposing) { - if (disposing) - { - foreach (IDalamudTextureWrap tex in _desaturatedCache.Values) - { - tex.Dispose(); - } - - _desaturatedCache.Clear(); - } } } } \ No newline at end of file diff --git a/LMeter/Helpers/Utils.cs b/LMeter/Helpers/Utils.cs index a89ce12..da07362 100644 --- a/LMeter/Helpers/Utils.cs +++ b/LMeter/Helpers/Utils.cs @@ -9,21 +9,53 @@ namespace LMeter.Helpers { public static class Utils { - public static Vector2 GetAnchoredPosition(Vector2 position, Vector2 size, DrawAnchor anchor) + public static readonly string[] AnchorOptions = Enum.GetNames(typeof(DrawAnchor)); + + public static Vector2 GetAnchoredPosition(Vector2 position, Vector2 size, DrawAnchor anchor) => anchor switch { - return anchor switch - { - DrawAnchor.Center => position - size / 2f, - DrawAnchor.Left => position + new Vector2(0, -size.Y / 2f), - DrawAnchor.Right => position + new Vector2(-size.X, -size.Y / 2f), - DrawAnchor.Top => position + new Vector2(-size.X / 2f, 0), - DrawAnchor.TopLeft => position, - DrawAnchor.TopRight => position + new Vector2(-size.X, 0), - DrawAnchor.Bottom => position + new Vector2(-size.X / 2f, -size.Y), - DrawAnchor.BottomLeft => position + new Vector2(0, -size.Y), - DrawAnchor.BottomRight => position + new Vector2(-size.X, -size.Y), - _ => position - }; + DrawAnchor.Center => position - size / 2f, + DrawAnchor.Left => position + new Vector2(0, -size.Y / 2f), + DrawAnchor.Right => position + new Vector2(-size.X, -size.Y / 2f), + DrawAnchor.Top => position + new Vector2(-size.X / 2f, 0), + DrawAnchor.TopLeft => position, + DrawAnchor.TopRight => position + new Vector2(-size.X, 0), + DrawAnchor.Bottom => position + new Vector2(-size.X / 2f, -size.Y), + DrawAnchor.BottomLeft => position + new Vector2(0, -size.Y), + DrawAnchor.BottomRight => position + new Vector2(-size.X, -size.Y), + _ => position + }; + + public static Vector2 GetTopLeft(Vector2 anchorPoint, Vector2 textBoxSize, DrawAnchor anchor) => anchor switch + { + DrawAnchor.Center => anchorPoint + new Vector2(-textBoxSize.X / 2, -textBoxSize.Y / 2), + DrawAnchor.Left => anchorPoint + new Vector2(-textBoxSize.X, -textBoxSize.Y / 2), + DrawAnchor.Right => anchorPoint + new Vector2(0, -textBoxSize.Y / 2), + DrawAnchor.Top => anchorPoint + new Vector2(-textBoxSize.X / 2, -textBoxSize.Y), + DrawAnchor.TopLeft => anchorPoint + new Vector2(-textBoxSize.X, -textBoxSize.Y), + DrawAnchor.TopRight => anchorPoint + new Vector2(0, -textBoxSize.Y), + DrawAnchor.Bottom => anchorPoint + new Vector2(-textBoxSize.X / 2, textBoxSize.Y), + DrawAnchor.BottomLeft => anchorPoint + new Vector2(-textBoxSize.X, textBoxSize.Y), + DrawAnchor.BottomRight => anchorPoint + new Vector2(0, textBoxSize.Y), + _ => anchorPoint + }; + + public static DrawAnchor Opposite(this DrawAnchor anchor) => anchor switch + { + DrawAnchor.Center => DrawAnchor.Center, + DrawAnchor.Left => DrawAnchor.Right, + DrawAnchor.Right => DrawAnchor.Left, + DrawAnchor.Top => DrawAnchor.Bottom, + DrawAnchor.TopLeft => DrawAnchor.BottomRight, + DrawAnchor.TopRight => DrawAnchor.BottomLeft, + DrawAnchor.Bottom => DrawAnchor.Top, + DrawAnchor.BottomLeft => DrawAnchor.TopRight, + DrawAnchor.BottomRight => DrawAnchor.TopLeft, + _ => anchor + }; + + public static Vector2 GetTextPos(Vector2 parentPos, Vector2 parentSize, Vector2 textSize, DrawAnchor textAlignment) + { + return GetAnchoredPosition(GetAnchoredPosition(parentPos, -parentSize, textAlignment), textSize, textAlignment); } public static IGameObject? FindTargetOfTarget(IGameObject? player, IGameObject? target) @@ -81,10 +113,9 @@ public static void OpenUrl(string url) } } - public static string GetTagsTooltip(string[] textTags) + public static string GetTagsTooltip() { - return $"Available Text Tags:\n\n{string.Join("\n", textTags)}\n\n" + - "Append the characters ':k' to a numeric tag to kilo-format it.\n" + + return $"Append the characters ':k' to a numeric tag to kilo-format it.\n" + "Append a '.' and a number to limit the number of characters,\n" + "or the number of decimals when used with numeric values.\n\nExamples:\n" + "[damagetotal] => 123,456\n" + diff --git a/LMeter/LMeter.csproj b/LMeter/LMeter.csproj index fd72f56..aaabca6 100644 --- a/LMeter/LMeter.csproj +++ b/LMeter/LMeter.csproj @@ -10,9 +10,9 @@ LMeter - 0.3.1.0 - 0.3.1.0 - 0.3.1.0 + 0.4.0.0 + 0.4.0.0 + 0.4.0.0 diff --git a/LMeter/Meter/MeterWindow.cs b/LMeter/Meter/MeterWindow.cs index 9201fea..6e5534b 100644 --- a/LMeter/Meter/MeterWindow.cs +++ b/LMeter/Meter/MeterWindow.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Numerics; using Dalamud.Plugin.Services; using ImGuiNET; @@ -11,8 +12,8 @@ namespace LMeter.Meter { - public class MeterWindow : IConfigurable - { + public class MeterWindow(string name) : IConfigurable + { [JsonIgnore] private bool _lastFrameWasUnlocked = false; [JsonIgnore] private bool _lastFrameWasDragging = false; [JsonIgnore] private bool _lastFrameWasPreview = false; @@ -24,44 +25,42 @@ public class MeterWindow : IConfigurable [JsonIgnore] private int _eventIndex = -1; [JsonIgnore] private ActEvent? _previewEvent = null; [JsonIgnore] private int _scrollPosition = 0; + [JsonIgnore] private float _scrollShift = 0; [JsonIgnore] private DateTime? _lastSortedTimestamp = null; [JsonIgnore] private List _lastSortedCombatants = []; + [JsonIgnore] public string Id { get; init; } = $"LMeter_MeterWindow_{Guid.NewGuid()}"; - [JsonIgnore] public string ID { get; init; } + public string Name { get; set; } = name; - public string Name { get; set; } - - public GeneralConfig GeneralConfig { get; set; } - - public HeaderConfig HeaderConfig { get; set; } - - public BarConfig BarConfig { get; set; } - - public BarColorsConfig BarColorsConfig { get; set; } - - public VisibilityConfig VisibilityConfig { get; set; } - - public VisibilityConfig2 VisibilityConfig2 { get; set; } - - public MeterWindow(string name) - { - this.Name = name; - this.ID = $"LMeter_MeterWindow_{Guid.NewGuid()}"; - this.GeneralConfig = new GeneralConfig(); - this.HeaderConfig = new HeaderConfig(); - this.BarConfig = new BarConfig(); - this.BarColorsConfig = new BarColorsConfig(); - this.VisibilityConfig = new VisibilityConfig(); - this.VisibilityConfig2 = new VisibilityConfig2(); - } + public bool Enabled = true; + public GeneralConfig GeneralConfig { get; set; } = new GeneralConfig(); + public HeaderConfig HeaderConfig { get; set; } = new HeaderConfig(); + public TextListConfig HeaderTextConfig { get; set; } = new("Header Texts"); + public TextListConfig FooterTextConfig { get; set; } = new("Footer Texts"); + public BarConfig BarConfig { get; set; } = new BarConfig(); + public TextListConfig BarTextConfig { get; set; } = new("Bar Texts"); + public BarColorsConfig BarColorsConfig { get; set; } = new BarColorsConfig(); + public VisibilityConfig VisibilityConfig { get; set; } = new VisibilityConfig(); public IEnumerable GetConfigPages() { yield return this.GeneralConfig; yield return this.HeaderConfig; + + if (this.HeaderConfig.ShowHeader) + { + yield return this.HeaderTextConfig; + } + + if (this.HeaderConfig.ShowFooter) + { + yield return this.FooterTextConfig; + } + yield return this.BarConfig; + yield return this.BarTextConfig; yield return this.BarColorsConfig; - yield return this.VisibilityConfig2; + yield return this.VisibilityConfig; } public void ImportPage(IConfigPage page) @@ -73,10 +72,27 @@ public void ImportPage(IConfigPage page) break; case HeaderConfig newPage: this.HeaderConfig = newPage; + break; + case TextListConfig newPage: + if (this.HeaderTextConfig.Active) + { + newPage.NameInternal = "Header Texts"; + this.HeaderTextConfig = newPage; + } + + if (this.FooterTextConfig.Active) + { + newPage.NameInternal = "Footer Texts"; + this.FooterTextConfig = newPage; + } + break; case BarConfig newPage: this.BarConfig = newPage; break; + case TextListConfig newPage: + this.BarTextConfig = newPage; + break; case BarColorsConfig newPage: this.BarColorsConfig = newPage; break; @@ -86,12 +102,21 @@ public void ImportPage(IConfigPage page) } } - public static MeterWindow GetDefaultMeter(string name) + public static MeterWindow GetDefaultMeter(MeterDataType type, string name = "Default") { - MeterWindow newMeter = new(name); - newMeter.ImportPage(newMeter.HeaderConfig.GetDefault()); - newMeter.ImportPage(newMeter.BarConfig.GetDefault()); - return newMeter; + MeterWindow? newMeter = type switch + { + MeterDataType.Damage => ConfigHelpers.GetFromImportString(DefaultProfiles.DefaultDpsMeter), + MeterDataType.Healing => ConfigHelpers.GetFromImportString(DefaultProfiles.DefaultHpsMeter), + _ => ConfigHelpers.GetFromImportString(DefaultProfiles.DefaultDpsMeter) + }; + + if (newMeter is not null) + { + newMeter.Name = name; + } + + return newMeter ?? new MeterWindow(name); } public void Clear() @@ -110,15 +135,41 @@ protected void UpdateDragData(Vector2 pos, Vector2 size, bool locked) _lastFrameWasDragging = _hovered || _dragging; } + private bool ShouldDraw(Vector2 pos, Vector2 size) + { + if (_dragging) + { + return true; + } + + if (!this.GeneralConfig.Preview && !this.VisibilityConfig.IsVisible() && + !(this.VisibilityConfig.ShowOnMouseover && ImGui.IsMouseHoveringRect(pos, pos + size))) + { + return false; + } + + if (this.VisibilityConfig.ShouldClip && + Singletons.Get().GetClipRectForArea(pos, size).HasValue) + { + return false; + } + + return true; + } + public void Draw(Vector2 pos) { - if (!this.GeneralConfig.Preview && !this.VisibilityConfig2.IsVisible()) + if (!this.Enabled) { return; } Vector2 localPos = pos + this.GeneralConfig.Position; Vector2 size = this.GeneralConfig.Size; + if (!this.ShouldDraw(localPos, size)) + { + return; + } if (ImGui.IsMouseHoveringRect(localPos, localPos + size)) { @@ -126,22 +177,18 @@ public void Draw(Vector2 pos) if (ImGui.IsMouseClicked(ImGuiMouseButton.Right) && !this.GeneralConfig.Preview) { - ImGui.OpenPopup($"{this.ID}_ContextMenu", ImGuiPopupFlags.MouseButtonRight); + ImGui.OpenPopup($"{this.Id}_ContextMenu", ImGuiPopupFlags.MouseButtonRight); } } - if (this.DrawContextMenu($"{this.ID}_ContextMenu", out int index)) + bool contextMenuOpen = this.DrawContextMenu($"{this.Id}_ContextMenu", out bool selected, out int index); + if (contextMenuOpen && selected) { _eventIndex = index; _lastSortedTimestamp = null; _lastSortedCombatants = []; _scrollPosition = 0; } - else if (this.VisibilityConfig2.ShouldClip && - Singletons.Get().GetClipRectForArea(localPos, size).HasValue) - { - return; - } bool combat = CharacterState.IsInCombat(); if (this.GeneralConfig.ReturnToCurrent && !_lastFrameWasCombat && combat) @@ -151,7 +198,7 @@ public void Draw(Vector2 pos) this.UpdateDragData(localPos, size, this.GeneralConfig.Lock); bool needsInput = !this.GeneralConfig.ClickThrough; - DrawHelpers.DrawInWindow($"##{this.ID}", localPos, size, needsInput, _locked || this.GeneralConfig.Lock, (drawList) => + DrawHelpers.DrawInWindow($"##{this.Id}", localPos, size, needsInput, _locked || this.GeneralConfig.Lock, (drawList) => { if (_unlocked) { @@ -164,7 +211,7 @@ public void Draw(Vector2 pos) this.GeneralConfig.Size = size; } } - + if (this.GeneralConfig.ShowBorder) { Vector2 borderPos = localPos; @@ -192,10 +239,59 @@ public void Draw(Vector2 pos) } ActEvent? actEvent = this.GeneralConfig.Preview ? _previewEvent : Singletons.Get().GetEvent(_eventIndex); + ConfigColor jobColor = this.BarColorsConfig.GetColor(CharacterState.GetCharacterJob()); + + Vector2 footerPos = localPos.AddY(size.Y - this.HeaderConfig.FooterHeight); + if (this.HeaderConfig.ShowHeader) + { + (localPos, size) = DrawHeader( + drawList, + this.HeaderConfig, + this.HeaderTextConfig, + localPos, + size, + jobColor, + actEvent?.Encounter); + } + + Vector2 backgroundSize = this.HeaderConfig.ShowFooter ? size.AddY(-this.HeaderConfig.FooterHeight) : size; + drawList.AddRectFilled(localPos, localPos + backgroundSize, this.GeneralConfig.BackgroundColor.Base); + if (this.BarConfig.ShowColumnHeader && actEvent is not null) + { + List columnHeaderTexts = GetColumnHeaderTexts(this.BarTextConfig.Texts, this.BarConfig); + Vector2 columnHeaderSize = new(size.X, this.BarConfig.ColumnHeaderHeight); + drawList.AddRectFilled(localPos, localPos + columnHeaderSize, this.BarConfig.ColumnHeaderColor.Base); + DrawBarTexts( + drawList, + columnHeaderTexts, + localPos + this.BarConfig.ColumnHeaderOffset, + columnHeaderSize, + jobColor, + actEvent); + + (localPos, size) = (localPos.AddY(columnHeaderSize.Y), size.AddY(-columnHeaderSize.Y)); + } + + if (this.HeaderConfig.ShowFooter) + { + size = size.AddY(-this.HeaderConfig.FooterHeight); + } - (localPos, size) = this.HeaderConfig.DrawHeader(localPos, size, actEvent?.Encounter, drawList); - drawList.AddRectFilled(localPos, localPos + size, this.GeneralConfig.BackgroundColor.Base); + ImGui.PushClipRect(localPos, localPos + size, false); this.DrawBars(drawList, localPos, size, actEvent); + ImGui.PopClipRect(); + + if (this.HeaderConfig.ShowFooter) + { + DrawFooter( + drawList, + this.HeaderConfig, + this.FooterTextConfig, + footerPos, + size, + jobColor, + actEvent?.Encounter); + } }); _lastFrameWasUnlocked = _unlocked; @@ -203,6 +299,79 @@ public void Draw(Vector2 pos) _lastFrameWasCombat = combat; } + private static List GetColumnHeaderTexts(List texts, BarConfig config) + { + List newTexts = [.. texts.Select(x => x.Clone())]; + foreach (Text text in newTexts) + { + text.TextFormat = text.Name; + text.TextColor = config.ColumnHeaderTextColor; + text.ShowOutline = config.ColumnHeaderShowOutline; + text.OutlineColor = config.ColumnHeaderOutlineColor; + text.FontKey = config.UseColumnFont ? text.FontKey : config.ColumnHeaderFontKey; + text.FontId = config.UseColumnFont ? text.FontId : config.ColumnHeaderFontId; + } + + return newTexts; + } + + private static (Vector2, Vector2) DrawHeader( + ImDrawListPtr drawList, + HeaderConfig headerConfig, + TextListConfig headerTextConfig, + Vector2 pos, + Vector2 size, + ConfigColor jobColor, + Encounter? encounter) + { + Vector2 headerSize = new(size.X, headerConfig.HeaderHeight); + drawList.AddRectFilled(pos, pos + headerSize, headerConfig.BackgroundColor.Base); + + if (encounter is null && headerConfig.ShowVersion) + { + using (FontsManager.PushFont(headerConfig.VersionFontKey)) + { + string version = $" LMeter v{Plugin.Version} "; + Vector2 versionSize = ImGui.CalcTextSize(version); + Vector2 versionPos = Utils.GetAnchoredPosition(pos, -headerSize, DrawAnchor.Left); + versionPos = Utils.GetAnchoredPosition(versionPos, versionSize, DrawAnchor.Left); + DrawHelpers.DrawText( + drawList, + version, + versionPos + headerConfig.VersionOffset, + headerConfig.VersionColor.Base, + headerConfig.VersionShowOutline, + headerConfig.VersionOutlineColor.Base); + } + } + else if (encounter is not null) + { + DrawBarTexts(drawList, headerTextConfig.Texts, pos, headerSize, jobColor, encounter); + } + + return (pos.AddY(headerConfig.HeaderHeight), size.AddY(-headerConfig.HeaderHeight)); + } + + private static (Vector2, Vector2) DrawFooter( + ImDrawListPtr drawList, + HeaderConfig headerConfig, + TextListConfig footerTextConfig, + Vector2 pos, + Vector2 size, + ConfigColor jobColor, + Encounter? encounter) + { + Vector2 footerSize = new(size.X, headerConfig.FooterHeight); + drawList.AddRectFilled(pos, pos + footerSize, headerConfig.FooterBackgroundColor.Base); + + if (encounter is not null) + { + DrawBarTexts(drawList, footerTextConfig.Texts, pos, footerSize, jobColor, encounter); + } + + return (pos.AddY(headerConfig.HeaderHeight), size.AddY(-headerConfig.HeaderHeight)); + } + private void DrawBars(ImDrawListPtr drawList, Vector2 localPos, Vector2 size, ActEvent? actEvent) { if (actEvent?.Combatants is not null && actEvent.Combatants.Count != 0) @@ -218,22 +387,48 @@ private void DrawBars(ImDrawListPtr drawList, Vector2 localPos, Vector2 size, Ac MeterDataType.DamageTaken => sortedCombatants[0].DamageTaken?.Value ?? 0, _ => 0 }; + + int barCount = this.BarConfig.BarCount; + float margin = 0; + if (this.BarConfig.BarHeightType == 1) + { + float total = 0; + barCount = 0; + do + { + barCount++; + total += this.BarConfig.BarHeight + this.BarConfig.BarGaps; + } + while (total <= size.Y); + margin = total - size.Y - this.BarConfig.BarGaps; + } int currentIndex = 0; string playerName = Singletons.Get().LocalPlayer?.Name.ToString() ?? "YOU"; - - if (sortedCombatants.Count > this.BarConfig.BarCount) + if (sortedCombatants.Count > barCount) { - currentIndex = Math.Clamp(_scrollPosition, 0, sortedCombatants.Count - this.BarConfig.BarCount); + int unclampedScroll = _scrollPosition; + currentIndex = Math.Clamp(_scrollPosition, 0, sortedCombatants.Count - barCount); _scrollPosition = currentIndex; - if (this.BarConfig.AlwaysShowSelf) + if (margin > 0 && _scrollPosition < unclampedScroll) + { + _scrollShift = margin; + } + + if (unclampedScroll < 0) + { + _scrollShift = 0; + } + + if (this.BarConfig.AlwaysShowSelf && this.BarConfig.BarHeightType == 0) { MovePlayerIntoViewableRange(sortedCombatants, _scrollPosition, playerName); } } - int maxIndex = Math.Min(currentIndex + this.BarConfig.BarCount, sortedCombatants.Count); + localPos = localPos.AddY(-_scrollShift); + int maxIndex = Math.Min(currentIndex + barCount, sortedCombatants.Count); for (; currentIndex < maxIndex; currentIndex++) { Combatant combatant = sortedCombatants[currentIndex]; @@ -250,7 +445,129 @@ private void DrawBars(ImDrawListPtr drawList, Vector2 localPos, Vector2 size, Ac ConfigColor barColor = this.BarConfig.BarColor; ConfigColor jobColor = this.BarColorsConfig.GetColor(combatant.Job); - localPos = this.BarConfig.DrawBar(drawList, localPos, size, combatant, jobColor, barColor, top, current); + localPos = this.DrawBar(drawList, localPos, size, combatant, jobColor, barColor, top, current); + } + }; + } + + private Vector2 DrawBar( + ImDrawListPtr drawList, + Vector2 localPos, + Vector2 size, + Combatant combatant, + ConfigColor jobColor, + ConfigColor barColor, + float top, + float current) + { + BarConfig barConfig = this.BarConfig; + float barHeight = barConfig.BarHeightType == 0 + ? (size.Y - (barConfig.BarCount - 1) * barConfig.BarGaps) / barConfig.BarCount + : barConfig.BarHeight; + + Vector2 barPos = localPos; + Vector2 barSize = new(size.X, barHeight); + Vector2 barFillSize = new(size.X * (current / top), barHeight * barConfig.BarFillHeight); + + if (barConfig.BarFillHeight != 1f) + { + barPos = barConfig.BarFillDirection == 0 ? barPos.AddY(barHeight - barFillSize.Y) : barPos; + Vector2 barBackgroundSize = new(size.X * (current / top), barHeight); + drawList.AddRectFilled(localPos, localPos + barBackgroundSize, barConfig.BarBackgroundColor.Base); + } + + drawList.AddRectFilled(barPos, barPos + barFillSize, barConfig.UseJobColor ? jobColor.Base : barColor.Base); + + if (barConfig.ShowJobIcon && combatant.Job != Job.UKN) + { + uint jobIconId = 62000u + (uint)combatant.Job + 100u * (uint)barConfig.JobIconStyle; + Vector2 jobIconPos = localPos + barConfig.JobIconOffset; + Vector2 jobIconSize = barConfig.JobIconSizeType == 0 ? Vector2.One * barHeight : barConfig.JobIconSize; + if (barConfig.JobIconBackgroundColor.Vector.W > 0f) + { + Vector2 jobIconBackgroundPos = new(jobIconPos.X, localPos.Y); + Vector2 jobIconBackgroundSize = new(jobIconSize.X, barSize.Y); + drawList.AddRectFilled(jobIconBackgroundPos, jobIconBackgroundPos + jobIconBackgroundSize, barConfig.JobIconBackgroundColor.Base); + } + + DrawHelpers.DrawIcon(jobIconId, jobIconPos, jobIconSize, drawList); + } + + DrawBarTexts(drawList, this.BarTextConfig.Texts, localPos, barSize, jobColor, combatant); + return localPos.AddY(barHeight + barConfig.BarGaps); + } + + private static void DrawBarTexts( + ImDrawListPtr drawList, + List texts, + Vector2 parentPos, + Vector2 parentSize, + ConfigColor jobColor, + IActData actData) + { + bool[] visited = new bool[texts.Count]; + Dictionary lookup = new() { { 0, (parentPos, parentSize) } }; + for (int anchorLayer = 0; anchorLayer < texts.Count + 1; anchorLayer++) + { + for (int textIndex = 0; textIndex < texts.Count; textIndex++) + { + Text text = texts[textIndex]; + if (!visited[textIndex] && lookup.TryGetValue(text.AnchorParent, out (Vector2, Vector2) parent)) + { + using (FontsManager.PushFont(text.FontKey)) + { + string formattedText = actData.GetFormattedString($" {text.TextFormat} ", text.ThousandsSeparators ? "N" : "F"); + Vector2 textSize = ImGui.CalcTextSize(formattedText); + + if (text.FixedTextWidth && textSize.X > text.TextWidth) + { + float ellipsisWidth = text.UseEllipsis ? ImGui.CalcTextSize("... ").X : ImGui.CalcTextSize(" ").X; + do + { + formattedText = formattedText.AsSpan(0, formattedText.Length - 1).ToString(); + textSize = ImGui.CalcTextSize(formattedText); + } + while (textSize.X + ellipsisWidth > text.TextWidth && formattedText.Length > 1); + formattedText += text.UseEllipsis ? "... " : " "; + textSize = ImGui.CalcTextSize(formattedText); + } + + Vector2 textBoxSize = new(text.FixedTextWidth ? text.TextWidth : textSize.X, textSize.Y); + Vector2 anchorPoint = Utils.GetAnchoredPosition(parent.Item1, -parent.Item2, text.AnchorPoint); + Vector2 textBoxPos = Utils.GetTopLeft(anchorPoint, textBoxSize, text.AnchorParent == 0 ? text.AnchorPoint.Opposite() : text.AnchorPoint); + + textBoxPos += text.TextOffset; + DrawAnchor alignment = text.FixedTextWidth ? text.TextAlignment : text.AnchorPoint; + Vector2 textPos = Utils.GetTextPos(textBoxPos, textBoxSize, textSize, alignment); + lookup.Add(textIndex + 1, (textBoxPos, textBoxSize)); + visited[textIndex] = true; + + if (text.UseBackground) + { + Vector2 backgroundPos = new(textBoxPos.X, parentPos.Y); + Vector2 backgroundSize = new(textBoxSize.X, parentSize.Y); + drawList.AddRectFilled(backgroundPos, backgroundPos + backgroundSize, text.BackgroundColor.Base); + } + + if (text.ShowSeparator) + { + Vector2 separatorSize = new(text.SeparatorWidth, parentSize.Y * text.SeparatorHeight); + Vector2 separatorPos = new Vector2(anchorPoint.X, anchorPoint.Y - separatorSize.Y / 2) + text.SeparatorOffset; + drawList.AddRectFilled(separatorPos, separatorPos + separatorSize, text.SeparatorColor.Base); + } + + if (text.Enabled) + { + DrawHelpers.DrawText( + drawList, + formattedText, + textPos, + text.TextJobColor ? jobColor.Base : text.TextColor.Base, + text.ShowOutline, + text.OutlineColor.Base); + } + } + } } } } @@ -283,12 +600,13 @@ true when combatant.Name.Contains("YOU") => localPlayerName, }; } - private bool DrawContextMenu(string popupId, out int selectedIndex) + private bool DrawContextMenu(string popupId, out bool selected, out int selectedIndex) { selectedIndex = -1; - bool selected = false; + selected = false; - if (ImGui.BeginPopup(popupId)) + bool popupDrawn = ImGui.BeginPopup(popupId); + if (popupDrawn) { if (!ImGui.IsAnyItemActive() && !ImGui.IsMouseClicked(ImGuiMouseButton.Left)) { @@ -331,7 +649,7 @@ private bool DrawContextMenu(string popupId, out int selectedIndex) ImGui.EndPopup(); } - return selected; + return popupDrawn; } private List GetSortedCombatants(ActEvent actEvent, MeterDataType dataType) @@ -345,7 +663,6 @@ private List GetSortedCombatants(ActEvent actEvent, MeterDataType dat } List sortedCombatants = [.. actEvent.Combatants.Values]; - sortedCombatants.Sort((x, y) => { float xFloat = dataType switch diff --git a/LMeter/Plugin.cs b/LMeter/Plugin.cs index 536c167..dcc9777 100644 --- a/LMeter/Plugin.cs +++ b/LMeter/Plugin.cs @@ -17,16 +17,11 @@ public class Plugin : IDalamudPlugin { public const string ConfigFileName = "LMeter.json"; - public static string Version { get; private set; } = "0.3.1.0"; - + public static string Version { get; private set; } = "0.4.0.0"; public static string ConfigFileDir { get; private set; } = ""; - public static string ConfigFilePath { get; private set; } = ""; - public static string AssemblyFileDir { get; private set; } = ""; - public static IDalamudTextureWrap? IconTexture { get; private set; } = null; - public static string Changelog { get; private set; } = string.Empty; public string Name => "LMeter"; @@ -80,10 +75,7 @@ INotificationManager notificationManager Singletons.Register(new ClipRectsHelper()); // Init TexturesCache - Singletons.Register(new TexturesCache()); - - // Load Icon Texure - Plugin.IconTexture = LoadIconTexture(textureProvider); + Singletons.Register(new TextureCache()); // Load changelog Plugin.Changelog = LoadChangelog(); @@ -91,9 +83,9 @@ INotificationManager notificationManager // Load config FontsManager.CopyPluginFontsToUserPath(); LMeterConfig config = ConfigHelpers.LoadConfig(Plugin.ConfigFilePath); - - // Check if any old configs need to be converted - ConfigHelpers.ConvertOldConfigs(config); + + // Convert old configs + ConfigHelpers.ConvertOldConfig(config); // Refresh fonts config.FontConfig.RefreshFontList(); @@ -117,8 +109,13 @@ INotificationManager notificationManager // Create profile on first load if (config.FirstLoad && config.MeterList.Meters.Count == 0) { - config.MeterList.Meters.Add(MeterWindow.GetDefaultMeter("Profile 1")); + config.MeterList.Meters.Add(MeterWindow.GetDefaultMeter(MeterDataType.Damage, "Dps Meter")); + + MeterWindow hps = MeterWindow.GetDefaultMeter(MeterDataType.Healing, "Hps Meter"); + hps.Enabled = false; + config.MeterList.Meters.Add(hps); } + config.FirstLoad = false; // Start the plugin diff --git a/LMeter/PluginManager.cs b/LMeter/PluginManager.cs index 4f7841b..c9b25f6 100644 --- a/LMeter/PluginManager.cs +++ b/LMeter/PluginManager.cs @@ -16,7 +16,7 @@ namespace LMeter { public class PluginManager : IPluginDisposable { - private readonly Vector2 _configSize = new(550, 550); + private readonly Vector2 _configSize = new(650, 750); private readonly IClientState _clientState; private readonly IDalamudPluginInterface _pluginInterface; @@ -154,19 +154,20 @@ private void OnLogout() private void PluginCommand(string command, string arguments) { - switch (arguments) + string[] argArray = arguments.Split(" "); + switch (argArray) { - case "end": + case {} args when args[0].Equals("end"): Singletons.Get().EndEncounter(); break; - case "clear": + case {} args when args[0].Equals("clear"): this.Clear(); break; - case { } argument when argument.StartsWith("toggle"): - _config.MeterList.ToggleMeter(GetIntArg(argument) - 1, GetBoolArg(argument, 2)); + case { } args when args[0].Equals("toggle"): + _config.MeterList.ToggleMeter(args.Length > 1 ? GetIntArg(args[1]) - 1 : null); break; - case { } argument when argument.StartsWith("ct"): - _config.MeterList.ToggleClickThrough(GetIntArg(argument) - 1); + case { } args when args[0].Equals("ct"): + _config.MeterList.ToggleClickThrough(args.Length > 1 ? GetIntArg(args[1]) - 1 : null); break; default: this.ToggleWindow(); @@ -176,20 +177,7 @@ private void PluginCommand(string command, string arguments) private static int GetIntArg(string argument) { - string[] args = argument.Split(" "); - return args.Length > 1 && int.TryParse(args[1], out int num) ? num : 0; - } - - private static bool? GetBoolArg(string argument, int index = 1) - { - string[] args = argument.Split(" "); - if (args.Length > index) - { - string arg = args[index].ToLower(); - return arg.Equals("on") ? true : (arg.Equals("off") ? false : null); - } - - return null; + return !string.IsNullOrEmpty(argument) && int.TryParse(argument, out int num) ? num : 0; } private void ToggleWindow() diff --git a/LMeter/Windows/ConfigWindow.cs b/LMeter/Windows/ConfigWindow.cs index 08304ec..7243ff3 100644 --- a/LMeter/Windows/ConfigWindow.cs +++ b/LMeter/Windows/ConfigWindow.cs @@ -51,18 +51,11 @@ public override void PreDraw() { if (_configStack.Count != 0) { - this.WindowName = this.GetWindowTitle(); + this.WindowName = string.Join(" > ", _configStack.Reverse().Select(c => c.Name)); ImGui.SetNextWindowSize(_windowSize); } } - private string GetWindowTitle() - { - string title = string.Empty; - title = string.Join(" > ", _configStack.Reverse().Select(c => c.Name)); - return title; - } - public override void Draw() { if (_configStack.Count == 0) @@ -86,7 +79,8 @@ public override void Draw() { foreach (IConfigPage page in configItem.GetConfigPages()) { - if (ImGui.BeginTabItem($"{page.Name}##{this.WindowName}")) + page.Active = ImGui.BeginTabItem($"{page.Name}##{this.WindowName}"); + if (page.Active) { openPage = page; page.DrawConfig(size.AddY(-ImGui.GetCursorPosY()), spacing.X, spacing.Y); @@ -114,8 +108,8 @@ private void DrawNavBar(IConfigPage? openPage, Vector2 size, float padX) if (ImGui.BeginChild($"##{this.WindowName}_NavBar", new Vector2(size.X, NavBarHeight), true)) { DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.LongArrowAltLeft, () => _back = true, "Back", buttonsize); - ImGui.SameLine(); + ImGui.SameLine(); if (_configStack.Count > 2) { DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Home, () => _home = true, "Home", buttonsize); @@ -128,12 +122,11 @@ private void DrawNavBar(IConfigPage? openPage, Vector2 size, float padX) // calculate empty horizontal space based on size of buttons and text box float offset = size.X - buttonsize.X * 5 - textInputWidth - padX * 7; - ImGui.SetCursorPosX(ImGui.GetCursorPosX() + offset); DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.UndoAlt, () => Reset(openPage), $"Reset {openPage?.Name} to Defaults", buttonsize); - ImGui.SameLine(); + ImGui.SameLine(); ImGui.PushItemWidth(textInputWidth); if (ImGui.InputText("##Input", ref _name, 64, ImGuiInputTextFlags.EnterReturnsTrue)) { @@ -146,11 +139,11 @@ private void DrawNavBar(IConfigPage? openPage, Vector2 size, float padX) } ImGui.PopItemWidth(); - ImGui.SameLine(); - DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Upload, () => Export(openPage), $"Export {openPage?.Name}", buttonsize); ImGui.SameLine(); + DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Upload, () => Export(openPage), $"Export {openPage?.Name}", buttonsize); + ImGui.SameLine(); DrawHelpers.DrawButton(string.Empty, FontAwesomeIcon.Download, () => Import(), $"Import {openPage?.Name}", buttonsize); } diff --git a/LMeter/changelog.md b/LMeter/changelog.md index 097b1db..57a639d 100644 --- a/LMeter/changelog.md +++ b/LMeter/changelog.md @@ -1,3 +1,18 @@ +# Version 0.4.0.0 +- Redesigned Text options to allow significantly more customization + - Can now create as many separate bar texts as you would like + - Bar Texts can now be configured with fixed width + - Bar Texts can be anchored relative to other texts + - The above features allow creation of data columns + - Added option for a column header bar + - And a lot more... +- Added option for a Footer bar +- Overhauled Visibility settings (again) +- Bar height can now be set to a specific value +- Added option for thinner bars (similar to Kagerou) +- Added option for job icon background color +- OTF fonts can now be added to the font list + # Version 0.3.1.0 - Updated plugin for Dawntrail - Added support for Viper and Pictomancer diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index afb8651..9f1d22e 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("0.3.1.0")] -[assembly: AssemblyFileVersion("0.3.1.0")] +[assembly: AssemblyVersion("0.4.0.0")] +[assembly: AssemblyFileVersion("0.4.0.0")] diff --git a/repo.json b/repo.json index 340cf46..7de10dd 100644 --- a/repo.json +++ b/repo.json @@ -4,8 +4,8 @@ "Name": "LMeter", "Description": "Plugin to display ACT combat log data.", "InternalName": "LMeter", - "AssemblyVersion": "0.3.1.0", - "TestingAssemblyVersion": "0.3.1.0", + "AssemblyVersion": "0.3.2.0", + "TestingAssemblyVersion": "0.3.2.0", "RepoUrl": "https://github.com/lichie567/LMeter", "ApplicableVersion": "any", "DalamudApiLevel": 10, @@ -14,9 +14,9 @@ "DownloadCount": 0, "LastUpdate": 0, "LoadPriority": 69420, - "DownloadLinkInstall": "https://github.com/lichie567/LMeter/releases/download/0.3.1.0/LMeter.zip", - "DownloadLinkTesting": "https://github.com/lichie567/LMeter/releases/download/0.3.1.0/LMeter.zip", - "DownloadLinkUpdate": "https://github.com/lichie567/LMeter/releases/download/0.3.1.0/LMeter.zip", + "DownloadLinkInstall": "https://github.com/lichie567/LMeter/releases/download/0.3.2.0/LMeter.zip", + "DownloadLinkTesting": "https://github.com/lichie567/LMeter/releases/download/0.3.2.0/LMeter.zip", + "DownloadLinkUpdate": "https://github.com/lichie567/LMeter/releases/download/0.3.2.0/LMeter.zip", "IconUrl": "https://raw.githubusercontent.com/lichie567/LMeter/main/LMeter/Media/Images/icon.png" } ]