diff --git a/ActionTimelineEx/Configurations/DrawingSettings.cs b/ActionTimelineEx/Configurations/DrawingSettings.cs index f3fc14b..29f5f3a 100644 --- a/ActionTimelineEx/Configurations/DrawingSettings.cs +++ b/ActionTimelineEx/Configurations/DrawingSettings.cs @@ -5,6 +5,8 @@ namespace ActionTimelineEx.Configurations; public class DrawingSettings { + public string Name = "Major"; + public bool Enable = true; public bool IsRotation = false; diff --git a/ActionTimelineEx/Configurations/Settings.cs b/ActionTimelineEx/Configurations/Settings.cs index 811f6b7..5e96cc6 100644 --- a/ActionTimelineEx/Configurations/Settings.cs +++ b/ActionTimelineEx/Configurations/Settings.cs @@ -10,7 +10,7 @@ public class Settings : IPluginConfiguration public bool ShowTimelineOnlyInDuty = false; public bool ShowTimelineOnlyInCombat = false; //public float StatusCheckDelay = 0.1f; - public DrawingSettings TimelineSetting = new DrawingSettings(); + public List TimelineSettings = new() { new DrawingSettings() }; public HashSet HideStatusIds = new HashSet(); public bool PrintClipping = false; public int PrintClippingMin = 150; diff --git a/ActionTimelineEx/Plugin.cs b/ActionTimelineEx/Plugin.cs index e5992f4..df147e5 100644 --- a/ActionTimelineEx/Plugin.cs +++ b/ActionTimelineEx/Plugin.cs @@ -8,6 +8,8 @@ using ECommons.Commands; using ECommons.DalamudServices; using ECommons.GameHelpers; +using ImGuiNET; +using System.Numerics; namespace ActionTimeline; @@ -102,20 +104,16 @@ private void PluginCommand(string command, string arguments) var sub = arguments.Split(' ').FirstOrDefault(); if(string.Equals("unlock", sub, StringComparison.OrdinalIgnoreCase)) { - foreach (var window in _windowSystem.Windows) + foreach (var setting in Settings.TimelineSettings) { - if (window is not TimelineWindow tWindow) continue; - - tWindow.Setting.Locked = false; + setting.Locked = false; } } else if (string.Equals("lock", sub, StringComparison.OrdinalIgnoreCase)) { - foreach (var window in _windowSystem.Windows) + foreach (var setting in Settings.TimelineSettings) { - if (window is not TimelineWindow tWindow) continue; - - tWindow.Setting.Locked = true; + setting.Locked = true; } } else @@ -130,43 +128,46 @@ private void CreateWindows() _windowSystem = new WindowSystem("ActionTimeline_Windows"); _windowSystem.AddWindow(_settingsWindow); - _windowSystem.AddWindow(new TimelineWindow("Timeline1") - { - Setting = Settings.TimelineSetting, - }); } private void Draw() { if (Settings == null || !Player.Available) return; - UpdateTimeline(); - _windowSystem?.Draw(); + + if (!ShowTimeline()) return; + + ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 0)); + ImGui.PushStyleVar(ImGuiStyleVar.WindowBorderSize, 0); + + HashSet showedName = new HashSet(); + foreach (var setting in Settings.TimelineSettings) + { + if (showedName.Contains(setting.Name)) continue; + + TimelineWindow.Draw(setting); + + showedName.Add(setting.Name); + } + + ImGui.PopStyleColor(); + ImGui.PopStyleVar(2); } - private void UpdateTimeline() + private bool ShowTimeline() { - foreach (var window in _windowSystem.Windows) + if (Settings.ShowTimelineOnlyInCombat && !Svc.Condition[ConditionFlag.InCombat]) { - if (window is not TimelineWindow tWindow) continue; - - bool show = tWindow.Setting.Enable; - if (show) - { - if (Settings.ShowTimelineOnlyInCombat && !Svc.Condition[ConditionFlag.InCombat]) - { - show = false; - } - - if (Settings.ShowTimelineOnlyInDuty && !Svc.Condition[ConditionFlag.BoundByDuty]) - { - show = false; - } - } + return false; + } - tWindow.IsOpen = show; + if (Settings.ShowTimelineOnlyInDuty && !Svc.Condition[ConditionFlag.BoundByDuty]) + { + return false; } + + return true; } public static void OpenConfigUi() @@ -176,10 +177,7 @@ public static void OpenConfigUi() protected virtual void Dispose(bool disposing) { - if (!disposing) - { - return; - } + if (!disposing) return; Settings.Save(); diff --git a/ActionTimelineEx/Windows/SettingsWindow.cs b/ActionTimelineEx/Windows/SettingsWindow.cs index bba4178..22a69be 100644 --- a/ActionTimelineEx/Windows/SettingsWindow.cs +++ b/ActionTimelineEx/Windows/SettingsWindow.cs @@ -2,6 +2,7 @@ using ActionTimeline.Timeline; using ActionTimelineEx.Configurations; using Dalamud.Interface; +using Dalamud.Interface.Colors; using Dalamud.Interface.Windowing; using Dalamud.Utility; using ECommons.Commands; @@ -39,11 +40,35 @@ public override void Draw() DrawGeneralSetting(); ImGui.EndTabItem(); } - if (ImGui.BeginTabItem("Timeline")) + + HashSet showedName = new HashSet(); + int index = 0; + DrawingSettings? removingSetting = null; + + foreach (var setting in Settings.TimelineSettings) { - DrawTimelineSetting(Settings.TimelineSetting); - ImGui.EndTabItem(); + var duplicated = showedName.Contains(setting.Name); + if (duplicated) ImGui.PushStyleColor(ImGuiCol.Text, ImGui.ColorConvertFloat4ToU32(ImGuiColors.DalamudRed)); + + if (ImGui.BeginTabItem($"TL:{setting.Name}")) + { + if(duplicated) ImGui.PopStyleColor(); + if (DrawTimelineSetting(setting)) + { + removingSetting = setting; + } + ImGui.EndTabItem(); + } + + showedName.Add(setting.Name); + index++; + } + + if(removingSetting != null) + { + Settings.TimelineSettings.Remove(removingSetting); } + if (ImGui.BeginTabItem("Help")) { DrawHelp(); @@ -89,6 +114,13 @@ private void DrawHelp() private ushort _aboutAdd = 0; private void DrawGeneralSetting() { + if(ImGui.Button("Add One Timeline")) + { + Settings.TimelineSettings.Add(new DrawingSettings() + { + Name = (Settings.TimelineSettings.Count + 1).ToString(), + }); + } ImGui.Checkbox("Show Only In Duty", ref Settings.ShowTimelineOnlyInDuty); ImGui.Checkbox("Show Only In Combat", ref Settings.ShowTimelineOnlyInCombat); ImGui.Checkbox("Print Clipping Time On Chat", ref Settings.PrintClipping); @@ -188,11 +220,12 @@ private void DrawGeneralSetting() } #region Timeline - private void DrawTimelineSetting(DrawingSettings settings) + private bool DrawTimelineSetting(DrawingSettings settings) { + var result = false; if (!ImGui.BeginTabBar("##Timeline_Settings_TabBar")) { - return; + return result; } ImGui.PushItemWidth(80 * _scale); @@ -200,7 +233,7 @@ private void DrawTimelineSetting(DrawingSettings settings) // general if (ImGui.BeginTabItem("General##Timeline_General")) { - DrawGeneralTab(settings); + result = DrawGeneralTab(settings); ImGui.EndTabItem(); } @@ -233,10 +266,56 @@ private void DrawTimelineSetting(DrawingSettings settings) } ImGui.EndTabBar(); + + return result; + } + + private string _undoName = string.Empty; + private DateTime _lastTime = DateTime.MinValue; + private bool RemoveValue(string name) + { + ImGui.SameLine(); + + bool isLast = name == _undoName && DateTime.Now - _lastTime < TimeSpan.FromSeconds(2); + bool isTime = DateTime.Now - _lastTime > TimeSpan.FromSeconds(0.5); + + bool result = false; + + if (isLast) ImGui.PushStyleColor(ImGuiCol.Text, isTime ? ImGuiColors.HealerGreen : ImGuiColors.DPSRed); + + ImGui.PushFont(UiBuilder.IconFont); + if (ImGui.Button($"{(isLast ? FontAwesomeIcon.Check : FontAwesomeIcon.Undo).ToIconString()}##Remove{name}")) + { + if (isLast && isTime) + { + result = true; + _lastTime = DateTime.MinValue; + } + else + { + _lastTime = DateTime.Now; + _undoName = name; + } + } + + ImGui.PopFont(); + + if (ImGui.IsItemHovered()) + { + ImGui.SetTooltip(!isTime ? "Please wait for a second." : + isLast ? "Are you sure to remove this timeline?" + : "Click to remove this timeline."); + } + + if (isLast) ImGui.PopStyleColor(); + return result; } - private void DrawGeneralTab(DrawingSettings settings) + private bool DrawGeneralTab(DrawingSettings settings) { + ImGui.InputText("Name: ", ref settings.Name, 32); + var result = RemoveValue(settings.Name); + ImGui.Checkbox("Enable", ref settings.Enable); ImGui.Checkbox("Is Rotation", ref settings.IsRotation); @@ -257,6 +336,8 @@ private void DrawGeneralTab(DrawingSettings settings) DrawHelper.SetTooltip("This is the advanced time about action using"); } ImGui.DragFloat("Drawing Center offset", ref settings.CenterOffset, 0.3f, -500, 500); + + return result; } private void DrawIconsTab(DrawingSettings settings) diff --git a/ActionTimelineEx/Windows/TimelineWindow.cs b/ActionTimelineEx/Windows/TimelineWindow.cs index 19aa9c1..6b5df6f 100644 --- a/ActionTimelineEx/Windows/TimelineWindow.cs +++ b/ActionTimelineEx/Windows/TimelineWindow.cs @@ -1,57 +1,46 @@ using ActionTimeline.Timeline; using ActionTimelineEx.Configurations; using ActionTimelineEx.Timeline; -using Dalamud.Interface.Windowing; +using Dalamud.Interface; using ImGuiNET; using System.Numerics; -using static System.Windows.Forms.VisualStyles.VisualStyleElement.TaskbarClock; namespace ActionTimeline.Windows; -internal class TimelineWindow : Window +internal static class TimelineWindow { - public DrawingSettings Setting { get; set; } = new DrawingSettings(); - - private ImGuiWindowFlags _baseFlags = ImGuiWindowFlags.NoScrollbar + private const ImGuiWindowFlags _baseFlags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoNav | ImGuiWindowFlags.NoScrollWithMouse; - public TimelineWindow(string name) : base(name) + public static void Draw(DrawingSettings setting) { - Flags = _baseFlags; - - Size = new Vector2(560, 100); - SizeCondition = ImGuiCond.FirstUseEver; + if (!setting.Enable || string.IsNullOrEmpty(setting.Name)) return; - Position = new Vector2(200, 200); - PositionCondition = ImGuiCond.FirstUseEver; - } + var flag = _baseFlags; + if (setting.Locked) + { + flag |= ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoMouseInputs; + } - public override void PreDraw() - { - Vector4 bgColor = Setting.Locked ? Setting.LockedBackgroundColor : Setting.UnlockedBackgroundColor; + Vector4 bgColor = setting.Locked ? setting.LockedBackgroundColor : setting.UnlockedBackgroundColor; ImGui.PushStyleColor(ImGuiCol.WindowBg, bgColor); - Flags = _baseFlags; + ImGui.SetNextWindowSize(new Vector2(560, 100) * ImGuiHelpers.GlobalScale, ImGuiCond.FirstUseEver); + ImGui.SetNextWindowPos(new Vector2(200, 200) * ImGuiHelpers.GlobalScale, ImGuiCond.FirstUseEver); - if (Setting.Locked) + if (ImGui.Begin($"Timeline: {setting.Name}", flag)) { - Flags |= ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoMove | ImGuiWindowFlags.NoMouseInputs; + DrawContent(setting); + ImGui.End(); } - ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, new Vector2(0, 0)); - ImGui.PushStyleVar(ImGuiStyleVar.WindowBorderSize, 0); - } - - public override void PostDraw() - { ImGui.PopStyleColor(); - ImGui.PopStyleVar(2); } - public override void Draw() + private static void DrawContent(DrawingSettings setting) { if (ImGui.IsWindowHovered()) { @@ -63,21 +52,21 @@ public override void Draw() var pos = ImGui.GetWindowPos(); var size = ImGui.GetWindowSize(); - var now = Setting.IsRotation ? TimelineManager.Instance?.EndTime ?? DateTime.Now : DateTime.Now; + var now = setting.IsRotation ? TimelineManager.Instance?.EndTime ?? DateTime.Now : DateTime.Now; - var endTime = now - TimeSpan.FromSeconds(size.X / Setting.SizePerSecond - Setting.TimeOffset); + var endTime = now - TimeSpan.FromSeconds(size.X / setting.SizePerSecond - setting.TimeOffset); var last = now; var list = TimelineManager.Instance?.GetItems(endTime, out last); - DrawGrid(pos, size); + DrawGrid(pos, size, setting); - if (Setting.ShowGCDClipping && list != null) //Clipping + if (setting.ShowGCDClipping && list != null) //Clipping { - var gcdClippingColor = ImGui.ColorConvertFloat4ToU32(Setting.GCDClippingColor); - var threshold = TimeSpan.FromSeconds(Setting.GCDClippingThreshold); - var max = TimeSpan.FromSeconds(Setting.GCDClippingMaxTime); - var sizePerSecond = Setting.SizePerSecond; + var gcdClippingColor = ImGui.ColorConvertFloat4ToU32(setting.GCDClippingColor); + var threshold = TimeSpan.FromSeconds(setting.GCDClippingThreshold); + var max = TimeSpan.FromSeconds(setting.GCDClippingMaxTime); + var sizePerSecond = setting.SizePerSecond; foreach (var item in list) { @@ -88,11 +77,11 @@ public override void Draw() if (last != DateTime.MinValue && span >= threshold && span < max) { - var drawingLeftTop = pos + new Vector2(size.X - (Setting.TimeOffset + (float)(now - last).TotalSeconds) * sizePerSecond, 0); + var drawingLeftTop = pos + new Vector2(size.X - (setting.TimeOffset + (float)(now - last).TotalSeconds) * sizePerSecond, 0); ImGui.GetWindowDrawList().AddRectFilled( drawingLeftTop, - pos + new Vector2(size.X - (Setting.TimeOffset + (float)(now - start).TotalSeconds) * sizePerSecond, size.Y), gcdClippingColor); + pos + new Vector2(size.X - (setting.TimeOffset + (float)(now - start).TotalSeconds) * sizePerSecond, size.Y), gcdClippingColor); ImGui.GetWindowDrawList().AddText(drawingLeftTop, - ImGui.ColorConvertFloat4ToU32(Setting.GCDClippingTextColor), + ImGui.ColorConvertFloat4ToU32(setting.GCDClippingTextColor), $"{(int)span.TotalMilliseconds}ms"); } @@ -104,80 +93,82 @@ public override void Draw() { foreach (var item in list) { - item.Draw(now, pos, size, TimelineLayer.General, Setting); + item.Draw(now, pos, size, TimelineLayer.General, setting); } foreach (var item in list) { - item.Draw(now, pos, size, TimelineLayer.Status, Setting); + item.Draw(now, pos, size, TimelineLayer.Status, setting); } var status = TimelineManager.Instance?.GetStatus(endTime, out _); - if (status != null && Setting.ShowStatusLine) + if (status != null && setting.ShowStatusLine) { foreach (var item in status) { - item.Draw(now, pos, size, Setting); + item.Draw(now, pos, size, setting); } } foreach (var item in list) { - item.Draw(now, pos, size, TimelineLayer.Icon, Setting); + item.Draw(now, pos, size, TimelineLayer.Icon, setting); } } - uint lineColor = ImGui.ColorConvertFloat4ToU32(Setting.GridStartLineColor); + uint lineColor = ImGui.ColorConvertFloat4ToU32(setting.GridStartLineColor); + + var x = pos.X + size.X - setting.TimeOffset * setting.SizePerSecond; + ImGui.GetWindowDrawList().AddLine(new Vector2(x, pos.Y), new Vector2(x, pos.Y + size.Y), lineColor, setting.GridStartLineWidth); - var x = pos.X + size.X - Setting.TimeOffset * Setting.SizePerSecond; - ImGui.GetWindowDrawList().AddLine(new Vector2(x, pos.Y), new Vector2(x, pos.Y + size.Y), lineColor, Setting.GridStartLineWidth); + if (!setting.Locked) ImGui.Text(setting.Name); } - private void DrawGrid(Vector2 pos, Vector2 size) + private static void DrawGrid(Vector2 pos, Vector2 size, DrawingSettings setting) { - if (!Setting.ShowGrid) return; + if (!setting.ShowGrid) return; ImDrawListPtr drawList = ImGui.GetWindowDrawList(); float width = size.X; float height = size.Y; - uint lineColor = ImGui.ColorConvertFloat4ToU32(Setting.GridLineColor); - uint subdivisionLineColor = ImGui.ColorConvertFloat4ToU32(Setting.GridSubdivisionLineColor); + uint lineColor = ImGui.ColorConvertFloat4ToU32(setting.GridLineColor); + uint subdivisionLineColor = ImGui.ColorConvertFloat4ToU32(setting.GridSubdivisionLineColor); - if (Setting.GridDivideBySeconds) + if (setting.GridDivideBySeconds) { - float step = Setting.SizePerSecond; + float step = setting.SizePerSecond; for (int i = 0; i < width / step; i++) { float x = step * i; var start = pos.X + width - x; - if (Setting.GridSubdivideSeconds && Setting.GridSubdivisionCount > 1) + if (setting.GridSubdivideSeconds && setting.GridSubdivisionCount > 1) { - float subStep = step * 1f / Setting.GridSubdivisionCount; - for (int j = 1; j < Setting.GridSubdivisionCount; j++) + float subStep = step * 1f / setting.GridSubdivisionCount; + for (int j = 1; j < setting.GridSubdivisionCount; j++) { - drawList.AddLine(new Vector2(start + subStep * j, pos.Y), new Vector2(start + subStep * j, pos.Y + height), subdivisionLineColor, Setting.GridSubdivisionLineWidth); + drawList.AddLine(new Vector2(start + subStep * j, pos.Y), new Vector2(start + subStep * j, pos.Y + height), subdivisionLineColor, setting.GridSubdivisionLineWidth); } } - var time = -i + Setting.TimeOffset; + var time = -i + setting.TimeOffset; if (time != 0) { - drawList.AddLine(new Vector2(start, pos.Y), new Vector2(start, pos.Y + height), lineColor, Setting.GridLineWidth); + drawList.AddLine(new Vector2(start, pos.Y), new Vector2(start, pos.Y + height), lineColor, setting.GridLineWidth); } - if (Setting.GridShowSecondsText) + if (setting.GridShowSecondsText) { drawList.AddText(new Vector2(start + 2, pos.Y), lineColor, $" {time}s"); } } } - lineColor = ImGui.ColorConvertFloat4ToU32(Setting.GridCenterLineColor); - if (Setting.ShowGridCenterLine) + lineColor = ImGui.ColorConvertFloat4ToU32(setting.GridCenterLineColor); + if (setting.ShowGridCenterLine) { - drawList.AddLine(new Vector2(pos.X, pos.Y + height / 2f + Setting.CenterOffset), new Vector2(pos.X + width, pos.Y + height / 2f + Setting.CenterOffset), lineColor, Setting.GridCenterLineWidth); + drawList.AddLine(new Vector2(pos.X, pos.Y + height / 2f + setting.CenterOffset), new Vector2(pos.X + width, pos.Y + height / 2f + setting.CenterOffset), lineColor, setting.GridCenterLineWidth); } } }