diff --git a/ChatTwo/Configuration.cs b/ChatTwo/Configuration.cs index a64accf..79d9123 100755 --- a/ChatTwo/Configuration.cs +++ b/ChatTwo/Configuration.cs @@ -240,6 +240,14 @@ internal class Tab public bool CanMove = true; public bool CanResize = true; + public bool IndependentHide; + public bool HideDuringCutscenes = true; + public bool HideWhenNotLoggedIn = true; + public bool HideWhenUiHidden = true; + public bool HideInLoadingScreens; + public bool HideInBattle; + public bool HideWhenInactive; + [NonSerialized] public uint Unread; [NonSerialized] public long LastActivity; [NonSerialized] public MessageList Messages = new(); @@ -285,6 +293,13 @@ internal class Tab CurrentChannel = CurrentChannel, CanMove = CanMove, CanResize = CanResize, + IndependentHide = IndependentHide, + HideDuringCutscenes = HideDuringCutscenes, + HideWhenNotLoggedIn = HideWhenNotLoggedIn, + HideWhenUiHidden = HideWhenUiHidden, + HideInLoadingScreens = HideInLoadingScreens, + HideInBattle = HideInBattle, + HideWhenInactive = HideWhenInactive, }; } diff --git a/ChatTwo/GameFunctions/Chat.cs b/ChatTwo/GameFunctions/Chat.cs index 44176ac..f256119 100755 --- a/ChatTwo/GameFunctions/Chat.cs +++ b/ChatTwo/GameFunctions/Chat.cs @@ -561,4 +561,14 @@ internal sealed unsafe class Chat : IDisposable _ => playerName }; } + + internal bool CheckHideFlags() + { + // Only hide the chat in a cutscene when the vanilla chat would've + // also been hidden. This prevents Chat 2 from hiding for a split + // second before the cutscene actually starts, because the game sets + // the cutscene conditions before processing the skip. + var raptureAtkUnitManager = RaptureAtkUnitManager.Instance(); + return raptureAtkUnitManager == null || raptureAtkUnitManager->UiFlags.HasFlag(UIModule.UiFlags.Chat); + } } diff --git a/ChatTwo/Plugin.cs b/ChatTwo/Plugin.cs index 001158d..bf05741 100755 --- a/ChatTwo/Plugin.cs +++ b/ChatTwo/Plugin.cs @@ -242,4 +242,8 @@ public sealed class Plugin : IDalamudPlugin if (GameFunctions.GameFunctions.IsAddonInteractable(name)) GameFunctions.GameFunctions.SetAddonInteractable(name, false); } + + public static bool InBattle => Condition[ConditionFlag.InCombat]; + public static bool GposeActive => Condition[ConditionFlag.WatchingCutscene]; + public static bool CutsceneActive => Condition[ConditionFlag.OccupiedInCutSceneEvent] || Condition[ConditionFlag.WatchingCutscene78]; } diff --git a/ChatTwo/Resources/Language.Designer.cs b/ChatTwo/Resources/Language.Designer.cs index 9688f9a..85d3a3e 100755 --- a/ChatTwo/Resources/Language.Designer.cs +++ b/ChatTwo/Resources/Language.Designer.cs @@ -3236,6 +3236,15 @@ namespace ChatTwo.Resources { } } + /// + /// Looks up a localized string similar to Use different hide condition than main window. + /// + internal static string Options_Tabs_IndependentHide { + get { + return ResourceManager.GetString("Options_Tabs_IndependentHide", resourceCulture); + } + } + /// /// Looks up a localized string similar to Use different opacity than main window. /// diff --git a/ChatTwo/Resources/Language.resx b/ChatTwo/Resources/Language.resx index dd7f74f..218ea20 100644 --- a/ChatTwo/Resources/Language.resx +++ b/ChatTwo/Resources/Language.resx @@ -541,6 +541,9 @@ Opacity + + Use different hide condition than main window + Enable custom fonts diff --git a/ChatTwo/Ui/ChatLogWindow.cs b/ChatTwo/Ui/ChatLogWindow.cs index cef664e..ec23bfa 100644 --- a/ChatTwo/Ui/ChatLogWindow.cs +++ b/ChatTwo/Ui/ChatLogWindow.cs @@ -369,10 +369,6 @@ public sealed class ChatLogWindow : Window Plugin.ServerCore.SendNewLogin(); } - internal static bool InBattle => Plugin.Condition[ConditionFlag.InCombat]; - private static bool GposeActive => Plugin.Condition[ConditionFlag.WatchingCutscene]; - private static bool CutsceneActive => Plugin.Condition[ConditionFlag.OccupiedInCutSceneEvent] || Plugin.Condition[ConditionFlag.WatchingCutscene78]; - private enum HideState { None, @@ -385,30 +381,25 @@ public sealed class ChatLogWindow : Window private HideState CurrentHideState = HideState.None; public bool IsHidden; - public unsafe void HideStateCheck() + public void HideStateCheck() { // if the chat has no hide state set, and the player has entered battle, we hide chat if they have configured it - if (Plugin.Config.HideInBattle && CurrentHideState == HideState.None && InBattle) + if (Plugin.Config.HideInBattle && CurrentHideState == HideState.None && Plugin.InBattle) CurrentHideState = HideState.Battle; // If the chat is hidden because of battle, we reset it here - if (CurrentHideState is HideState.Battle && !InBattle) + if (CurrentHideState is HideState.Battle && !Plugin.InBattle) CurrentHideState = HideState.None; // if the chat has no hide state and in a cutscene, set the hide state to cutscene - if (Plugin.Config.HideDuringCutscenes && CurrentHideState == HideState.None && (CutsceneActive || GposeActive)) + if (Plugin.Config.HideDuringCutscenes && CurrentHideState == HideState.None && (Plugin.CutsceneActive || Plugin.GposeActive)) { - // Only hide the chat in a cutscene when the vanilla chat would've - // also been hidden. This prevents Chat 2 from hiding for a split - // second before the cutscene actually starts, because the game sets - // the cutscene conditions before processing the skip. - var raptureAtkUnitManager = RaptureAtkUnitManager.Instance(); - if (raptureAtkUnitManager == null || raptureAtkUnitManager->UiFlags.HasFlag(UIModule.UiFlags.Chat)) + if (Plugin.Functions.Chat.CheckHideFlags()) CurrentHideState = HideState.Cutscene; } // if the chat is hidden because of a cutscene and no longer in a cutscene, set the hide state to none - if (CurrentHideState is HideState.Cutscene or HideState.CutsceneOverride && !CutsceneActive && !GposeActive) + if (CurrentHideState is HideState.Cutscene or HideState.CutsceneOverride && !Plugin.CutsceneActive && !Plugin.GposeActive) CurrentHideState = HideState.None; // if the chat is hidden because of a cutscene and the chat has been activated, show chat @@ -453,7 +444,7 @@ public sealed class ChatLogWindow : Window if (IsHidden) return false; - if (!Plugin.Config.HideWhenInactive || (!Plugin.Config.InactivityHideActiveDuringBattle && InBattle) || Activate) + if (!Plugin.Config.HideWhenInactive || (!Plugin.Config.InactivityHideActiveDuringBattle && Plugin.InBattle) || Activate) { LastActivityTime = FrameTime; return true; diff --git a/ChatTwo/Ui/Popout.cs b/ChatTwo/Ui/Popout.cs index e6c9d98..7a0b395 100644 --- a/ChatTwo/Ui/Popout.cs +++ b/ChatTwo/Ui/Popout.cs @@ -38,10 +38,10 @@ internal class Popout : Window public override bool DrawConditions() { FrameTime = Environment.TickCount64; - if (ChatLogWindow.IsHidden) + if (Tab.IndependentHide ? HideStateCheck() : ChatLogWindow.IsHidden) return false; - if (!Plugin.Config.HideWhenInactive || (!Plugin.Config.InactivityHideActiveDuringBattle && ChatLogWindow.InBattle) || !Tab.UnhideOnActivity) + if (!Plugin.Config.HideWhenInactive || (!Plugin.Config.InactivityHideActiveDuringBattle && Plugin.InBattle) || !Tab.UnhideOnActivity) { LastActivityTime = FrameTime; return true; @@ -108,4 +108,47 @@ internal class Popout : Window Tab.PopOut = false; ChatLogWindow.Plugin.SaveConfig(); } + + private enum HideState + { + None, + Cutscene, + CutsceneOverride, + User, + Battle + } + + private HideState CurrentHideState = HideState.None; + + private bool HideStateCheck() + { + // if the chat has no hide state set, and the player has entered battle, we hide chat if they have configured it + if (Tab.HideInBattle && CurrentHideState == HideState.None && Plugin.InBattle) + CurrentHideState = HideState.Battle; + + // If the chat is hidden because of battle, we reset it here + if (CurrentHideState is HideState.Battle && !Plugin.InBattle) + CurrentHideState = HideState.None; + + // if the chat has no hide state and in a cutscene, set the hide state to cutscene + if (Tab.HideDuringCutscenes && CurrentHideState == HideState.None && (Plugin.CutsceneActive || Plugin.GposeActive)) + { + if (ChatLogWindow.Plugin.Functions.Chat.CheckHideFlags()) + CurrentHideState = HideState.Cutscene; + } + + // if the chat is hidden because of a cutscene and no longer in a cutscene, set the hide state to none + if (CurrentHideState is HideState.Cutscene or HideState.CutsceneOverride && !Plugin.CutsceneActive && !Plugin.GposeActive) + CurrentHideState = HideState.None; + + // if the chat is hidden because of a cutscene and the chat has been activated, show chat + if (CurrentHideState == HideState.Cutscene && ChatLogWindow.Activate) + CurrentHideState = HideState.CutsceneOverride; + + // if the user hid the chat and is now activating chat, reset the hide state + if (CurrentHideState == HideState.User && ChatLogWindow.Activate) + CurrentHideState = HideState.None; + + return CurrentHideState is HideState.Cutscene or HideState.User or HideState.Battle || (Tab.HideWhenNotLoggedIn && !Plugin.ClientState.IsLoggedIn); + } } diff --git a/ChatTwo/Ui/SettingsTabs/Tabs.cs b/ChatTwo/Ui/SettingsTabs/Tabs.cs index e77f655..906410a 100755 --- a/ChatTwo/Ui/SettingsTabs/Tabs.cs +++ b/ChatTwo/Ui/SettingsTabs/Tabs.cs @@ -88,10 +88,31 @@ internal sealed class Tabs : ISettingsTab ImGui.Checkbox(Language.Options_Tabs_PopOut, ref tab.PopOut); if (tab.PopOut) { + using var _ = ImRaii.PushIndent(10.0f); ImGui.Checkbox(Language.Options_Tabs_IndependentOpacity, ref tab.IndependentOpacity); if (tab.IndependentOpacity) ImGuiUtil.DragFloatVertical(Language.Options_Tabs_Opacity, ref tab.Opacity, 0.25f, 0f, 100f, $"{tab.Opacity:N2}%%", ImGuiSliderFlags.AlwaysClamp); + ImGui.Checkbox(Language.Options_Tabs_IndependentHide, ref tab.IndependentHide); + if (tab.IndependentHide) + { + using var __ = ImRaii.PushIndent(10.0f); + ImGuiUtil.OptionCheckbox(ref tab.HideDuringCutscenes, Language.Options_HideDuringCutscenes_Name); + ImGui.Spacing(); + + ImGuiUtil.OptionCheckbox(ref tab.HideWhenNotLoggedIn, Language.Options_HideWhenNotLoggedIn_Name); + ImGui.Spacing(); + + ImGuiUtil.OptionCheckbox(ref tab.HideWhenUiHidden, Language.Options_HideWhenUiHidden_Name); + ImGui.Spacing(); + + ImGuiUtil.OptionCheckbox(ref tab.HideInLoadingScreens, Language.Options_HideInLoadingScreens_Name); + ImGui.Spacing(); + + ImGuiUtil.OptionCheckbox(ref tab.HideInBattle, Language.Options_HideInBattle_Name); + ImGui.Spacing(); + } + ImGuiUtil.OptionCheckbox(ref tab.CanMove, Language.Popout_CanMove_Name); ImGui.Spacing();