diff --git a/ChatTwo/ChatTwo.csproj b/ChatTwo/ChatTwo.csproj index d462ec6..275f83e 100755 --- a/ChatTwo/ChatTwo.csproj +++ b/ChatTwo/ChatTwo.csproj @@ -1,7 +1,7 @@ - 1.19.4 + 1.20.0 net8.0-windows enable enable diff --git a/ChatTwo/PluginUi.cs b/ChatTwo/FontManager.cs old mode 100755 new mode 100644 similarity index 80% rename from ChatTwo/PluginUi.cs rename to ChatTwo/FontManager.cs index 2059dd7..4594bd6 --- a/ChatTwo/PluginUi.cs +++ b/ChatTwo/FontManager.cs @@ -1,5 +1,4 @@ -using System.Numerics; -using ChatTwo.Ui; +using ChatTwo.Ui; using Dalamud.Interface; using Dalamud.Interface.GameFonts; using Dalamud.Interface.ManagedFontAtlas; @@ -8,32 +7,15 @@ using ImGuiNET; namespace ChatTwo; -internal sealed class PluginUi : IDisposable { - internal Plugin Plugin { get; } - - internal bool SettingsVisible; - internal bool ScreenshotMode; - internal string Salt { get; } +public class FontManager +{ + private readonly Plugin Plugin; internal IFontHandle Axis { get; private set; } internal IFontHandle AxisItalic { get; private set; } internal IFontHandle RegularFont { get; private set; } internal IFontHandle? ItalicFont { get; private set; } - internal Vector4 DefaultText { get; private set; } - - internal Tab? CurrentTab { - get { - var i = ChatLog.LastTab; - if (i > -1 && i < Plugin.Config.Tabs.Count) { - return Plugin.Config.Tabs[i]; - } - - return null; - } - } - - private List Components { get; } private FaceData _regularFont; private FaceData? _italicFont; @@ -44,17 +26,9 @@ internal sealed class PluginUi : IDisposable { private ushort[] _jpRange; private ushort[] _symRange = [0xE020, 0xE0DB, 0]; - public readonly ChatLog ChatLog; - - internal PluginUi(Plugin plugin) { + public FontManager(Plugin plugin) + { Plugin = plugin; - Salt = new Random().Next().ToString(); - - ChatLog = new ChatLog(this); - Components = new List { - new Settings(this), - ChatLog, - }; var gameSym = new HttpClient().GetAsync("https://img.finalfantasyxiv.com/lds/pc/global/fonts/FFXIV_Lodestone_SSF.ttf") .Result @@ -62,38 +36,9 @@ internal sealed class PluginUi : IDisposable { .ReadAsByteArrayAsync() .Result; _gameSymFont = new FaceData(gameSym); - - Plugin.Interface.UiBuilder.DisableCutsceneUiHide = true; - Plugin.Interface.UiBuilder.DisableGposeUiHide = true; } - public void Dispose() { - foreach (var component in Components) { - component.Dispose(); - } - } - - public void Draw() { - if (Plugin.Config.DatabaseMigration != Configuration.LatestDbVersion) { - return; - } - - Plugin.Interface.UiBuilder.DisableUserUiHide = !Plugin.Config.HideWhenUiHidden; - DefaultText = ImGui.GetStyle().Colors[(int) ImGuiCol.Text]; - - using ((Plugin.Config.FontsEnabled ? RegularFont : Axis).Push()) - { - foreach (var component in Components) { - try { - component.Draw(); - } catch (Exception ex) { - Plugin.Log.Error(ex, "Error drawing component"); - } - } - } - } - - private byte[] GetResource(string name) { + private byte[] GetResource(string name) { var stream = GetType().Assembly.GetManifestResourceStream(name)!; var memory = new MemoryStream(); stream.CopyTo(memory); @@ -257,4 +202,4 @@ internal sealed class PluginUi : IDisposable { )); } } -} +} \ No newline at end of file diff --git a/ChatTwo/PayloadHandler.cs b/ChatTwo/PayloadHandler.cs index e5f8370..5e9b263 100755 --- a/ChatTwo/PayloadHandler.cs +++ b/ChatTwo/PayloadHandler.cs @@ -22,11 +22,10 @@ using ChatTwoPartyFinderPayload = ChatTwo.Util.PartyFinderPayload; namespace ChatTwo; -internal sealed class PayloadHandler { +public sealed class PayloadHandler { private const string PopupId = "chat2-context-popup"; - private PluginUi Ui { get; } - private ChatLog Log { get; } + private ChatLogWindow LogWindow { get; } private (Chunk, Payload?)? Popup { get; set; } @@ -35,9 +34,8 @@ internal sealed class PayloadHandler { private uint _hoverCounter; private uint _lastHoverCounter; - internal PayloadHandler(PluginUi ui, ChatLog log) { - Ui = ui; - Log = log; + internal PayloadHandler(ChatLogWindow logWindow) { + LogWindow = logWindow; } internal void Draw() { @@ -87,7 +85,7 @@ internal sealed class PayloadHandler { } private void Integrations(Chunk chunk, Payload? payload) { - var registered = Ui.Plugin.Ipc.Registered; + var registered = LogWindow.Plugin.Ipc.Registered; if (registered.Count == 0) { return; } @@ -102,7 +100,7 @@ internal sealed class PayloadHandler { foreach (var id in registered) { try { - Ui.Plugin.Ipc.Invoke(id, sender, contentId, payload, chunk.Message?.SenderSource, chunk.Message?.ContentSource); + LogWindow.Plugin.Ipc.Invoke(id, sender, contentId, payload, chunk.Message?.SenderSource, chunk.Message?.ContentSource); } catch (Exception ex) { Plugin.Log.Error(ex, "Error executing integration"); } @@ -127,10 +125,10 @@ internal sealed class PayloadHandler { return; } - ImGui.Checkbox(Language.Context_ScreenshotMode, ref Ui.ScreenshotMode); + ImGui.Checkbox(Language.Context_ScreenshotMode, ref LogWindow.ScreenshotMode); if (ImGui.Selectable(Language.Context_HideChat)) { - Log.UserHide(); + LogWindow.UserHide(); } if (chunk.Message is { } message) { @@ -186,7 +184,7 @@ internal sealed class PayloadHandler { break; } case ItemPayload item: { - if (Ui.Plugin.Config.NativeItemTooltips) { + if (LogWindow.Plugin.Config.NativeItemTooltips) { GameFunctions.GameFunctions.OpenItemTooltip(item.RawItemId); _handleTooltips = true; @@ -214,7 +212,7 @@ internal sealed class PayloadHandler { ImGui.BeginTooltip(); ImGui.PushTextWrapPos(); - ImGui.PushStyleColor(ImGuiCol.Text, Ui.DefaultText); + ImGui.PushStyleColor(ImGuiCol.Text, LogWindow.DefaultText); try { @@ -237,7 +235,7 @@ internal sealed class PayloadHandler { if (!Plugin.GameConfig.TryGet(UiControlOption.DetailTrackingType, out uint selected) || selected != 0) return; - if (Log.LastViewport != ImGuiHelpers.MainViewport.NativePtr) + if (LogWindow.LastViewport != ImGuiHelpers.MainViewport.NativePtr) return; var atk = (AtkUnitBase*) args.Addon; @@ -246,11 +244,11 @@ internal sealed class PayloadHandler { var atkSize = (X: atk->GetScaledWidth(true), Y: atk->GetScaledHeight(true)); var viewportSize = ImGuiHelpers.MainViewport.Size; - var window = Log.LastWindowPos + Log.LastWindowSize; + var window = LogWindow.LastWindowPos + LogWindow.LastWindowSize; var isLeft = window.X < viewportSize.X / 2; var isTop = window.Y < viewportSize.Y / 2; - var x = isLeft ? window.X : Log.LastWindowPos.X - atkSize.X; + var x = isLeft ? window.X : LogWindow.LastWindowPos.X - atkSize.X; var y = Math.Clamp(window.Y - atkSize.Y, 0, float.MaxValue); y -= isTop ? 0 : 10; // small offset to prevent cut-off on the bottom atk->SetPosition((short) x, (short) y); @@ -267,16 +265,16 @@ internal sealed class PayloadHandler { } private void HoverStatus(StatusPayload status) { - if (Ui.Plugin.TextureCache.GetStatus(status.Status) is { } icon) { + if (LogWindow.Plugin.TextureCache.GetStatus(status.Status) is { } icon) { InlineIcon(icon); } var name = ChunkUtil.ToChunks(status.Status.Name.ToDalamudString(), ChunkSource.None, null); - Log.DrawChunks(name.ToList()); + LogWindow.DrawChunks(name.ToList()); ImGui.Separator(); var desc = ChunkUtil.ToChunks(status.Status.Description.ToDalamudString(), ChunkSource.None, null); - Log.DrawChunks(desc.ToList()); + LogWindow.DrawChunks(desc.ToList()); } private void HoverItem(ItemPayload item) { @@ -289,16 +287,16 @@ internal sealed class PayloadHandler { return; } - if (Ui.Plugin.TextureCache.GetItem(item.Item, item.IsHQ) is { } icon) { + if (LogWindow.Plugin.TextureCache.GetItem(item.Item, item.IsHQ) is { } icon) { InlineIcon(icon); } var name = ChunkUtil.ToChunks(item.Item.Name.ToDalamudString(), ChunkSource.None, null); - Log.DrawChunks(name.ToList()); + LogWindow.DrawChunks(name.ToList()); ImGui.Separator(); var desc = ChunkUtil.ToChunks(item.Item.Description.ToDalamudString(), ChunkSource.None, null); - Log.DrawChunks(desc.ToList()); + LogWindow.DrawChunks(desc.ToList()); } private void HoverEventItem(ItemPayload payload) { @@ -307,18 +305,18 @@ internal sealed class PayloadHandler { return; } - if (Ui.Plugin.TextureCache.GetEventItem(item) is { } icon) { + if (LogWindow.Plugin.TextureCache.GetEventItem(item) is { } icon) { InlineIcon(icon); } var name = ChunkUtil.ToChunks(item.Name.ToDalamudString(), ChunkSource.None, null); - Log.DrawChunks(name.ToList()); + LogWindow.DrawChunks(name.ToList()); ImGui.Separator(); var help = Plugin.DataManager.GetExcelSheet()?.GetRow(payload.RawItemId); if (help != null) { var desc = ChunkUtil.ToChunks(help.Description.ToDalamudString(), ChunkSource.None, null); - Log.DrawChunks(desc.ToList()); + LogWindow.DrawChunks(desc.ToList()); } } @@ -329,7 +327,7 @@ internal sealed class PayloadHandler { break; } case QuestPayload quest: { - Ui.Plugin.Common.Functions.Journal.OpenQuest(quest.Quest); + LogWindow.Plugin.Common.Functions.Journal.OpenQuest(quest.Quest); break; } case DalamudLinkPayload link: { @@ -340,17 +338,17 @@ internal sealed class PayloadHandler { if (pf.LinkType == DalamudPartyFinderPayload.PartyFinderLinkType.PartyFinderNotification) { GameFunctions.GameFunctions.OpenPartyFinder(); } else { - Ui.Plugin.Functions.OpenPartyFinder(pf.ListingId); + LogWindow.Plugin.Functions.OpenPartyFinder(pf.ListingId); } break; } case ChatTwoPartyFinderPayload pf: { - Ui.Plugin.Functions.OpenPartyFinder(pf.Id); + LogWindow.Plugin.Functions.OpenPartyFinder(pf.Id); break; } case AchievementPayload achievement: { - Ui.Plugin.Functions.OpenAchievement(achievement.Id); + LogWindow.Plugin.Functions.OpenAchievement(achievement.Id); break; } case RawPayload raw: { @@ -408,7 +406,7 @@ internal sealed class PayloadHandler { var hq = payload.Kind == ItemPayload.ItemKind.Hq; - if (Ui.Plugin.TextureCache.GetItem(item, hq) is { } icon) { + if (LogWindow.Plugin.TextureCache.GetItem(item, hq) is { } icon) { InlineIcon(icon); } @@ -420,32 +418,32 @@ internal sealed class PayloadHandler { name.Payloads.Add(new TextPayload(" ")); } - Log.DrawChunks(ChunkUtil.ToChunks(name, ChunkSource.None, null).ToList(), false); + LogWindow.DrawChunks(ChunkUtil.ToChunks(name, ChunkSource.None, null).ToList(), false); ImGui.Separator(); var realItemId = payload.RawItemId; if (item.EquipSlotCategory.Row != 0) { if (ImGui.Selectable(Language.Context_TryOn)) { - Ui.Plugin.Functions.Context.TryOn(realItemId, 0); + LogWindow.Plugin.Functions.Context.TryOn(realItemId, 0); } if (ImGui.Selectable(Language.Context_ItemComparison)) { - Ui.Plugin.Functions.Context.OpenItemComparison(realItemId); + LogWindow.Plugin.Functions.Context.OpenItemComparison(realItemId); } } if (item.ItemSearchCategory.Value?.Category == 3) { if (ImGui.Selectable(Language.Context_SearchRecipes)) { - Ui.Plugin.Functions.Context.SearchForRecipesUsingItem(payload.ItemId); + LogWindow.Plugin.Functions.Context.SearchForRecipesUsingItem(payload.ItemId); } } if (ImGui.Selectable(Language.Context_SearchForItem)) { - Ui.Plugin.Functions.Context.SearchForItem(realItemId); + LogWindow.Plugin.Functions.Context.SearchForItem(realItemId); } if (ImGui.Selectable(Language.Context_Link)) { - Ui.Plugin.Functions.Context.LinkItem(realItemId); + LogWindow.Plugin.Functions.Context.LinkItem(realItemId); } if (ImGui.Selectable(Language.Context_CopyItemName)) { @@ -463,17 +461,17 @@ internal sealed class PayloadHandler { return; } - if (Ui.Plugin.TextureCache.GetEventItem(item) is { } icon) { + if (LogWindow.Plugin.TextureCache.GetEventItem(item) is { } icon) { InlineIcon(icon); } var name = item.Name.ToDalamudString(); - Log.DrawChunks(ChunkUtil.ToChunks(name, ChunkSource.None, null).ToList(), false); + LogWindow.DrawChunks(ChunkUtil.ToChunks(name, ChunkSource.None, null).ToList(), false); ImGui.Separator(); var realItemId = payload.RawItemId; if (ImGui.Selectable(Language.Context_Link)) { - Ui.Plugin.Functions.Context.LinkItem(realItemId); + LogWindow.Plugin.Functions.Context.LinkItem(realItemId); } if (ImGui.Selectable(Language.Context_CopyItemName)) { @@ -502,17 +500,17 @@ internal sealed class PayloadHandler { }); } - Log.DrawChunks(name, false); + LogWindow.DrawChunks(name, false); ImGui.Separator(); if (ImGui.Selectable(Language.Context_SendTell)) { - Log.Chat = $"/tell {player.PlayerName}"; + LogWindow.Chat = $"/tell {player.PlayerName}"; if (world.IsPublic) { - Log.Chat += $"@{world.Name}"; + LogWindow.Chat += $"@{world.Name}"; } - Log.Chat += " "; - Log.Activate = true; + LogWindow.Chat += " "; + LogWindow.Activate = true; } var validContentId = chunk.Message?.ContentId is not (null or 0); @@ -522,21 +520,21 @@ internal sealed class PayloadHandler { var isLeader = party.Length == 0 || Plugin.ClientState.LocalContentId == leader; var member = party.FirstOrDefault(member => member.Name.TextValue == player.PlayerName && member.World.Id == world.RowId); var isInParty = member != default; - var inInstance = Ui.Plugin.Functions.IsInInstance(); + var inInstance = LogWindow.Plugin.Functions.IsInInstance(); var inPartyInstance = Plugin.DataManager.GetExcelSheet()!.GetRow(Plugin.ClientState.TerritoryType)?.TerritoryIntendedUse is (41 or 47 or 48 or 52 or 53); if (isLeader) { if (!isInParty) { if (inInstance && inPartyInstance) { if (validContentId && ImGui.Selectable(Language.Context_InviteToParty)) { - Ui.Plugin.Functions.Party.InviteInInstance(chunk.Message!.ContentId); + LogWindow.Plugin.Functions.Party.InviteInInstance(chunk.Message!.ContentId); } } else if (!inInstance && ImGui.BeginMenu(Language.Context_InviteToParty)) { if (ImGui.Selectable(Language.Context_InviteToParty_SameWorld)) { - Ui.Plugin.Functions.Party.InviteSameWorld(player.PlayerName, (ushort) world.RowId, chunk.Message?.ContentId ?? 0); + LogWindow.Plugin.Functions.Party.InviteSameWorld(player.PlayerName, (ushort) world.RowId, chunk.Message?.ContentId ?? 0); } if (validContentId && ImGui.Selectable(Language.Context_InviteToParty_DifferentWorld)) { - Ui.Plugin.Functions.Party.InviteOtherWorld(chunk.Message!.ContentId); + LogWindow.Plugin.Functions.Party.InviteOtherWorld(chunk.Message!.ContentId); } ImGui.EndMenu(); @@ -545,33 +543,33 @@ internal sealed class PayloadHandler { if (isInParty && member != null && (!inInstance || (inInstance && inPartyInstance))) { if (ImGui.Selectable(Language.Context_Promote)) { - Ui.Plugin.Functions.Party.Promote(player.PlayerName, (ulong) member.ContentId); + LogWindow.Plugin.Functions.Party.Promote(player.PlayerName, (ulong) member.ContentId); } if (ImGui.Selectable(Language.Context_KickFromParty)) { - Ui.Plugin.Functions.Party.Kick(player.PlayerName, (ulong) member.ContentId); + LogWindow.Plugin.Functions.Party.Kick(player.PlayerName, (ulong) member.ContentId); } } } - var isFriend = Ui.Plugin.Common.Functions.FriendList.List.Any(friend => friend.Name.TextValue == player.PlayerName && friend.HomeWorld == world.RowId); + var isFriend = LogWindow.Plugin.Common.Functions.FriendList.List.Any(friend => friend.Name.TextValue == player.PlayerName && friend.HomeWorld == world.RowId); if (!isFriend && ImGui.Selectable(Language.Context_SendFriendRequest)) { - Ui.Plugin.Functions.SendFriendRequest(player.PlayerName, (ushort) world.RowId); + LogWindow.Plugin.Functions.SendFriendRequest(player.PlayerName, (ushort) world.RowId); } if (ImGui.Selectable(Language.Context_AddToBlacklist)) { - Ui.Plugin.Functions.AddToBlacklist(player.PlayerName, (ushort) world.RowId); + LogWindow.Plugin.Functions.AddToBlacklist(player.PlayerName, (ushort) world.RowId); } - if (Ui.Plugin.Functions.IsMentor() && ImGui.Selectable(Language.Context_InviteToNoviceNetwork)) { - Ui.Plugin.Functions.Context.InviteToNoviceNetwork(player.PlayerName, (ushort) world.RowId); + if (LogWindow.Plugin.Functions.IsMentor() && ImGui.Selectable(Language.Context_InviteToNoviceNetwork)) { + LogWindow.Plugin.Functions.Context.InviteToNoviceNetwork(player.PlayerName, (ushort) world.RowId); } } var inputChannel = chunk.Message?.Code.Type.ToInputChannel(); if (inputChannel != null && ImGui.Selectable(Language.Context_ReplyInSelectedChatMode)) { - Ui.Plugin.Functions.Chat.SetChannel(inputChannel.Value); - Log.Activate = true; + LogWindow.Plugin.Functions.Chat.SetChannel(inputChannel.Value); + LogWindow.Activate = true; } if (ImGui.Selectable(Language.Context_Target) && FindCharacterForPayload(player) is { } obj) { @@ -580,7 +578,7 @@ internal sealed class PayloadHandler { if (validContentId && ImGui.Selectable(Language.Context_AdventurerPlate)) { - if (!Ui.Plugin.Functions.TryOpenAdventurerPlate(chunk.Message!.ContentId)) + if (!LogWindow.Plugin.Functions.TryOpenAdventurerPlate(chunk.Message!.ContentId)) WrapperUtil.AddNotification(Language.Context_AdventurerPlateError, NotificationType.Warning); } diff --git a/ChatTwo/Plugin.cs b/ChatTwo/Plugin.cs index d9ee386..45c1092 100755 --- a/ChatTwo/Plugin.cs +++ b/ChatTwo/Plugin.cs @@ -2,12 +2,14 @@ using System.Diagnostics; using System.Globalization; using ChatTwo.Ipc; using ChatTwo.Resources; +using ChatTwo.Ui; using ChatTwo.Util; -using Dalamud.Game.Addon.Lifecycle; using Dalamud.Game.ClientState.Objects; +using Dalamud.Interface.Windowing; using Dalamud.IoC; using Dalamud.Plugin; using Dalamud.Plugin.Services; +using ImGuiNET; using XivCommon; namespace ChatTwo; @@ -35,6 +37,12 @@ public sealed class Plugin : IDalamudPlugin { [PluginService] internal static INotificationManager Notification { get; private set; } = null!; [PluginService] internal static IAddonLifecycle AddonLifecycle { get; private set; } = null!; + public readonly WindowSystem WindowSystem = new(PluginName); + + public SettingsWindow SettingsWindow { get; } + public ChatLogWindow ChatLogWindow { get; } + public CommandHelpWindow CommandHelpWindow { get; } + internal Configuration Config { get; } internal Commands Commands { get; } internal XivCommonBase Common { get; } @@ -43,7 +51,7 @@ public sealed class Plugin : IDalamudPlugin { internal Store Store { get; } internal IpcManager Ipc { get; } internal ExtraChat ExtraChat { get; } - internal PluginUi Ui { get; } + internal FontManager FontManager { get; } internal int DeferredSaveFrames = -1; @@ -51,69 +59,90 @@ public sealed class Plugin : IDalamudPlugin { #pragma warning disable CS8618 public Plugin() { - this.GameStarted = Process.GetCurrentProcess().StartTime.ToUniversalTime(); + GameStarted = Process.GetCurrentProcess().StartTime.ToUniversalTime(); - this.Config = Interface.GetPluginConfig() as Configuration ?? new Configuration(); - this.Config.Migrate(); + Config = Interface.GetPluginConfig() as Configuration ?? new Configuration(); + Config.Migrate(); - if (this.Config.Tabs.Count == 0) { - this.Config.Tabs.Add(TabsUtil.VanillaGeneral); + if (Config.Tabs.Count == 0) { + Config.Tabs.Add(TabsUtil.VanillaGeneral); } - this.LanguageChanged(Interface.UiLanguage); + LanguageChanged(Interface.UiLanguage); - this.Commands = new Commands(this); - this.Common = new XivCommonBase(Interface); - this.TextureCache = new TextureCache(TextureProvider); - this.Functions = new GameFunctions.GameFunctions(this); - this.Ipc = new IpcManager(Interface); - this.ExtraChat = new ExtraChat(this); - this.Ui = new PluginUi(this); - Ui.BuildFonts(); + Commands = new Commands(this); + Common = new XivCommonBase(Interface); + TextureCache = new TextureCache(TextureProvider); + Functions = new GameFunctions.GameFunctions(this); + Ipc = new IpcManager(Interface); + ExtraChat = new ExtraChat(this); + FontManager = new FontManager(this); - this.Store = new Store(this); // requires Ui + ChatLogWindow = new ChatLogWindow(this); + SettingsWindow = new SettingsWindow(this); + CommandHelpWindow = new CommandHelpWindow(ChatLogWindow); + + WindowSystem.AddWindow(ChatLogWindow); + WindowSystem.AddWindow(SettingsWindow); + WindowSystem.AddWindow(CommandHelpWindow); + FontManager.BuildFonts(); + + Interface.UiBuilder.DisableCutsceneUiHide = true; + Interface.UiBuilder.DisableGposeUiHide = true; + + Store = new Store(this); // requires Ui // let all the other components register, then initialise commands - this.Commands.Initialise(); + Commands.Initialise(); if (Interface.Reason is not PluginLoadReason.Boot) { - this.Store.FilterAllTabs(false); + Store.FilterAllTabs(false); } Framework.Update += FrameworkUpdate; - Interface.UiBuilder.Draw += Ui.Draw; + Interface.UiBuilder.Draw += Draw; Interface.LanguageChanged += LanguageChanged; - - AddonLifecycle.RegisterListener(AddonEvent.PostRequestedUpdate, "ItemDetail", Ui.ChatLog.PayloadHandler.MoveTooltip); } #pragma warning restore CS8618 public void Dispose() { - AddonLifecycle.UnregisterListener(AddonEvent.PostRequestedUpdate, "ItemDetail", Ui.ChatLog.PayloadHandler.MoveTooltip); - Interface.LanguageChanged -= LanguageChanged; - Interface.UiBuilder.Draw -= Ui.Draw; + Interface.UiBuilder.Draw -= Draw; Framework.Update -= FrameworkUpdate; GameFunctions.GameFunctions.SetChatInteractable(true); - this.Ui.Dispose(); - this.ExtraChat.Dispose(); - this.Ipc.Dispose(); - this.Store.Dispose(); - this.Functions.Dispose(); - this.TextureCache.Dispose(); - this.Common.Dispose(); - this.Commands.Dispose(); + WindowSystem.RemoveAllWindows(); + ChatLogWindow.Dispose(); + SettingsWindow.Dispose(); + + ExtraChat.Dispose(); + Ipc.Dispose(); + Store.Dispose(); + Functions.Dispose(); + TextureCache.Dispose(); + Common.Dispose(); + Commands.Dispose(); + } + + private void Draw() + { + Interface.UiBuilder.DisableUserUiHide = !Config.HideWhenUiHidden; + ChatLogWindow.DefaultText = ImGui.GetStyle().Colors[(int) ImGuiCol.Text]; + + using ((Config.FontsEnabled ? FontManager.RegularFont : FontManager.Axis).Push()) + { + WindowSystem.Draw(); + } } internal void SaveConfig() { - Interface.SavePluginConfig(this.Config); + Interface.SavePluginConfig(Config); } internal void LanguageChanged(string langCode) { - var info = this.Config.LanguageOverride is LanguageOverride.None + var info = Config.LanguageOverride is LanguageOverride.None ? new CultureInfo(langCode) - : new CultureInfo(this.Config.LanguageOverride.Code()); + : new CultureInfo(Config.LanguageOverride.Code()); Language.Culture = info; } diff --git a/ChatTwo/Store.cs b/ChatTwo/Store.cs index 619154a..dda6102 100755 --- a/ChatTwo/Store.cs +++ b/ChatTwo/Store.cs @@ -1,13 +1,10 @@ using System.Collections.Concurrent; using System.Diagnostics; -using System.Numerics; using ChatTwo.Code; -using ChatTwo.Resources; using ChatTwo.Util; using Dalamud.Game.Text; using Dalamud.Game.Text.SeStringHandling; using Dalamud.Plugin.Services; -using ImGuiNET; using LiteDB; using Lumina.Excel.GeneratedSheets; @@ -21,7 +18,7 @@ internal class Store : IDisposable { private ConcurrentQueue<(uint, Message)> Pending { get; } = new(); private Stopwatch CheckpointTimer { get; } = new(); internal ILiteDatabase Database { get; private set; } - private ILiteCollection Messages => this.Database.GetCollection("messages"); + private ILiteCollection Messages => Database.GetCollection("messages"); private Dictionary Formats { get; } = new(); private ulong LastContentId { get; set; } @@ -29,13 +26,13 @@ internal class Store : IDisposable { private ulong CurrentContentId { get { var contentId = Plugin.ClientState.LocalContentId; - return contentId == 0 ? this.LastContentId : contentId; + return contentId == 0 ? LastContentId : contentId; } } internal Store(Plugin plugin) { - this.Plugin = plugin; - this.CheckpointTimer.Start(); + Plugin = plugin; + CheckpointTimer.Start(); BsonMapper.Global = new BsonMapper { IncludeNonPublic = true, @@ -43,7 +40,7 @@ internal class Store : IDisposable { // EnumAsInteger = true, }; - if (this.Plugin.Config.DatabaseMigration == 0) { + if (Plugin.Config.DatabaseMigration == 0) { BsonMapper.Global.Entity() .Id(msg => msg.Id) .Ctor(doc => new Message( @@ -136,26 +133,24 @@ internal class Store : IDisposable { dateTime => dateTime.Subtract(DateTime.UnixEpoch).TotalMilliseconds, bson => DateTime.UnixEpoch.AddMilliseconds(bson.AsInt64) ); - this.Database = this.Connect(); - this.Messages.EnsureIndex(msg => msg.Date); - this.Messages.EnsureIndex(msg => msg.SortCode); - this.Messages.EnsureIndex(msg => msg.ExtraChatChannel); + Database = Connect(); + Messages.EnsureIndex(msg => msg.Date); + Messages.EnsureIndex(msg => msg.SortCode); + Messages.EnsureIndex(msg => msg.ExtraChatChannel); - this.MigrateWrapper(); - - Plugin.ChatGui.ChatMessageUnhandled += this.ChatMessage; - Plugin.Framework.Update += this.GetMessageInfo; - Plugin.Framework.Update += this.UpdateReceiver; - Plugin.ClientState.Logout += this.Logout; + Plugin.ChatGui.ChatMessageUnhandled += ChatMessage; + Plugin.Framework.Update += GetMessageInfo; + Plugin.Framework.Update += UpdateReceiver; + Plugin.ClientState.Logout += Logout; } public void Dispose() { - Plugin.ClientState.Logout -= this.Logout; - Plugin.Framework.Update -= this.UpdateReceiver; - Plugin.Framework.Update -= this.GetMessageInfo; - Plugin.ChatGui.ChatMessageUnhandled -= this.ChatMessage; + Plugin.ClientState.Logout -= Logout; + Plugin.Framework.Update -= UpdateReceiver; + Plugin.Framework.Update -= GetMessageInfo; + Plugin.ChatGui.ChatMessageUnhandled -= ChatMessage; - this.Database.Dispose(); + Database.Dispose(); } private ILiteDatabase Connect() { @@ -163,7 +158,7 @@ internal class Store : IDisposable { dir.Create(); var dbPath = Path.Join(dir.FullName, "chat.db"); - var connection = this.Plugin.Config.SharedMode ? "shared" : "direct"; + var connection = Plugin.Config.SharedMode ? "shared" : "direct"; var connString = $"Filename='{dbPath}';Connection={connection}"; return new LiteDatabase(connString, BsonMapper.Global) { CheckpointSize = 1_000, @@ -172,127 +167,46 @@ internal class Store : IDisposable { } internal void Reconnect() { - this.Database.Dispose(); - this.Database = this.Connect(); + Database.Dispose(); + Database = Connect(); } private void Logout() { - this.LastContentId = 0; + LastContentId = 0; } private void UpdateReceiver(IFramework framework) { var contentId = Plugin.ClientState.LocalContentId; if (contentId != 0) { - this.LastContentId = contentId; + LastContentId = contentId; } } private void GetMessageInfo(IFramework framework) { - if (this.CheckpointTimer.Elapsed > TimeSpan.FromMinutes(5)) { - this.CheckpointTimer.Restart(); - new Thread(() => this.Database.Checkpoint()).Start(); + if (CheckpointTimer.Elapsed > TimeSpan.FromMinutes(5)) { + CheckpointTimer.Restart(); + new Thread(() => Database.Checkpoint()).Start(); } - if (!this.Pending.TryDequeue(out var entry)) { + if (!Pending.TryDequeue(out var entry)) { return; } - var contentId = this.Plugin.Functions.Chat.GetContentIdForEntry(entry.Item1); + var contentId = Plugin.Functions.Chat.GetContentIdForEntry(entry.Item1); entry.Item2.ContentId = contentId ?? 0; - if (this.Plugin.Config.DatabaseBattleMessages || !entry.Item2.Code.IsBattle()) { - this.Messages.Update(entry.Item2); - } - } - - private long _migrateCurrent; - private long _migrateMax; - - private void MigrateDraw() { - ImGui.SetNextWindowSizeConstraints(new Vector2(450, 0), new Vector2(450, float.MaxValue)); - if (!ImGui.Begin($"{Plugin.PluginName}##migration-window", ImGuiWindowFlags.AlwaysAutoResize)) { - ImGui.End(); - return; - } - - ImGui.PushTextWrapPos(); - ImGui.TextUnformatted(string.Format(Language.Migration_Line1, Plugin.PluginName)); - ImGui.TextUnformatted(string.Format(Language.Migration_Line2, Plugin.PluginName)); - ImGui.TextUnformatted(Language.Migration_Line3); - ImGui.TextUnformatted(Language.Migration_Line4); - ImGui.PopTextWrapPos(); - - ImGui.Spacing(); - ImGui.ProgressBar((float) this._migrateCurrent / this._migrateMax, new Vector2(-1, 0), $"{this._migrateCurrent} / {this._migrateMax}"); - - ImGui.End(); - } - - internal void MigrateWrapper() { - if (this.Plugin.Config.DatabaseMigration < Configuration.LatestDbVersion) { - Plugin.Interface.UiBuilder.Draw += this.MigrateDraw; - } - - try { - this.Migrate(); - } finally { - Plugin.Interface.UiBuilder.Draw -= this.MigrateDraw; - } - } - - internal void Migrate() { - // re-save all messages, which will add the ExtraChat channel - if (this.Plugin.Config.DatabaseMigration == 0) { - var total = (float) this.Messages.LongCount() / 10_000.0; - var rounds = (long) Math.Ceiling(total); - this._migrateMax = rounds; - - var lastId = ObjectId.Empty; - for (var i = 0; i < rounds; i++) { - this._migrateCurrent = i + 1; - Plugin.Log.Info($"Update round {i + 1}/{rounds}"); - var messages = this.Messages.Query() - .OrderBy(msg => msg.Id) - .Where(msg => msg.Id > lastId) - .Limit(10_000) - .ToArray(); - - foreach (var message in messages) { - this.Messages.Update(message); - lastId = message.Id; - } - } - - this.Database.Checkpoint(); - - BsonMapper.Global.Entity() - .Id(msg => msg.Id) - .Ctor(doc => new Message( - doc["_id"].AsObjectId, - (ulong) doc["Receiver"].AsInt64, - (ulong) doc["ContentId"].AsInt64, - DateTime.UnixEpoch.AddMilliseconds(doc["Date"].AsInt64), - doc["Code"].AsDocument, - doc["Sender"].AsArray, - doc["Content"].AsArray, - doc["SenderSource"], - doc["ContentSource"], - doc["SortCode"].AsDocument, - doc["ExtraChatChannel"] - )); - - this.Plugin.Config.DatabaseMigration = 1; - this.Plugin.SaveConfig(); + if (Plugin.Config.DatabaseBattleMessages || !entry.Item2.Code.IsBattle()) { + Messages.Update(entry.Item2); } } internal void AddMessage(Message message, Tab? currentTab) { - if (this.Plugin.Config.DatabaseBattleMessages || !message.Code.IsBattle()) { - this.Messages.Insert(message); + if (Plugin.Config.DatabaseBattleMessages || !message.Code.IsBattle()) { + Messages.Insert(message); } var currentMatches = currentTab?.Matches(message) ?? false; - foreach (var tab in this.Plugin.Config.Tabs) { + foreach (var tab in Plugin.Config.Tabs) { var unread = !(tab.UnreadMode == UnreadMode.Unseen && currentTab != tab && currentMatches); if (tab.Matches(message)) { @@ -302,8 +216,8 @@ internal class Store : IDisposable { } internal void FilterAllTabs(bool unread = true) { - foreach (var tab in this.Plugin.Config.Tabs) { - this.FilterTab(tab, unread); + foreach (var tab in Plugin.Config.Tabs) { + FilterTab(tab, unread); } } @@ -322,13 +236,13 @@ internal class Store : IDisposable { } } - var query = this.Messages + var query = Messages .Query() .OrderByDescending(msg => msg.Date) .Where(msg => sortCodes.Contains(msg.SortCode) || msg.ExtraChatChannel != Guid.Empty) - .Where(msg => msg.Receiver == this.CurrentContentId); - if (!this.Plugin.Config.FilterIncludePreviousSessions) { - query = query.Where(msg => msg.Date >= this.Plugin.GameStarted); + .Where(msg => msg.Receiver == CurrentContentId); + if (!Plugin.Config.FilterIncludePreviousSessions) { + query = query.Where(msg => msg.Date >= Plugin.GameStarted); } var messages = query @@ -348,7 +262,7 @@ internal class Store : IDisposable { NameFormatting? formatting = null; if (sender.Payloads.Count > 0) { - formatting = this.FormatFor(chatCode.Type); + formatting = FormatFor(chatCode.Type); } var senderChunks = new List(); @@ -364,12 +278,12 @@ internal class Store : IDisposable { var messageChunks = ChunkUtil.ToChunks(message, ChunkSource.Content, chatCode.Type).ToList(); - var msg = new Message(this.CurrentContentId, chatCode, senderChunks, messageChunks, sender, message); - this.AddMessage(msg, this.Plugin.Ui.CurrentTab ?? null); + var msg = new Message(CurrentContentId, chatCode, senderChunks, messageChunks, sender, message); + AddMessage(msg, Plugin.ChatLogWindow.CurrentTab ?? null); - var idx = this.Plugin.Functions.GetCurrentChatLogEntryIndex(); + var idx = Plugin.Functions.GetCurrentChatLogEntryIndex(); if (idx != null) { - this.Pending.Enqueue((idx.Value - 1, msg)); + Pending.Enqueue((idx.Value - 1, msg)); } } @@ -393,7 +307,7 @@ internal class Store : IDisposable { } private NameFormatting? FormatFor(ChatType type) { - if (this.Formats.TryGetValue(type, out var cached)) { + if (Formats.TryGetValue(type, out var cached)) { return cached; } @@ -434,7 +348,7 @@ internal class Store : IDisposable { string.Join("", after) ); - this.Formats[type] = nameFormatting; + Formats[type] = nameFormatting; return nameFormatting; } diff --git a/ChatTwo/Ui/ChatLog.cs b/ChatTwo/Ui/ChatLogWindow.cs old mode 100755 new mode 100644 similarity index 81% rename from ChatTwo/Ui/ChatLog.cs rename to ChatTwo/Ui/ChatLogWindow.cs index d68dee7..7bdc7ae --- a/ChatTwo/Ui/ChatLog.cs +++ b/ChatTwo/Ui/ChatLogWindow.cs @@ -6,6 +6,7 @@ using ChatTwo.Code; using ChatTwo.GameFunctions.Types; using ChatTwo.Resources; using ChatTwo.Util; +using Dalamud.Game.Addon.Lifecycle; using Dalamud.Game.ClientState.Conditions; using Dalamud.Game.ClientState.Keys; using Dalamud.Game.Text.SeStringHandling; @@ -13,17 +14,34 @@ using Dalamud.Game.Text.SeStringHandling.Payloads; using Dalamud.Interface; using Dalamud.Interface.Internal; using Dalamud.Interface.Utility; +using Dalamud.Interface.Windowing; using Dalamud.Memory; using ImGuiNET; using Lumina.Excel.GeneratedSheets; namespace ChatTwo.Ui; -internal sealed class ChatLog : IUiComponent { +public sealed class ChatLogWindow : Window, IUiComponent { private const string ChatChannelPicker = "chat-channel-picker"; private const string AutoCompleteId = "##chat2-autocomplete"; - internal PluginUi Ui { get; } + internal Plugin Plugin { get; } + + internal bool ScreenshotMode; + internal string Salt { get; } + + internal Vector4 DefaultText { get; set; } + + internal Tab? CurrentTab { + get { + var i = LastTab; + if (i > -1 && i < Plugin.Config.Tabs.Count) { + return Plugin.Config.Tabs[i]; + } + + return null; + } + } internal bool Activate; private int _activatePos = -1; @@ -35,7 +53,6 @@ internal sealed class ChatLog : IUiComponent { private InputChannel? _tempChannel; private TellTarget? _tellTarget; private readonly Stopwatch _lastResize = new(); - private CommandHelp? _commandHelp; private AutoCompleteInfo? _autoCompleteInfo; private bool _autoCompleteOpen; private List? _autoCompleteList; @@ -49,46 +66,59 @@ internal sealed class ChatLog : IUiComponent { public unsafe ImGuiViewport* LastViewport; private bool _wasDocked; - public PayloadHandler PayloadHandler { get; } - private Lender HandlerLender { get; } + internal PayloadHandler PayloadHandler { get; } + internal Lender HandlerLender { get; } private Dictionary TextCommandChannels { get; } = new(); private HashSet AllCommands { get; } = new(); - internal ChatLog(PluginUi ui) { - Ui = ui; - PayloadHandler = new PayloadHandler(Ui, this); - HandlerLender = new Lender(() => new PayloadHandler(Ui, this)); + internal ChatLogWindow(Plugin plugin) : base($"{Plugin.PluginName}###chat2") { + Plugin = plugin; + Salt = new Random().Next().ToString(); + + SizeCondition = ImGuiCond.FirstUseEver; + SizeConstraints = new WindowSizeConstraints + { + MinimumSize = new Vector2(500, 250), + MaximumSize = new Vector2(float.MaxValue, float.MaxValue) + }; + + PayloadHandler = new PayloadHandler(this); + HandlerLender = new Lender(() => new PayloadHandler(this)); SetUpTextCommandChannels(); SetUpAllCommands(); - Ui.Plugin.Commands.Register("/clearlog2", "Clear the Chat 2 chat log").Execute += ClearLog; - Ui.Plugin.Commands.Register("/chat2").Execute += ToggleChat; + Plugin.Commands.Register("/clearlog2", "Clear the Chat 2 chat log").Execute += ClearLog; + Plugin.Commands.Register("/chat2").Execute += ToggleChat; _fontIcon = Plugin.TextureProvider.GetTextureFromGame("common/font/fonticon_ps5.tex"); - Ui.Plugin.Functions.Chat.Activated += Activated; + Plugin.Functions.Chat.Activated += Activated; Plugin.ClientState.Login += Login; Plugin.ClientState.Logout += Logout; + + Plugin.AddonLifecycle.RegisterListener(AddonEvent.PostRequestedUpdate, "ItemDetail", PayloadHandler.MoveTooltip); } public void Dispose() { + Plugin.AddonLifecycle.UnregisterListener(AddonEvent.PostRequestedUpdate, "ItemDetail", PayloadHandler.MoveTooltip); + Plugin.ClientState.Logout -= Logout; Plugin.ClientState.Login -= Login; - Ui.Plugin.Functions.Chat.Activated -= Activated; + Plugin.Functions.Chat.Activated -= Activated; _fontIcon?.Dispose(); - Ui.Plugin.Commands.Register("/chat2").Execute -= ToggleChat; - Ui.Plugin.Commands.Register("/clearlog2").Execute -= ClearLog; + Plugin.Commands.Register("/chat2").Execute -= ToggleChat; + Plugin.Commands.Register("/clearlog2").Execute -= ClearLog; } private void Logout() { - foreach (var tab in Ui.Plugin.Config.Tabs) { + foreach (var tab in Plugin.Config.Tabs) { tab.Clear(); } } private void Login() { - Ui.Plugin.Store.FilterAllTabs(false); + Plugin.Store.FilterAllTabs(false); } private void Activated(ChatActivatedArgs args) { @@ -107,7 +137,7 @@ internal sealed class ChatLog : IUiComponent { var prevTemp = _tempChannel; if (info.Permanent) { - Ui.Plugin.Functions.Chat.SetChannel(info.Channel.Value); + Plugin.Functions.Chat.SetChannel(info.Channel.Value); } else { _tempChannel = info.Channel.Value; } @@ -120,7 +150,7 @@ internal sealed class ChatLog : IUiComponent { ? -1 : 1; - var tellInfo = Ui.Plugin.Functions.Chat.GetTellHistoryInfo(idx); + var tellInfo = Plugin.Functions.Chat.GetTellHistoryInfo(idx); if (tellInfo != null && reason != null) { _tellTarget = new TellTarget(tellInfo.Name, (ushort) tellInfo.World, tellInfo.ContentId, reason.Value); } @@ -140,10 +170,10 @@ internal sealed class ChatLog : IUiComponent { : info.Rotate; if (info.Channel is InputChannel.Linkshell1 && info.Rotate != RotateMode.None) { - var idx = Ui.Plugin.Functions.Chat.RotateLinkshellHistory(mode); + var idx = Plugin.Functions.Chat.RotateLinkshellHistory(mode); _tempChannel = info.Channel.Value + (uint) idx; } else if (info.Channel is InputChannel.CrossLinkshell1 && info.Rotate != RotateMode.None) { - var idx = Ui.Plugin.Functions.Chat.RotateCrossLinkshellHistory(mode); + var idx = Plugin.Functions.Chat.RotateCrossLinkshellHistory(mode); _tempChannel = info.Channel.Value + (uint) idx; } } @@ -161,7 +191,7 @@ internal sealed class ChatLog : IUiComponent { private void ClearLog(string command, string arguments) { switch (arguments) { case "all": - foreach (var tab in Ui.Plugin.Config.Tabs) { + foreach (var tab in Plugin.Config.Tabs) { tab.Clear(); } @@ -173,8 +203,8 @@ internal sealed class ChatLog : IUiComponent { break; default: - if (LastTab > -1 && LastTab < Ui.Plugin.Config.Tabs.Count) { - Ui.Plugin.Config.Tabs[LastTab].Clear(); + if (LastTab > -1 && LastTab < Plugin.Config.Tabs.Count) { + Plugin.Config.Tabs[LastTab].Clear(); } break; @@ -287,7 +317,7 @@ internal sealed class ChatLog : IUiComponent { } var turnedOff = new Dictionary(); - foreach (var (toIntercept, keybind) in Ui.Plugin.Functions.Chat.Keybinds) { + foreach (var (toIntercept, keybind) in Plugin.Functions.Chat.Keybinds) { if (toIntercept is "CMD_CHAT" or "CMD_COMMAND") { continue; } @@ -297,7 +327,7 @@ internal sealed class ChatLog : IUiComponent { return; } - var modifierPressed = Ui.Plugin.Config.KeybindMode switch { + var modifierPressed = Plugin.Config.KeybindMode switch { KeybindMode.Strict => modifier == modifierState, KeybindMode.Flexible => modifierState.HasFlag(modifier), _ => false, @@ -354,90 +384,80 @@ internal sealed class ChatLog : IUiComponent { private HideState _hideState = HideState.None; - public void Draw() { - if (!DrawChatLog()) { + public override unsafe void PreOpenCheck() + { + // if the chat has no hide state and in a cutscene, set the hide state to cutscene + if (Plugin.Config.HideDuringCutscenes && _hideState == HideState.None && (CutsceneActive || GposeActive)) + _hideState = HideState.Cutscene; + + // if the chat is hidden because of a cutscene and no longer in a cutscene, set the hide state to none + if (_hideState is HideState.Cutscene or HideState.CutsceneOverride && !CutsceneActive && !GposeActive) + _hideState = HideState.None; + + // if the chat is hidden because of a cutscene and the chat has been activated, show chat + if (_hideState == HideState.Cutscene && Activate) + _hideState = HideState.CutsceneOverride; + + // if the user hid the chat and is now activating chat, reset the hide state + if (_hideState == HideState.User && Activate) + _hideState = HideState.None; + + if (_hideState is HideState.Cutscene or HideState.User) + { + IsOpen = false; return; } - _commandHelp?.Draw(); + if (Plugin.Config.HideWhenNotLoggedIn && !Plugin.ClientState.IsLoggedIn) { + IsOpen = false; + return; + } + + IsOpen = true; + + Flags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse; + if (Plugin.Config.CanMove) + Flags |= ImGuiWindowFlags.NoMove; + + if (Plugin.Config.CanResize) + Flags |= ImGuiWindowFlags.NoResize; + + if (!Plugin.Config.ShowTitleBar) + Flags |= ImGuiWindowFlags.NoTitleBar; + + if (LastViewport == ImGuiHelpers.MainViewport.NativePtr && !_wasDocked) + BgAlpha = Plugin.Config.WindowAlpha / 100f; + + LastViewport = ImGui.GetWindowViewport().NativePtr; + _wasDocked = ImGui.IsWindowDocked(); + } + + public override void Draw() + { + DrawChatLog(); + DrawPopOuts(); DrawAutoComplete(); } /// true if window was rendered - private unsafe bool DrawChatLog() { - // if the chat has no hide state and in a cutscene, set the hide state to cutscene - if (Ui.Plugin.Config.HideDuringCutscenes && _hideState == HideState.None && (CutsceneActive || GposeActive)) { - _hideState = HideState.Cutscene; - } - - // if the chat is hidden because of a cutscene and no longer in a cutscene, set the hide state to none - if (_hideState is HideState.Cutscene or HideState.CutsceneOverride && !CutsceneActive && !GposeActive) { - _hideState = HideState.None; - } - - // if the chat is hidden because of a cutscene and the chat has been activated, show chat - if (_hideState == HideState.Cutscene && Activate) { - _hideState = HideState.CutsceneOverride; - } - - // if the user hid the chat and is now activating chat, reset the hide state - if (_hideState == HideState.User && Activate) { - _hideState = HideState.None; - } - - if (_hideState is HideState.Cutscene or HideState.User) { - return false; - } - - if (Ui.Plugin.Config.HideWhenNotLoggedIn && !Plugin.ClientState.IsLoggedIn) { - return false; - } - - var flags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse; - if (!Ui.Plugin.Config.CanMove) { - flags |= ImGuiWindowFlags.NoMove; - } - - if (!Ui.Plugin.Config.CanResize) { - flags |= ImGuiWindowFlags.NoResize; - } - - if (!Ui.Plugin.Config.ShowTitleBar) { - flags |= ImGuiWindowFlags.NoTitleBar; - } - - if (LastViewport == ImGuiHelpers.MainViewport.NativePtr && !_wasDocked) { - ImGui.SetNextWindowBgAlpha(Ui.Plugin.Config.WindowAlpha / 100f); - } - - ImGui.SetNextWindowSize(new Vector2(500, 250) * ImGuiHelpers.GlobalScale, ImGuiCond.FirstUseEver); - - if (!ImGui.Begin($"{Plugin.PluginName}###chat2", flags)) { - LastViewport = ImGui.GetWindowViewport().NativePtr; - _wasDocked = ImGui.IsWindowDocked(); - ImGui.End(); - return false; - } - + private unsafe void DrawChatLog() + { var resized = LastWindowSize != ImGui.GetWindowSize(); LastWindowSize = ImGui.GetWindowSize(); LastWindowPos = ImGui.GetWindowPos(); - if (resized) { + if (resized) _lastResize.Restart(); - } LastViewport = ImGui.GetWindowViewport().NativePtr; _wasDocked = ImGui.IsWindowDocked(); - var currentTab = Ui.Plugin.Config.SidebarTabView - ? DrawTabSidebar() - : DrawTabBar(); + var currentTab = Plugin.Config.SidebarTabView ? DrawTabSidebar() : DrawTabBar(); Tab? activeTab = null; - if (currentTab > -1 && currentTab < Ui.Plugin.Config.Tabs.Count) { - activeTab = Ui.Plugin.Config.Tabs[currentTab]; + if (currentTab > -1 && currentTab < Plugin.Config.Tabs.Count) { + activeTab = Plugin.Config.Tabs[currentTab]; } ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); @@ -457,23 +477,25 @@ internal sealed class ChatLog : IUiComponent { } else if (_tempChannel != null) { if (_tempChannel.Value.IsLinkshell()) { var idx = (uint) _tempChannel.Value - (uint) InputChannel.Linkshell1; - var lsName = Ui.Plugin.Functions.Chat.GetLinkshellName(idx); + var lsName = Plugin.Functions.Chat.GetLinkshellName(idx); ImGui.TextUnformatted($"LS #{idx + 1}: {lsName}"); } else if (_tempChannel.Value.IsCrossLinkshell()) { var idx = (uint) _tempChannel.Value - (uint) InputChannel.CrossLinkshell1; - var cwlsName = Ui.Plugin.Functions.Chat.GetCrossLinkshellName(idx); + var cwlsName = Plugin.Functions.Chat.GetCrossLinkshellName(idx); ImGui.TextUnformatted($"CWLS [{idx + 1}]: {cwlsName}"); } else { ImGui.TextUnformatted(_tempChannel.Value.ToChatType().Name()); } } else if (activeTab is { Channel: { } channel }) { ImGui.TextUnformatted(channel.ToChatType().Name()); - } else if (Ui.Plugin.ExtraChat.ChannelOverride is var (overrideName, _)) { + } else if (Plugin.ExtraChat.ChannelOverride is var (overrideName, _)) { ImGui.TextUnformatted(overrideName); } else { - DrawChunks(Ui.Plugin.Functions.Chat.Channel.name); + DrawChunks(Plugin.Functions.Chat.Channel.name); } - } finally { + } + finally + { ImGui.PopStyleVar(); } @@ -497,7 +519,7 @@ internal sealed class ChatLog : IUiComponent { ?.RawString ?? channel.ToString(); if (channel.IsLinkshell()) { - var lsName = Ui.Plugin.Functions.Chat.GetLinkshellName(channel.LinkshellIndex()); + var lsName = Plugin.Functions.Chat.GetLinkshellName(channel.LinkshellIndex()); if (string.IsNullOrWhiteSpace(lsName)) { continue; } @@ -506,7 +528,7 @@ internal sealed class ChatLog : IUiComponent { } if (channel.IsCrossLinkshell()) { - var lsName = Ui.Plugin.Functions.Chat.GetCrossLinkshellName(channel.LinkshellIndex()); + var lsName = Plugin.Functions.Chat.GetCrossLinkshellName(channel.LinkshellIndex()); if (string.IsNullOrWhiteSpace(lsName)) { continue; } @@ -515,7 +537,7 @@ internal sealed class ChatLog : IUiComponent { } if (ImGui.Selectable(name)) { - Ui.Plugin.Functions.Chat.SetChannel(channel); + Plugin.Functions.Chat.SetChannel(channel); _tellTarget = null; } } @@ -527,10 +549,10 @@ internal sealed class ChatLog : IUiComponent { var afterIcon = ImGui.GetCursorPos(); var buttonWidth = afterIcon.X - beforeIcon.X; - var showNovice = Ui.Plugin.Config.ShowNoviceNetwork && Ui.Plugin.Functions.IsMentor(); + var showNovice = Plugin.Config.ShowNoviceNetwork && Plugin.Functions.IsMentor(); var inputWidth = ImGui.GetContentRegionAvail().X - buttonWidth * (showNovice ? 2 : 1); - var inputType = _tempChannel?.ToChatType() ?? activeTab?.Channel?.ToChatType() ?? Ui.Plugin.Functions.Chat.Channel.channel.ToChatType(); + var inputType = _tempChannel?.ToChatType() ?? activeTab?.Channel?.ToChatType() ?? Plugin.Functions.Chat.Channel.channel.ToChatType(); var isCommand = Chat.Trim().StartsWith('/'); if (isCommand) { var command = Chat.Split(' ')[0]; @@ -545,15 +567,15 @@ internal sealed class ChatLog : IUiComponent { var normalColour = *ImGui.GetStyleColorVec4(ImGuiCol.Text); - var inputColour = Ui.Plugin.Config.ChatColours.TryGetValue(inputType, out var inputCol) + var inputColour = Plugin.Config.ChatColours.TryGetValue(inputType, out var inputCol) ? inputCol : inputType.DefaultColour(); - if (!isCommand && Ui.Plugin.ExtraChat.ChannelOverride is var (_, overrideColour)) { + if (!isCommand && Plugin.ExtraChat.ChannelOverride is var (_, overrideColour)) { inputColour = overrideColour; } - if (isCommand && Ui.Plugin.ExtraChat.ChannelCommandColours.TryGetValue(Chat.Split(' ')[0], out var ecColour)) { + if (isCommand && Plugin.ExtraChat.ChannelCommandColours.TryGetValue(Chat.Split(' ')[0], out var ecColour)) { inputColour = ecColour; } @@ -567,10 +589,8 @@ internal sealed class ChatLog : IUiComponent { var chatCopy = Chat; ImGui.SetNextItemWidth(inputWidth); - const ImGuiInputTextFlags inputFlags = ImGuiInputTextFlags.CallbackAlways - | ImGuiInputTextFlags.CallbackCharFilter - | ImGuiInputTextFlags.CallbackCompletion - | ImGuiInputTextFlags.CallbackHistory; + const ImGuiInputTextFlags inputFlags = ImGuiInputTextFlags.CallbackAlways | ImGuiInputTextFlags.CallbackCharFilter | + ImGuiInputTextFlags.CallbackCompletion | ImGuiInputTextFlags.CallbackHistory; ImGui.InputText("##chat2-input", ref Chat, 500, inputFlags, Callback); if (ImGui.IsItemDeactivated()) { @@ -618,20 +638,16 @@ internal sealed class ChatLog : IUiComponent { ImGui.SameLine(); if (ImGuiUtil.IconButton(FontAwesomeIcon.Cog)) { - Ui.SettingsVisible ^= true; + Plugin.SettingsWindow.IsOpen ^= true; } if (showNovice) { ImGui.SameLine(); if (ImGuiUtil.IconButton(FontAwesomeIcon.Leaf)) { - Ui.Plugin.Functions.ClickNoviceNetworkButton(); + Plugin.Functions.ClickNoviceNetworkButton(); } } - - ImGui.End(); - - return true; } private void SendChatBox(Tab? activeTab) { @@ -646,11 +662,11 @@ internal sealed class ChatLog : IUiComponent { var reason = target.Reason; var world = Plugin.DataManager.GetExcelSheet()?.GetRow(target.World); if (world is { IsPublic: true }) { - if (reason == TellReason.Reply && Ui.Plugin.Common.Functions.FriendList.List.Any(friend => friend.ContentId == target.ContentId)) { + if (reason == TellReason.Reply && Plugin.Common.Functions.FriendList.List.Any(friend => friend.ContentId == target.ContentId)) { reason = TellReason.Friend; } - Ui.Plugin.Functions.Chat.SendTell(reason, target.ContentId, target.Name, (ushort) world.RowId, trimmed); + Plugin.Functions.Chat.SendTell(reason, target.ContentId, target.Name, (ushort) world.RowId, trimmed); } if (_tempChannel is InputChannel.Tell) { @@ -671,7 +687,7 @@ internal sealed class ChatLog : IUiComponent { var bytes = Encoding.UTF8.GetBytes(trimmed); AutoTranslate.ReplaceWithPayload(Plugin.DataManager, ref bytes); - Ui.Plugin.Common.Functions.Chat.SendMessageUnsafe(bytes); + Plugin.Common.Functions.Chat.SendMessageUnsafe(bytes); } Skip: @@ -682,13 +698,13 @@ internal sealed class ChatLog : IUiComponent { _hideState = HideState.User; } - private void DrawMessageLog(Tab tab, PayloadHandler handler, float childHeight, bool switchedTab) { + internal void DrawMessageLog(Tab tab, PayloadHandler handler, float childHeight, bool switchedTab) { if (ImGui.BeginChild("##chat2-messages", new Vector2(-1, childHeight))) { ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, Vector2.Zero); - var table = tab.DisplayTimestamp && Ui.Plugin.Config.PrettierTimestamps; + var table = tab.DisplayTimestamp && Plugin.Config.PrettierTimestamps; var oldCellPaddingY = ImGui.GetStyle().CellPadding.Y; - if (Ui.Plugin.Config.PrettierTimestamps && Ui.Plugin.Config.MoreCompactPretty) { + if (Plugin.Config.PrettierTimestamps && Plugin.Config.MoreCompactPretty) { var padding = ImGui.GetStyle().CellPadding; padding.Y = 0; @@ -726,7 +742,7 @@ internal sealed class ChatLog : IUiComponent { message.IsVisible = false; } - if (Ui.Plugin.Config.CollapseDuplicateMessages) { + if (Plugin.Config.CollapseDuplicateMessages) { var messageHash = message.Hash; var same = lastMessageHash == messageHash; if (same) { @@ -794,7 +810,7 @@ internal sealed class ChatLog : IUiComponent { if (tab.DisplayTimestamp) { var timestamp = message.Date.ToLocalTime().ToString("t"); if (table) { - if (!Ui.Plugin.Config.HideSameTimestamps || timestamp != lastTimestamp) { + if (!Plugin.Config.HideSameTimestamps || timestamp != lastTimestamp) { ImGui.TextUnformatted(timestamp); lastTimestamp = timestamp; } @@ -827,7 +843,7 @@ internal sealed class ChatLog : IUiComponent { var afterDraw = ImGui.GetCursorScreenPos(); message.Height = ImGui.GetCursorPosY() - lastPos; - if (Ui.Plugin.Config.PrettierTimestamps && !Ui.Plugin.Config.MoreCompactPretty) { + if (Plugin.Config.PrettierTimestamps && !Plugin.Config.MoreCompactPretty) { message.Height -= oldCellPaddingY * 2; beforeDraw.Y += oldCellPaddingY; afterDraw.Y -= oldCellPaddingY; @@ -840,7 +856,7 @@ internal sealed class ChatLog : IUiComponent { } } finally { tab.MessagesMutex.Release(); - ImGui.PopStyleVar(Ui.Plugin.Config.PrettierTimestamps && Ui.Plugin.Config.MoreCompactPretty ? 2 : 1); + ImGui.PopStyleVar(Plugin.Config.PrettierTimestamps && Plugin.Config.MoreCompactPretty ? 2 : 1); } if (switchedTab || ImGui.GetScrollY() >= ImGui.GetScrollMaxY()) { @@ -865,8 +881,8 @@ internal sealed class ChatLog : IUiComponent { return currentTab; } - for (var tabI = 0; tabI < Ui.Plugin.Config.Tabs.Count; tabI++) { - var tab = Ui.Plugin.Config.Tabs[tabI]; + for (var tabI = 0; tabI < Plugin.Config.Tabs.Count; tabI++) { + var tab = Plugin.Config.Tabs[tabI]; if (tab.PopOut) { continue; } @@ -909,8 +925,8 @@ internal sealed class ChatLog : IUiComponent { var switchedTab = false; var childHeight = GetRemainingHeightForMessageLog(); if (ImGui.BeginChild("##chat2-tab-sidebar", new Vector2(-1, childHeight))) { - for (var tabI = 0; tabI < Ui.Plugin.Config.Tabs.Count; tabI++) { - var tab = Ui.Plugin.Config.Tabs[tabI]; + for (var tabI = 0; tabI < Plugin.Config.Tabs.Count; tabI++) { + var tab = Plugin.Config.Tabs[tabI]; if (tab.PopOut) { continue; } @@ -933,13 +949,13 @@ internal sealed class ChatLog : IUiComponent { ImGui.TableNextColumn(); - if (currentTab == -1 && LastTab < Ui.Plugin.Config.Tabs.Count) { + if (currentTab == -1 && LastTab < Plugin.Config.Tabs.Count) { currentTab = LastTab; - Ui.Plugin.Config.Tabs[currentTab].Unread = 0; + Plugin.Config.Tabs[currentTab].Unread = 0; } if (currentTab > -1) { - DrawMessageLog(Ui.Plugin.Config.Tabs[currentTab], PayloadHandler, childHeight, switchedTab); + DrawMessageLog(Plugin.Config.Tabs[currentTab], PayloadHandler, childHeight, switchedTab); } ImGui.EndTable(); @@ -952,7 +968,7 @@ internal sealed class ChatLog : IUiComponent { return; } - var tabs = Ui.Plugin.Config.Tabs; + var tabs = Plugin.Config.Tabs; var anyChanged = false; ImGui.PushID($"tab-context-menu-{i}"); @@ -969,7 +985,7 @@ internal sealed class ChatLog : IUiComponent { ImGui.SameLine(); - var (leftIcon, leftTooltip) = Ui.Plugin.Config.SidebarTabView + var (leftIcon, leftTooltip) = Plugin.Config.SidebarTabView ? (FontAwesomeIcon.ArrowUp, Language.ChatLog_Tabs_MoveUp) : (FontAwesomeIcon.ArrowLeft, Language.ChatLog_Tabs_MoveLeft); if (ImGuiUtil.IconButton(leftIcon, tooltip: leftTooltip) && i > 0) { @@ -980,7 +996,7 @@ internal sealed class ChatLog : IUiComponent { ImGui.SameLine(); - var (rightIcon, rightTooltip) = Ui.Plugin.Config.SidebarTabView + var (rightIcon, rightTooltip) = Plugin.Config.SidebarTabView ? (FontAwesomeIcon.ArrowDown, Language.ChatLog_Tabs_MoveDown) : (FontAwesomeIcon.ArrowRight, Language.ChatLog_Tabs_MoveRight); if (ImGuiUtil.IconButton(rightIcon, tooltip: rightTooltip) && i < tabs.Count - 1) { @@ -996,67 +1012,35 @@ internal sealed class ChatLog : IUiComponent { } if (anyChanged) { - Ui.Plugin.SaveConfig(); + Plugin.SaveConfig(); } ImGui.PopID(); ImGui.EndPopup(); } - private readonly List _popOutDocked = new(); - + internal readonly List PopOutDocked = new(); + internal Dictionary PopOutWindows = new(); private void DrawPopOuts() { HandlerLender.ResetCounter(); - if (_popOutDocked.Count != Ui.Plugin.Config.Tabs.Count) { - _popOutDocked.Clear(); - _popOutDocked.AddRange(Enumerable.Repeat(false, Ui.Plugin.Config.Tabs.Count)); + if (PopOutDocked.Count != Plugin.Config.Tabs.Count) { + PopOutDocked.Clear(); + PopOutDocked.AddRange(Enumerable.Repeat(false, Plugin.Config.Tabs.Count)); } - for (var i = 0; i < Ui.Plugin.Config.Tabs.Count; i++) { - var tab = Ui.Plugin.Config.Tabs[i]; - if (!tab.PopOut) { + for (var i = 0; i < Plugin.Config.Tabs.Count; i++) { + var tab = Plugin.Config.Tabs[i]; + if (!tab.PopOut) continue; - } - DrawPopOut(tab, i); - } - } + if (PopOutWindows.ContainsKey($"{tab.Name}{i}")) + continue; - private void DrawPopOut(Tab tab, int idx) { - var flags = ImGuiWindowFlags.None; - if (!Ui.Plugin.Config.ShowPopOutTitleBar) { - flags |= ImGuiWindowFlags.NoTitleBar; - } + var window = new Popout(this, tab, i) { IsOpen = true }; - if (!_popOutDocked[idx]) { - var alpha = tab.IndependentOpacity ? tab.Opacity : Ui.Plugin.Config.WindowAlpha; - ImGui.SetNextWindowBgAlpha(alpha / 100f); - } - - ImGui.SetNextWindowSize(new Vector2(350, 350) * ImGuiHelpers.GlobalScale, ImGuiCond.FirstUseEver); - if (!ImGui.Begin($"{tab.Name}##popout", ref tab.PopOut, flags)) { - goto End; - } - - ImGui.PushID($"popout-{tab.Name}"); - - if (!Ui.Plugin.Config.ShowPopOutTitleBar) { - ImGui.TextUnformatted(tab.Name); - ImGui.Separator(); - } - - var handler = HandlerLender.Borrow(); - DrawMessageLog(tab, handler, ImGui.GetContentRegionAvail().Y, false); - - ImGui.PopID(); - - End: - _popOutDocked[idx] = ImGui.IsWindowDocked(); - ImGui.End(); - - if (!tab.PopOut) { - Ui.Plugin.SaveConfig(); + Plugin.WindowSystem.AddWindow(window); + PopOutWindows.Add($"{tab.Name}{i}", window); } } @@ -1065,7 +1049,7 @@ internal sealed class ChatLog : IUiComponent { return; } - _autoCompleteList ??= AutoTranslate.Matching(Plugin.DataManager, _autoCompleteInfo.ToComplete, Ui.Plugin.Config.SortAutoTranslate); + _autoCompleteList ??= AutoTranslate.Matching(Plugin.DataManager, _autoCompleteInfo.ToComplete, Plugin.Config.SortAutoTranslate); if (_autoCompleteOpen) { ImGui.OpenPopup(AutoCompleteId); @@ -1086,7 +1070,7 @@ internal sealed class ChatLog : IUiComponent { ImGui.SetNextItemWidth(-1); if (ImGui.InputTextWithHint("##auto-complete-filter", Language.AutoTranslate_Search_Hint, ref _autoCompleteInfo.ToComplete, 256, ImGuiInputTextFlags.CallbackAlways | ImGuiInputTextFlags.CallbackHistory, AutoCompleteCallback)) { - _autoCompleteList = AutoTranslate.Matching(Plugin.DataManager, _autoCompleteInfo.ToComplete, Ui.Plugin.Config.SortAutoTranslate); + _autoCompleteList = AutoTranslate.Matching(Plugin.DataManager, _autoCompleteInfo.ToComplete, Plugin.Config.SortAutoTranslate); _autoCompleteSelection = 0; _autoCompleteShouldScroll = true; } @@ -1242,7 +1226,7 @@ internal sealed class ChatLog : IUiComponent { } if (data->EventFlag == ImGuiInputTextFlags.CallbackCharFilter) { - var valid = Ui.Plugin.Functions.Chat.IsCharValid((char) ptr.EventChar); + var valid = Plugin.Functions.Chat.IsCharValid((char) ptr.EventChar); if (!valid) { return 1; } @@ -1263,12 +1247,12 @@ internal sealed class ChatLog : IUiComponent { || cmd.ShortCommand.RawString == command || cmd.ShortAlias.RawString == command); if (cmd != null) { - _commandHelp = new CommandHelp(this, cmd); + Plugin.CommandHelpWindow.UpdateContent(cmd); + Plugin.CommandHelpWindow.IsOpen = true; goto PostCommandHelp; } } - - _commandHelp = null; + Plugin.CommandHelpWindow.IsOpen = false; PostCommandHelp: if (data->EventFlag != ImGuiInputTextFlags.CallbackHistory) { @@ -1344,7 +1328,7 @@ internal sealed class ChatLog : IUiComponent { if (bounds != null) { var texSize = new Vector2(_fontIcon.Width, _fontIcon.Height); - var sizeRatio = Ui.Plugin.Config.FontSize / bounds.Value.W; + var sizeRatio = Plugin.Config.FontSize / bounds.Value.W; var size = new Vector2(bounds.Value.Z, bounds.Value.W) * sizeRatio * ImGuiHelpers.GlobalScale; var uv0 = new Vector2(bounds.Value.X, bounds.Value.Y - 2) / texSize; @@ -1363,7 +1347,7 @@ internal sealed class ChatLog : IUiComponent { var colour = text.Foreground; if (colour == null && text.FallbackColour != null) { var type = text.FallbackColour.Value; - colour = Ui.Plugin.Config.ChatColours.TryGetValue(type, out var col) + colour = Plugin.Config.ChatColours.TryGetValue(type, out var col) ? col : type.DefaultColour(); } @@ -1376,29 +1360,29 @@ internal sealed class ChatLog : IUiComponent { var pushed = false; if (text.Italic) { pushed = true; - (Ui.Plugin.Config.FontsEnabled && Ui.ItalicFont != null ? Ui.ItalicFont : Ui.AxisItalic).Push(); + (Plugin.Config.FontsEnabled && Plugin.FontManager.ItalicFont != null ? Plugin.FontManager.ItalicFont : Plugin.FontManager.AxisItalic).Push(); } var content = text.Content; - if (Ui.ScreenshotMode) { + if (ScreenshotMode) { if (chunk.Link is PlayerPayload playerPayload) { - var hashCode = $"{Ui.Salt}{playerPayload.PlayerName}{playerPayload.World.RowId}".GetHashCode(); + var hashCode = $"{Salt}{playerPayload.PlayerName}{playerPayload.World.RowId}".GetHashCode(); content = $"Player {hashCode:X8}"; } else if (Plugin.ClientState.LocalPlayer is { } player && content.Contains(player.Name.TextValue)) { - var hashCode = $"{Ui.Salt}{player.Name.TextValue}{player.HomeWorld.Id}".GetHashCode(); + var hashCode = $"{Salt}{player.Name.TextValue}{player.HomeWorld.Id}".GetHashCode(); content = content.Replace(player.Name.TextValue, $"Player {hashCode:X8}"); } } if (wrap) { - ImGuiUtil.WrapText(content, chunk, handler, Ui.DefaultText, lineWidth); + ImGuiUtil.WrapText(content, chunk, handler, DefaultText, lineWidth); } else { ImGui.TextUnformatted(content); ImGuiUtil.PostPayload(chunk, handler); } if (pushed) { - (Ui.Plugin.Config.FontsEnabled && Ui.ItalicFont != null ? Ui.ItalicFont : Ui.AxisItalic).Pop(); + (Plugin.Config.FontsEnabled && Plugin.FontManager.ItalicFont != null ? Plugin.FontManager.ItalicFont : Plugin.FontManager.AxisItalic).Pop(); } if (colour != null) { diff --git a/ChatTwo/Ui/CommandHelp.cs b/ChatTwo/Ui/CommandHelp.cs deleted file mode 100755 index 644a398..0000000 --- a/ChatTwo/Ui/CommandHelp.cs +++ /dev/null @@ -1,57 +0,0 @@ -using System.Numerics; -using ChatTwo.Util; -using Dalamud.Interface.Utility; -using Dalamud.Utility; -using ImGuiNET; -using Lumina.Excel.GeneratedSheets; - -namespace ChatTwo.Ui; - -internal class CommandHelp { - private ChatLog Log { get; } - private TextCommand Command { get; } - - internal CommandHelp(ChatLog log, TextCommand command) { - this.Log = log; - this.Command = command; - } - - internal void Draw() { - var width = 350 * ImGuiHelpers.GlobalScale; - - var pos = this.Log.LastWindowPos; - switch (this.Log.Ui.Plugin.Config.CommandHelpSide) { - case CommandHelpSide.Right: - pos.X += this.Log.LastWindowSize.X; - break; - case CommandHelpSide.Left: - pos.X -= width; - break; - case CommandHelpSide.None: - default: - return; - } - - ImGui.SetNextWindowPos(pos); - - ImGui.SetNextWindowSizeConstraints( - new Vector2(width, 0), - new Vector2(width, this.Log.LastWindowSize.Y) - ); - - const ImGuiWindowFlags flags = ImGuiWindowFlags.NoSavedSettings - | ImGuiWindowFlags.NoTitleBar - | ImGuiWindowFlags.NoMove - | ImGuiWindowFlags.NoResize - | ImGuiWindowFlags.NoFocusOnAppearing - | ImGuiWindowFlags.AlwaysAutoResize; - if (!ImGui.Begin($"command help {this.Command.RowId}", flags)) { - ImGui.End(); - return; - } - - this.Log.DrawChunks(ChunkUtil.ToChunks(this.Command.Description.ToDalamudString(), ChunkSource.None, null).ToList()); - - ImGui.End(); - } -} diff --git a/ChatTwo/Ui/CommandHelpWindow.cs b/ChatTwo/Ui/CommandHelpWindow.cs new file mode 100644 index 0000000..ab9ac55 --- /dev/null +++ b/ChatTwo/Ui/CommandHelpWindow.cs @@ -0,0 +1,57 @@ +using System.Numerics; +using ChatTwo.Util; +using Dalamud.Interface.Utility; +using Dalamud.Interface.Windowing; +using Dalamud.Utility; +using ImGuiNET; +using Lumina.Excel.GeneratedSheets; + +namespace ChatTwo.Ui; + +public class CommandHelpWindow : Window { + private ChatLogWindow LogWindow { get; } + private TextCommand? Command { get; set; } + + internal CommandHelpWindow(ChatLogWindow logWindow) : base($"command help##chat2-commandhelp") + { + LogWindow = logWindow; + + Flags = ImGuiWindowFlags.NoSavedSettings | ImGuiWindowFlags.NoTitleBar | ImGuiWindowFlags.NoMove | + ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoFocusOnAppearing | ImGuiWindowFlags.AlwaysAutoResize; + } + + public void UpdateContent(TextCommand command) + { + Command = command; + + var width = 350; + var scaledWidth = width * ImGuiHelpers.GlobalScale; + var pos = LogWindow.LastWindowPos; + switch (LogWindow.Plugin.Config.CommandHelpSide) { + case CommandHelpSide.Right: + pos.X += LogWindow.LastWindowSize.X; + break; + case CommandHelpSide.Left: + pos.X -= scaledWidth; + break; + case CommandHelpSide.None: + default: + return; + } + + Position = pos; + SizeConstraints = new WindowSizeConstraints + { + MinimumSize = new Vector2(width, 0), + MaximumSize = LogWindow.LastWindowSize with { X = width } + }; + } + + public override void Draw() + { + if (Command == null) + return; + + LogWindow.DrawChunks(ChunkUtil.ToChunks(Command.Description.ToDalamudString(), ChunkSource.None, null).ToList()); + } +} diff --git a/ChatTwo/Ui/Popout.cs b/ChatTwo/Ui/Popout.cs new file mode 100644 index 0000000..5aa0636 --- /dev/null +++ b/ChatTwo/Ui/Popout.cs @@ -0,0 +1,67 @@ +using System.Numerics; +using Dalamud.Interface.Windowing; +using ImGuiNET; + +namespace ChatTwo.Ui; + +internal class Popout : Window +{ + private readonly ChatLogWindow ChatLogWindow; + private readonly Tab Tab; + private readonly int Idx; + + public Popout(ChatLogWindow chatLogWindow, Tab tab, int idx) : base($"{tab.Name}##popout") + { + ChatLogWindow = chatLogWindow; + Tab = tab; + Idx = idx; + + SizeCondition = ImGuiCond.FirstUseEver; + SizeConstraints = new WindowSizeConstraints + { + MinimumSize = new Vector2(350, 350), + MaximumSize = new Vector2(float.MaxValue, float.MaxValue) + }; + } + + public override void PreDraw() + { + Flags = ImGuiWindowFlags.None; + if (!ChatLogWindow.Plugin.Config.ShowPopOutTitleBar) + Flags |= ImGuiWindowFlags.NoTitleBar; + + if (!ChatLogWindow.PopOutDocked[Idx]) { + var alpha = Tab.IndependentOpacity ? Tab.Opacity : ChatLogWindow.Plugin.Config.WindowAlpha; + BgAlpha = alpha / 100f; + } + } + + public override void Draw() + { + ImGui.PushID($"popout-{Tab.Name}"); + + if (!ChatLogWindow.Plugin.Config.ShowPopOutTitleBar) { + ImGui.TextUnformatted(Tab.Name); + ImGui.Separator(); + } + + var handler = ChatLogWindow.HandlerLender.Borrow(); + ChatLogWindow.DrawMessageLog(Tab, handler, ImGui.GetContentRegionAvail().Y, false); + + ImGui.PopID(); + } + + public override void PostDraw() + { + ChatLogWindow.PopOutDocked[Idx] = ImGui.IsWindowDocked(); + } + + public override void OnClose() + { + ChatLogWindow.PopOutWindows.Remove($"{Tab.Name}{Idx}"); + ChatLogWindow.Plugin.WindowSystem.RemoveWindow(this); + + Tab.PopOut = false; + ChatLogWindow.Plugin.SaveConfig(); + } +} \ No newline at end of file diff --git a/ChatTwo/Ui/Settings.cs b/ChatTwo/Ui/Settings.cs index 49e2a50..d4ae5d4 100755 --- a/ChatTwo/Ui/Settings.cs +++ b/ChatTwo/Ui/Settings.cs @@ -1,75 +1,69 @@ -using System.Diagnostics; using System.Numerics; using ChatTwo.Resources; using ChatTwo.Ui.SettingsTabs; using ChatTwo.Util; -using Dalamud.Interface.Utility; +using Dalamud.Interface.Windowing; +using Dalamud.Utility; using ImGuiNET; namespace ChatTwo.Ui; -internal sealed class Settings : IUiComponent { - private PluginUi Ui { get; } +public sealed class SettingsWindow : Window, IUiComponent +{ + private readonly Plugin Plugin; private Configuration Mutable { get; } private List Tabs { get; } - private int _currentTab; + private int CurrentTab; - internal Settings(PluginUi ui) { - this.Ui = ui; - this.Mutable = new Configuration(); + internal SettingsWindow(Plugin plugin) : base($"{Language.Settings_Title.Format(Plugin.PluginName)}###chat2-settings") + { + Flags = ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse; - this.Tabs = new List { - new Display(this.Mutable), - new Ui.SettingsTabs.Fonts(this.Mutable), - new ChatColours(this.Mutable, this.Ui.Plugin), - new Tabs(this.Ui.Plugin, this.Mutable), - new Database(this.Mutable, this.Ui.Plugin.Store), - new Miscellaneous(this.Mutable), + SizeCondition = ImGuiCond.FirstUseEver; + SizeConstraints = new WindowSizeConstraints + { + MinimumSize = new Vector2(475, 600), + MaximumSize = new Vector2(float.MaxValue, float.MaxValue) + }; + + Plugin = plugin; + Mutable = new Configuration(); + + Tabs = new List { + new Display(Mutable), + new Ui.SettingsTabs.Fonts(Mutable), + new ChatColours(Mutable, Plugin), + new Tabs(Plugin, Mutable), + new Database(Mutable, Plugin.Store), + new Miscellaneous(Mutable), new About(), }; - this.Initialise(); + Initialise(); - this.Ui.Plugin.Commands.Register("/chat2", "Perform various actions with Chat 2.").Execute += this.Command; - Plugin.Interface.UiBuilder.OpenConfigUi += this.Toggle; + Plugin.Commands.Register("/chat2", "Perform various actions with Chat 2.").Execute += Command; + Plugin.Interface.UiBuilder.OpenConfigUi += Toggle; } public void Dispose() { - Plugin.Interface.UiBuilder.OpenConfigUi -= this.Toggle; - this.Ui.Plugin.Commands.Register("/chat2").Execute -= this.Command; + Plugin.Interface.UiBuilder.OpenConfigUi -= Toggle; + Plugin.Commands.Register("/chat2").Execute -= Command; } private void Command(string command, string args) { - if (string.IsNullOrWhiteSpace(args)) { - this.Toggle(); - } - } - - private void Toggle() { - this.Ui.SettingsVisible ^= true; + if (string.IsNullOrWhiteSpace(args)) + Toggle(); } private void Initialise() { - this.Mutable.UpdateFrom(this.Ui.Plugin.Config); + Mutable.UpdateFrom(Plugin.Config); } - public void Draw() { - if (!this.Ui.SettingsVisible) { - return; - } - - ImGui.SetNextWindowSize(new Vector2(475, 600) * ImGuiHelpers.GlobalScale, ImGuiCond.FirstUseEver); - - var name = string.Format(Language.Settings_Title, Plugin.PluginName); - if (!ImGui.Begin($"{name}###chat2-settings", ref this.Ui.SettingsVisible, ImGuiWindowFlags.NoScrollbar | ImGuiWindowFlags.NoScrollWithMouse)) { - ImGui.End(); - return; - } - - if (ImGui.IsWindowAppearing()) { - this.Initialise(); - } + public override void Draw() + { + if (ImGui.IsWindowAppearing()) + Initialise(); if (ImGui.BeginTable("##chat2-settings-table", 2)) { ImGui.TableSetupColumn("tab", ImGuiTableColumnFlags.WidthFixed); @@ -78,9 +72,9 @@ internal sealed class Settings : IUiComponent { ImGui.TableNextColumn(); var changed = false; - for (var i = 0; i < this.Tabs.Count; i++) { - if (ImGui.Selectable($"{this.Tabs[i].Name}###tab-{i}", this._currentTab == i)) { - this._currentTab = i; + for (var i = 0; i < Tabs.Count; i++) { + if (ImGui.Selectable($"{Tabs[i].Name}###tab-{i}", CurrentTab == i)) { + CurrentTab = i; changed = true; } } @@ -93,7 +87,7 @@ internal sealed class Settings : IUiComponent { - ImGui.GetStyle().ItemInnerSpacing.Y * 2 - ImGui.CalcTextSize("A").Y; if (ImGui.BeginChild("##chat2-settings", new Vector2(-1, height))) { - this.Tabs[this._currentTab].Draw(changed); + Tabs[CurrentTab].Draw(changed); ImGui.EndChild(); } @@ -108,13 +102,13 @@ internal sealed class Settings : IUiComponent { if (ImGui.Button(Language.Settings_SaveAndClose)) { save = true; - this.Ui.SettingsVisible = false; + IsOpen = false; } ImGui.SameLine(); if (ImGui.Button(Language.Settings_Discard)) { - this.Ui.SettingsVisible = false; + IsOpen = false; } var buttonLabel = "Anna's Ko-fi"; @@ -143,46 +137,44 @@ internal sealed class Settings : IUiComponent { ImGui.PopStyleColor(4); } - ImGui.End(); - if (save) { - var config = this.Ui.Plugin.Config; + var config = Plugin.Config; - var hideChatChanged = this.Mutable.HideChat != this.Ui.Plugin.Config.HideChat; - var fontChanged = this.Mutable.GlobalFont != this.Ui.Plugin.Config.GlobalFont - || this.Mutable.JapaneseFont != this.Ui.Plugin.Config.JapaneseFont - || this.Mutable.ExtraGlyphRanges != this.Ui.Plugin.Config.ExtraGlyphRanges; - var fontSizeChanged = Math.Abs(this.Mutable.FontSize - this.Ui.Plugin.Config.FontSize) > 0.001 - || Math.Abs(this.Mutable.JapaneseFontSize - this.Ui.Plugin.Config.JapaneseFontSize) > 0.001 - || Math.Abs(this.Mutable.SymbolsFontSize - this.Ui.Plugin.Config.SymbolsFontSize) > 0.001; - var langChanged = this.Mutable.LanguageOverride != this.Ui.Plugin.Config.LanguageOverride; - var sharedChanged = this.Mutable.SharedMode != this.Ui.Plugin.Config.SharedMode; + var hideChatChanged = Mutable.HideChat != Plugin.Config.HideChat; + var fontChanged = Mutable.GlobalFont != Plugin.Config.GlobalFont + || Mutable.JapaneseFont != Plugin.Config.JapaneseFont + || Mutable.ExtraGlyphRanges != Plugin.Config.ExtraGlyphRanges; + var fontSizeChanged = Math.Abs(Mutable.FontSize - Plugin.Config.FontSize) > 0.001 + || Math.Abs(Mutable.JapaneseFontSize - Plugin.Config.JapaneseFontSize) > 0.001 + || Math.Abs(Mutable.SymbolsFontSize - Plugin.Config.SymbolsFontSize) > 0.001; + var langChanged = Mutable.LanguageOverride != Plugin.Config.LanguageOverride; + var sharedChanged = Mutable.SharedMode != Plugin.Config.SharedMode; - config.UpdateFrom(this.Mutable); + config.UpdateFrom(Mutable); // save after 60 frames have passed, which should hopefully not // commit any changes that cause a crash - this.Ui.Plugin.DeferredSaveFrames = 60; + Plugin.DeferredSaveFrames = 60; - this.Ui.Plugin.Store.FilterAllTabs(false); + Plugin.Store.FilterAllTabs(false); if (fontChanged || fontSizeChanged) { - this.Ui.BuildFonts(); + Plugin.FontManager.BuildFonts(); } if (langChanged) { - this.Ui.Plugin.LanguageChanged(Plugin.Interface.UiLanguage); + Plugin.LanguageChanged(Plugin.Interface.UiLanguage); } if (sharedChanged) { - this.Ui.Plugin.Store.Reconnect(); + Plugin.Store.Reconnect(); } - if (!this.Mutable.HideChat && hideChatChanged) { + if (!Mutable.HideChat && hideChatChanged) { GameFunctions.GameFunctions.SetChatInteractable(true); } - this.Initialise(); + Initialise(); } } }