feat: autohide improvements
- Adds new setting "Enable inactivity hide during battle" (default: true) which determines whether autohide should apply during battle (thanks @aurieh) - Adds new setting "Chat channels considered for activity" which allows customizing which channels incoming messages must match to "bump" the inactivity timer - Adds new per-tab setting "Unhide the chat window on activity" to configure whether it will be considered for "bumping" the inactivity timer when receiving messages that match the new channel filter. Note that the foreground tab is currently always considered. - Extends autohide code to apply to poped-out tabs as well. Each popout window has its own inactivity timer, but focusing the main window will restore all popped out windows. Co-authored-by: Auri <me@aurieh.me>
This commit is contained in:
+20
-20
@@ -3,6 +3,7 @@ using ChatTwo.Code;
|
|||||||
using ChatTwo.GameFunctions.Types;
|
using ChatTwo.GameFunctions.Types;
|
||||||
using ChatTwo.Resources;
|
using ChatTwo.Resources;
|
||||||
using ChatTwo.Ui;
|
using ChatTwo.Ui;
|
||||||
|
using ChatTwo.Util;
|
||||||
using Dalamud.Configuration;
|
using Dalamud.Configuration;
|
||||||
using Dalamud.Game.ClientState.Keys;
|
using Dalamud.Game.ClientState.Keys;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
@@ -43,6 +44,10 @@ internal class Configuration : IPluginConfiguration
|
|||||||
public bool HideInBattle;
|
public bool HideInBattle;
|
||||||
public bool HideWhenInactive;
|
public bool HideWhenInactive;
|
||||||
public int InactivityHideTimeout = 10;
|
public int InactivityHideTimeout = 10;
|
||||||
|
public bool InactivityHideActiveDuringBattle = true;
|
||||||
|
public Dictionary<ChatType, ChatSource> InactivityHideChannels = TabsUtil.AllChannels();
|
||||||
|
public bool InactivityHideExtraChatAll = true;
|
||||||
|
public HashSet<Guid> InactivityHideExtraChatChannels = [];
|
||||||
public bool ShowHideButton = true;
|
public bool ShowHideButton = true;
|
||||||
public bool NativeItemTooltips = true;
|
public bool NativeItemTooltips = true;
|
||||||
public bool PrettierTimestamps = true;
|
public bool PrettierTimestamps = true;
|
||||||
@@ -106,6 +111,10 @@ internal class Configuration : IPluginConfiguration
|
|||||||
HideInBattle = other.HideInBattle;
|
HideInBattle = other.HideInBattle;
|
||||||
HideWhenInactive = other.HideWhenInactive;
|
HideWhenInactive = other.HideWhenInactive;
|
||||||
InactivityHideTimeout = other.InactivityHideTimeout;
|
InactivityHideTimeout = other.InactivityHideTimeout;
|
||||||
|
InactivityHideActiveDuringBattle = other.InactivityHideActiveDuringBattle;
|
||||||
|
InactivityHideChannels = other.InactivityHideChannels.ToDictionary(entry => entry.Key, entry => entry.Value);
|
||||||
|
InactivityHideExtraChatAll = other.InactivityHideExtraChatAll;
|
||||||
|
InactivityHideExtraChatChannels = other.InactivityHideExtraChatChannels.ToHashSet();
|
||||||
ShowHideButton = other.ShowHideButton;
|
ShowHideButton = other.ShowHideButton;
|
||||||
NativeItemTooltips = other.NativeItemTooltips;
|
NativeItemTooltips = other.NativeItemTooltips;
|
||||||
PrettierTimestamps = other.PrettierTimestamps;
|
PrettierTimestamps = other.PrettierTimestamps;
|
||||||
@@ -188,6 +197,7 @@ internal class Tab
|
|||||||
public HashSet<Guid> ExtraChatChannels = [];
|
public HashSet<Guid> ExtraChatChannels = [];
|
||||||
|
|
||||||
public UnreadMode UnreadMode = UnreadMode.Unseen;
|
public UnreadMode UnreadMode = UnreadMode.Unseen;
|
||||||
|
public bool UnhideOnActivity;
|
||||||
public bool DisplayTimestamp = true;
|
public bool DisplayTimestamp = true;
|
||||||
public InputChannel? Channel;
|
public InputChannel? Channel;
|
||||||
public bool PopOut;
|
public bool PopOut;
|
||||||
@@ -199,7 +209,7 @@ internal class Tab
|
|||||||
public uint Unread;
|
public uint Unread;
|
||||||
|
|
||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
public long LastMessageTime;
|
public long LastActivity;
|
||||||
|
|
||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
public MessageList Messages = new();
|
public MessageList Messages = new();
|
||||||
@@ -210,31 +220,20 @@ internal class Tab
|
|||||||
[NonSerialized]
|
[NonSerialized]
|
||||||
public Guid Identifier = Guid.NewGuid();
|
public Guid Identifier = Guid.NewGuid();
|
||||||
|
|
||||||
internal bool Matches(Message message)
|
internal bool Matches(Message message) => message.Matches(ChatCodes, ExtraChatAll, ExtraChatChannels);
|
||||||
{
|
|
||||||
if (message.ExtraChatChannel != Guid.Empty)
|
|
||||||
return ExtraChatAll || ExtraChatChannels.Contains(message.ExtraChatChannel);
|
|
||||||
|
|
||||||
return message.Code.Type.IsGm()
|
|
||||||
|| ChatCodes.TryGetValue(message.Code.Type, out var sources)
|
|
||||||
&& (message.Code.Source is 0 or (ChatSource) 1
|
|
||||||
|| sources.HasFlag(message.Code.Source));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void AddMessage(Message message, bool unread = true)
|
internal void AddMessage(Message message, bool unread = true)
|
||||||
{
|
{
|
||||||
Messages.AddPrune(message, MessageManager.MessageDisplayLimit);
|
Messages.AddPrune(message, MessageManager.MessageDisplayLimit);
|
||||||
if (unread)
|
if (!unread)
|
||||||
{
|
return;
|
||||||
Unread += 1;
|
Unread += 1;
|
||||||
LastMessageTime = Environment.TickCount64;
|
|
||||||
}
|
if (message.Matches(Plugin.Config.InactivityHideChannels, Plugin.Config.InactivityHideExtraChatAll, Plugin.Config.InactivityHideExtraChatChannels))
|
||||||
|
LastActivity = Environment.TickCount64;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Clear()
|
internal void Clear() => Messages.Clear();
|
||||||
{
|
|
||||||
Messages.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
internal Tab Clone()
|
internal Tab Clone()
|
||||||
{
|
{
|
||||||
@@ -245,6 +244,7 @@ internal class Tab
|
|||||||
ExtraChatAll = ExtraChatAll,
|
ExtraChatAll = ExtraChatAll,
|
||||||
ExtraChatChannels = ExtraChatChannels.ToHashSet(),
|
ExtraChatChannels = ExtraChatChannels.ToHashSet(),
|
||||||
UnreadMode = UnreadMode,
|
UnreadMode = UnreadMode,
|
||||||
|
UnhideOnActivity = UnhideOnActivity,
|
||||||
DisplayTimestamp = DisplayTimestamp,
|
DisplayTimestamp = DisplayTimestamp,
|
||||||
Channel = Channel,
|
Channel = Channel,
|
||||||
PopOut = PopOut,
|
PopOut = PopOut,
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ using FFXIVClientStructs.FFXIV.Client.UI;
|
|||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
using ModifierFlag = ChatTwo.GameFunctions.Types.ModifierFlag;
|
using ModifierFlag = ChatTwo.GameFunctions.Types.ModifierFlag;
|
||||||
|
|
||||||
using ModifierFlag = ChatTwo.GameFunctions.Types.ModifierFlag;
|
|
||||||
|
|
||||||
namespace ChatTwo.GameFunctions;
|
namespace ChatTwo.GameFunctions;
|
||||||
|
|
||||||
internal enum KeyboardSource {
|
internal enum KeyboardSource {
|
||||||
@@ -95,8 +93,8 @@ internal unsafe class KeybindManager : IDisposable {
|
|||||||
|
|
||||||
// List of keys that can be used as a part of keybinds while the chat is
|
// List of keys that can be used as a part of keybinds while the chat is
|
||||||
// focused WITHOUT modifiers. All other keys can only be used if their
|
// focused WITHOUT modifiers. All other keys can only be used if their
|
||||||
// configured keybind contains modifiers. This allows for using e.g. F11 to
|
// configured keybind contains modifiers (except only SHIFT). This allows
|
||||||
// change chat channel while typing.
|
// for using e.g. F11 to change chat channel while typing.
|
||||||
private static readonly IReadOnlyCollection<VirtualKey> ModifierlessChatKeys = new[]
|
private static readonly IReadOnlyCollection<VirtualKey> ModifierlessChatKeys = new[]
|
||||||
{
|
{
|
||||||
// VirtualKey.NO_KEY,
|
// VirtualKey.NO_KEY,
|
||||||
|
|||||||
@@ -124,6 +124,17 @@ internal partial class Message
|
|||||||
return new Message(0, 0, code, [], content, new SeString(), new SeString());
|
return new Message(0, 0, code, [], content, new SeString(), new SeString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool Matches(Dictionary<ChatType, ChatSource> channels, bool allExtraChatChannels, HashSet<Guid> extraChatChannels)
|
||||||
|
{
|
||||||
|
if (ExtraChatChannel != Guid.Empty)
|
||||||
|
return allExtraChatChannels || extraChatChannels.Contains(ExtraChatChannel);
|
||||||
|
|
||||||
|
return Code.Type.IsGm()
|
||||||
|
|| channels.TryGetValue(Code.Type, out var sources)
|
||||||
|
&& (Code.Source is 0 or (ChatSource) 1
|
||||||
|
|| sources.HasFlag(Code.Source));
|
||||||
|
}
|
||||||
|
|
||||||
private int GenerateHash()
|
private int GenerateHash()
|
||||||
{
|
{
|
||||||
return SortCode.GetHashCode()
|
return SortCode.GetHashCode()
|
||||||
|
|||||||
Generated
+73
-1
@@ -2481,7 +2481,7 @@ namespace ChatTwo.Resources {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Hide the chat after a configurable period of inactivity. The current tab and any tabs with unread indicators enabled are considered for activity..
|
/// Looks up a localized string similar to Hide the chat after a configurable period of inactivity. The current tab and any other tabs with the setting enabled are considered for activity..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string Options_HideWhenInactive_Description {
|
internal static string Options_HideWhenInactive_Description {
|
||||||
get {
|
get {
|
||||||
@@ -2534,6 +2534,69 @@ namespace ChatTwo.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to When disabled, the chat log will stay active during battle..
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_InactivityHideActiveDuringBattle_Description {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_InactivityHideActiveDuringBattle_Description", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Enable inactivity hide during battle.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_InactivityHideActiveDuringBattle_Name {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_InactivityHideActiveDuringBattle_Name", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Select All.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_InactivityHideChannels_All_Label {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_InactivityHideChannels_All_Label", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Hold Ctrl+Shift to click..
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_InactivityHideChannels_Button_Tooltip {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_InactivityHideChannels_Button_Tooltip", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Which chat channels should be considered for activity. Other channels will not restore the chat regardless of which tab they occur in..
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_InactivityHideChannels_Description {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_InactivityHideChannels_Description", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Chat channels considered for activity.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_InactivityHideChannels_Name {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_InactivityHideChannels_Name", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Unselect All.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_InactivityHideChannels_None_Label {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_InactivityHideChannels_None_Label", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to How long to wait (in seconds) before considering the chat log inactive..
|
/// Looks up a localized string similar to How long to wait (in seconds) before considering the chat log inactive..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -3137,6 +3200,15 @@ namespace ChatTwo.Resources {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Unhide the chat window on activity.
|
||||||
|
/// </summary>
|
||||||
|
internal static string Options_Tabs_InactivityBehaviour {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Options_Tabs_InactivityBehaviour", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Use different opacity than main window.
|
/// Looks up a localized string similar to Use different opacity than main window.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -220,6 +220,9 @@
|
|||||||
<data name="Options_Tabs_UnreadMode">
|
<data name="Options_Tabs_UnreadMode">
|
||||||
<value>Unread mode</value>
|
<value>Unread mode</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Options_Tabs_InactivityBehaviour">
|
||||||
|
<value>Unhide the chat window on activity</value>
|
||||||
|
</data>
|
||||||
<data name="Options_Tabs_NoInputChannel">
|
<data name="Options_Tabs_NoInputChannel">
|
||||||
<value><None></value>
|
<value><None></value>
|
||||||
</data>
|
</data>
|
||||||
@@ -410,7 +413,7 @@
|
|||||||
<value>Hide when inactive</value>
|
<value>Hide when inactive</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Options_HideWhenInactive_Description">
|
<data name="Options_HideWhenInactive_Description">
|
||||||
<value>Hide the chat after a configurable period of inactivity. The current tab and any tabs with unread indicators enabled are considered for activity.</value>
|
<value>Hide the chat after a configurable period of inactivity. The current tab and any other tabs with the setting enabled are considered for activity.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Options_InactivityHideTimeout_Name">
|
<data name="Options_InactivityHideTimeout_Name">
|
||||||
<value>Inactivity timeout</value>
|
<value>Inactivity timeout</value>
|
||||||
@@ -418,6 +421,27 @@
|
|||||||
<data name="Options_InactivityHideTimeout_Description">
|
<data name="Options_InactivityHideTimeout_Description">
|
||||||
<value>How long to wait (in seconds) before considering the chat log inactive.</value>
|
<value>How long to wait (in seconds) before considering the chat log inactive.</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Options_InactivityHideActiveDuringBattle_Name" xml:space="preserve">
|
||||||
|
<value>Enable inactivity hide during battle</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_InactivityHideActiveDuringBattle_Description" xml:space="preserve">
|
||||||
|
<value>When disabled, the chat log will stay active during battle.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_InactivityHideChannels_Name">
|
||||||
|
<value>Chat channels considered for activity</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_InactivityHideChannels_Description">
|
||||||
|
<value>Which chat channels should be considered for activity. Other channels will not restore the chat regardless of which tab they occur in.</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_InactivityHideChannels_All_Label">
|
||||||
|
<value>Select All</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_InactivityHideChannels_None_Label">
|
||||||
|
<value>Unselect All</value>
|
||||||
|
</data>
|
||||||
|
<data name="Options_InactivityHideChannels_Button_Tooltip">
|
||||||
|
<value>Hold Ctrl+Shift to click.</value>
|
||||||
|
</data>
|
||||||
<data name="Options_KeybindMode_Name">
|
<data name="Options_KeybindMode_Name">
|
||||||
<value>Keybind mode</value>
|
<value>Keybind mode</value>
|
||||||
</data>
|
</data>
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ public sealed class ChatLogWindow : Window
|
|||||||
private bool PlayedClosingSound = true;
|
private bool PlayedClosingSound = true;
|
||||||
|
|
||||||
private long FrameTime; // set every frame
|
private long FrameTime; // set every frame
|
||||||
private long LastActivityTime = Environment.TickCount64;
|
internal long LastActivityTime = Environment.TickCount64;
|
||||||
|
|
||||||
private readonly ExcelSheet<World> WorldSheet;
|
private readonly ExcelSheet<World> WorldSheet;
|
||||||
private readonly ExcelSheet<LogFilter> LogFilterSheet;
|
private readonly ExcelSheet<LogFilter> LogFilterSheet;
|
||||||
@@ -348,7 +348,10 @@ public sealed class ChatLogWindow : Window
|
|||||||
return height;
|
return height;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void ChangeTab(int index) => WantedTab = index;
|
internal void ChangeTab(int index) {
|
||||||
|
WantedTab = index;
|
||||||
|
LastActivityTime = FrameTime;
|
||||||
|
}
|
||||||
|
|
||||||
internal void ChangeTabDelta(int offset)
|
internal void ChangeTabDelta(int offset)
|
||||||
{
|
{
|
||||||
@@ -373,7 +376,7 @@ public sealed class ChatLogWindow : Window
|
|||||||
SetChannel(tab.Channel ?? tab.PreviousChannel);
|
SetChannel(tab.Channel ?? tab.PreviousChannel);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool InBattle => Plugin.Condition[ConditionFlag.InCombat];
|
internal static bool InBattle => Plugin.Condition[ConditionFlag.InCombat];
|
||||||
private static bool GposeActive => Plugin.Condition[ConditionFlag.WatchingCutscene];
|
private static bool GposeActive => Plugin.Condition[ConditionFlag.WatchingCutscene];
|
||||||
private static bool CutsceneActive => Plugin.Condition[ConditionFlag.OccupiedInCutSceneEvent] || Plugin.Condition[ConditionFlag.WatchingCutscene78];
|
private static bool CutsceneActive => Plugin.Condition[ConditionFlag.OccupiedInCutSceneEvent] || Plugin.Condition[ConditionFlag.WatchingCutscene78];
|
||||||
|
|
||||||
@@ -448,7 +451,8 @@ public sealed class ChatLogWindow : Window
|
|||||||
FrameTime = Environment.TickCount64;
|
FrameTime = Environment.TickCount64;
|
||||||
if (IsHidden)
|
if (IsHidden)
|
||||||
return false;
|
return false;
|
||||||
if (!Plugin.Config.HideWhenInactive || Activate)
|
|
||||||
|
if (!Plugin.Config.HideWhenInactive || (!Plugin.Config.InactivityHideActiveDuringBattle && InBattle) || Activate)
|
||||||
{
|
{
|
||||||
LastActivityTime = FrameTime;
|
LastActivityTime = FrameTime;
|
||||||
return true;
|
return true;
|
||||||
@@ -456,11 +460,10 @@ public sealed class ChatLogWindow : Window
|
|||||||
|
|
||||||
var currentTab = CurrentTab; // local to avoid calling the getter repeatedly
|
var currentTab = CurrentTab; // local to avoid calling the getter repeatedly
|
||||||
var lastActivityTime = Plugin.Config.Tabs
|
var lastActivityTime = Plugin.Config.Tabs
|
||||||
.Where(tab => tab.UnreadMode is not UnreadMode.None || tab == currentTab)
|
.Where(tab => !tab.PopOut && (tab.UnhideOnActivity || tab == currentTab))
|
||||||
.Select(tab => tab.LastMessageTime)
|
.Select(tab => tab.LastActivity)
|
||||||
.DefaultIfEmpty(0)
|
.Append(LastActivityTime)
|
||||||
.Max();
|
.Max();
|
||||||
lastActivityTime = Math.Max(lastActivityTime, LastActivityTime);
|
|
||||||
return FrameTime - lastActivityTime <= 1000 * Plugin.Config.InactivityHideTimeout;
|
return FrameTime - lastActivityTime <= 1000 * Plugin.Config.InactivityHideTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+20
-1
@@ -12,6 +12,9 @@ internal class Popout : Window
|
|||||||
private readonly Tab Tab;
|
private readonly Tab Tab;
|
||||||
private readonly int Idx;
|
private readonly int Idx;
|
||||||
|
|
||||||
|
private long FrameTime; // set every frame
|
||||||
|
private long LastActivityTime = Environment.TickCount64;
|
||||||
|
|
||||||
public Popout(ChatLogWindow chatLogWindow, Tab tab, int idx) : base($"{tab.Name}##popout")
|
public Popout(ChatLogWindow chatLogWindow, Tab tab, int idx) : base($"{tab.Name}##popout")
|
||||||
{
|
{
|
||||||
ChatLogWindow = chatLogWindow;
|
ChatLogWindow = chatLogWindow;
|
||||||
@@ -34,7 +37,20 @@ internal class Popout : Window
|
|||||||
|
|
||||||
public override bool DrawConditions()
|
public override bool DrawConditions()
|
||||||
{
|
{
|
||||||
return !ChatLogWindow.IsHidden;
|
FrameTime = Environment.TickCount64;
|
||||||
|
if (ChatLogWindow.IsHidden)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!Plugin.Config.HideWhenInactive || (!Plugin.Config.InactivityHideActiveDuringBattle && ChatLogWindow.InBattle) || !Tab.UnhideOnActivity)
|
||||||
|
{
|
||||||
|
LastActivityTime = FrameTime;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activity in the tab, this popout window, or the main chat log window.
|
||||||
|
var lastActivityTime = Math.Max(Tab.LastActivity, LastActivityTime);
|
||||||
|
lastActivityTime = Math.Max(lastActivityTime, ChatLogWindow.LastActivityTime);
|
||||||
|
return FrameTime - lastActivityTime <= 1000 * Plugin.Config.InactivityHideTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PreDraw()
|
public override void PreDraw()
|
||||||
@@ -65,6 +81,9 @@ internal class Popout : Window
|
|||||||
|
|
||||||
var handler = ChatLogWindow.HandlerLender.Borrow();
|
var handler = ChatLogWindow.HandlerLender.Borrow();
|
||||||
ChatLogWindow.DrawMessageLog(Tab, handler, ImGui.GetContentRegionAvail().Y, false);
|
ChatLogWindow.DrawMessageLog(Tab, handler, ImGui.GetContentRegionAvail().Y, false);
|
||||||
|
|
||||||
|
if (ImGui.IsWindowHovered(ImGuiHoveredFlags.ChildWindows))
|
||||||
|
LastActivityTime = FrameTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void PostDraw()
|
public override void PostDraw()
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using ChatTwo.Resources;
|
using ChatTwo.Resources;
|
||||||
using ChatTwo.Util;
|
using ChatTwo.Util;
|
||||||
|
using Dalamud.Interface.Utility.Raii;
|
||||||
using ImGuiNET;
|
using ImGuiNET;
|
||||||
|
|
||||||
namespace ChatTwo.Ui.SettingsTabs;
|
namespace ChatTwo.Ui.SettingsTabs;
|
||||||
@@ -37,27 +38,70 @@ internal sealed class Display : ISettingsTab
|
|||||||
ImGuiUtil.OptionCheckbox(ref Mutable.HideInBattle, Language.Options_HideInBattle_Name, Language.Options_HideInBattle_Description);
|
ImGuiUtil.OptionCheckbox(ref Mutable.HideInBattle, Language.Options_HideInBattle_Name, Language.Options_HideInBattle_Description);
|
||||||
ImGui.Spacing();
|
ImGui.Spacing();
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
ImGui.Spacing();
|
||||||
|
|
||||||
ImGuiUtil.OptionCheckbox(ref Mutable.HideWhenInactive, Language.Options_HideWhenInactive_Name, Language.Options_HideWhenInactive_Description);
|
ImGuiUtil.OptionCheckbox(ref Mutable.HideWhenInactive, Language.Options_HideWhenInactive_Name, Language.Options_HideWhenInactive_Description);
|
||||||
ImGui.Spacing();
|
ImGui.Spacing();
|
||||||
|
|
||||||
if (Mutable.HideWhenInactive)
|
if (Mutable.HideWhenInactive)
|
||||||
{
|
{
|
||||||
|
using var _ = ImRaii.PushIndent();
|
||||||
ImGuiUtil.InputIntVertical(Language.Options_InactivityHideTimeout_Name,
|
ImGuiUtil.InputIntVertical(Language.Options_InactivityHideTimeout_Name,
|
||||||
Language.Options_InactivityHideTimeout_Description, ref Mutable.InactivityHideTimeout, 1, 10);
|
Language.Options_InactivityHideTimeout_Description, ref Mutable.InactivityHideTimeout, 1, 10);
|
||||||
// Enforce a minimum of 2 seconds to avoid people soft locking
|
// Enforce a minimum of 2 seconds to avoid people soft locking
|
||||||
// themselves.
|
// themselves.
|
||||||
Mutable.InactivityHideTimeout = Math.Max(2, Mutable.InactivityHideTimeout);
|
Mutable.InactivityHideTimeout = Math.Max(2, Mutable.InactivityHideTimeout);
|
||||||
ImGui.Spacing();
|
ImGui.Spacing();
|
||||||
|
|
||||||
|
// This setting conflicts with HideInBattle, so it's disabled.
|
||||||
|
using (ImRaii.Disabled(Mutable.HideInBattle))
|
||||||
|
{
|
||||||
|
ImGuiUtil.OptionCheckbox(ref Mutable.InactivityHideActiveDuringBattle,
|
||||||
|
Language.Options_InactivityHideActiveDuringBattle_Name,
|
||||||
|
Language.Options_InactivityHideActiveDuringBattle_Description);
|
||||||
|
ImGui.Spacing();
|
||||||
|
}
|
||||||
|
|
||||||
|
using var channelTree = ImRaii.TreeNode(Language.Options_InactivityHideChannels_Name);
|
||||||
|
if (channelTree.Success)
|
||||||
|
{
|
||||||
|
if (ImGuiUtil.CtrlShiftButton(Language.Options_InactivityHideChannels_All_Label,
|
||||||
|
Language.Options_InactivityHideChannels_Button_Tooltip))
|
||||||
|
{
|
||||||
|
Mutable.InactivityHideChannels = TabsUtil.AllChannels();
|
||||||
|
Mutable.InactivityHideExtraChatAll = true;
|
||||||
|
Mutable.InactivityHideExtraChatChannels = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
if (ImGuiUtil.CtrlShiftButton(Language.Options_InactivityHideChannels_None_Label,
|
||||||
|
Language.Options_InactivityHideChannels_Button_Tooltip))
|
||||||
|
{
|
||||||
|
Mutable.InactivityHideChannels = new();
|
||||||
|
Mutable.InactivityHideExtraChatAll = false;
|
||||||
|
Mutable.InactivityHideExtraChatChannels = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.Spacing();
|
||||||
|
|
||||||
|
ImGuiUtil.ChannelSelector(Language.Options_Tabs_Channels, Mutable.InactivityHideChannels);
|
||||||
|
ImGuiUtil.ExtraChatSelector(Language.Options_Tabs_ExtraChatChannels,
|
||||||
|
ref Mutable.InactivityHideExtraChatAll, Mutable.InactivityHideExtraChatChannels);
|
||||||
|
}
|
||||||
|
ImGui.Spacing();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ImGui.Separator();
|
||||||
|
ImGui.Spacing();
|
||||||
|
|
||||||
ImGuiUtil.OptionCheckbox(ref Mutable.PrettierTimestamps, Language.Options_PrettierTimestamps_Name, Language.Options_PrettierTimestamps_Description);
|
ImGuiUtil.OptionCheckbox(ref Mutable.PrettierTimestamps, Language.Options_PrettierTimestamps_Name, Language.Options_PrettierTimestamps_Description);
|
||||||
|
|
||||||
if (Mutable.PrettierTimestamps)
|
if (Mutable.PrettierTimestamps)
|
||||||
{
|
{
|
||||||
ImGui.TreePush();
|
using var _ = ImRaii.PushIndent();
|
||||||
ImGuiUtil.OptionCheckbox(ref Mutable.MoreCompactPretty, Language.Options_MoreCompactPretty_Name, Language.Options_MoreCompactPretty_Description);
|
ImGuiUtil.OptionCheckbox(ref Mutable.MoreCompactPretty, Language.Options_MoreCompactPretty_Name, Language.Options_MoreCompactPretty_Description);
|
||||||
ImGuiUtil.OptionCheckbox(ref Mutable.HideSameTimestamps, Language.Options_HideSameTimestamps_Name, Language.Options_HideSameTimestamps_Description);
|
ImGuiUtil.OptionCheckbox(ref Mutable.HideSameTimestamps, Language.Options_HideSameTimestamps_Name, Language.Options_HideSameTimestamps_Description);
|
||||||
ImGui.TreePop();
|
|
||||||
}
|
}
|
||||||
ImGui.Spacing();
|
ImGui.Spacing();
|
||||||
|
|
||||||
|
|||||||
@@ -108,6 +108,9 @@ internal sealed class Tabs : ISettingsTab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Mutable.HideWhenInactive)
|
||||||
|
ImGui.Checkbox(Language.Options_Tabs_InactivityBehaviour, ref tab.UnhideOnActivity);
|
||||||
|
|
||||||
ImGui.Checkbox(Language.Options_Tabs_NoInput, ref tab.InputDisabled);
|
ImGui.Checkbox(Language.Options_Tabs_NoInput, ref tab.InputDisabled);
|
||||||
if (!tab.InputDisabled)
|
if (!tab.InputDisabled)
|
||||||
{
|
{
|
||||||
@@ -124,81 +127,8 @@ internal sealed class Tabs : ISettingsTab
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using (var channelNode = ImRaii.TreeNode(Language.Options_Tabs_Channels))
|
ImGuiUtil.ChannelSelector(Language.Options_Tabs_Channels, tab.ChatCodes);
|
||||||
{
|
ImGuiUtil.ExtraChatSelector(Language.Options_Tabs_ExtraChatChannels, ref tab.ExtraChatAll, tab.ExtraChatChannels);
|
||||||
if (channelNode)
|
|
||||||
{
|
|
||||||
foreach (var (header, types) in ChatTypeExt.SortOrder)
|
|
||||||
{
|
|
||||||
using var headerNode = ImRaii.TreeNode(header + $"##{i}");
|
|
||||||
if (!headerNode.Success)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
foreach (var type in types)
|
|
||||||
{
|
|
||||||
if (type.IsGm())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
var enabled = tab.ChatCodes.ContainsKey(type);
|
|
||||||
if (ImGui.Checkbox($"##{type.Name()}-{i}", ref enabled))
|
|
||||||
{
|
|
||||||
if (enabled)
|
|
||||||
tab.ChatCodes[type] = ChatSourceExt.All;
|
|
||||||
else
|
|
||||||
tab.ChatCodes.Remove(type);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui.SameLine();
|
|
||||||
|
|
||||||
if (!type.HasSource())
|
|
||||||
{
|
|
||||||
ImGui.TextUnformatted(type.Name());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
using var typeNode = ImRaii.TreeNode($"{type.Name()}##{i}");
|
|
||||||
if (!typeNode.Success)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
tab.ChatCodes.TryGetValue(type, out var sourcesEnum);
|
|
||||||
var sources = (uint) sourcesEnum;
|
|
||||||
|
|
||||||
foreach (var source in Enum.GetValues<ChatSource>())
|
|
||||||
if (ImGui.CheckboxFlags(source.Name(), ref sources, (uint) source))
|
|
||||||
tab.ChatCodes[type] = (ChatSource) sources;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (Plugin.ExtraChat.ChannelNames.Count <= 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
using var extraTree = ImRaii.TreeNode(Language.Options_Tabs_ExtraChatChannels);
|
|
||||||
if (!extraTree.Success)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ImGui.Checkbox(Language.Options_Tabs_ExtraChatAll, ref tab.ExtraChatAll);
|
|
||||||
ImGui.Separator();
|
|
||||||
|
|
||||||
if (tab.ExtraChatAll)
|
|
||||||
ImGui.BeginDisabled();
|
|
||||||
|
|
||||||
foreach (var (id, name) in Plugin.ExtraChat.ChannelNames)
|
|
||||||
{
|
|
||||||
var enabled = tab.ExtraChatChannels.Contains(id);
|
|
||||||
if (!ImGui.Checkbox($"{name}##ec-{id}", ref enabled))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (enabled)
|
|
||||||
tab.ExtraChatChannels.Add(id);
|
|
||||||
else
|
|
||||||
tab.ExtraChatChannels.Remove(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tab.ExtraChatAll)
|
|
||||||
ImGui.EndDisabled();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toRemove > -1)
|
if (toRemove > -1)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using ChatTwo.Code;
|
||||||
using ChatTwo.GameFunctions.Types;
|
using ChatTwo.GameFunctions.Types;
|
||||||
using ChatTwo.Resources;
|
using ChatTwo.Resources;
|
||||||
using Dalamud.Game.ClientState.Keys;
|
using Dalamud.Game.ClientState.Keys;
|
||||||
@@ -549,6 +550,80 @@ internal static class ImGuiUtil
|
|||||||
return new EndUnconditionally(ImGui.PopTextWrapPos, true);
|
return new EndUnconditionally(ImGui.PopTextWrapPos, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void ChannelSelector(string headerText, Dictionary<ChatType, ChatSource> chatCodes)
|
||||||
|
{
|
||||||
|
using var channelNode = ImRaii.TreeNode(headerText);
|
||||||
|
if (!channelNode)
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var (header, types) in ChatTypeExt.SortOrder)
|
||||||
|
{
|
||||||
|
using var headerNode = ImRaii.TreeNode(header);
|
||||||
|
if (!headerNode.Success)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
if (type.IsGm())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
var enabled = chatCodes.ContainsKey(type);
|
||||||
|
if (ImGui.Checkbox($"##{type.Name()}", ref enabled))
|
||||||
|
{
|
||||||
|
if (enabled)
|
||||||
|
chatCodes[type] = ChatSourceExt.All;
|
||||||
|
else
|
||||||
|
chatCodes.Remove(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui.SameLine();
|
||||||
|
|
||||||
|
if (!type.HasSource())
|
||||||
|
{
|
||||||
|
ImGui.TextUnformatted(type.Name());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
using var typeNode = ImRaii.TreeNode($"{type.Name()}");
|
||||||
|
if (!typeNode.Success)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
chatCodes.TryGetValue(type, out var sourcesEnum);
|
||||||
|
var sources = (uint)sourcesEnum;
|
||||||
|
|
||||||
|
foreach (var source in Enum.GetValues<ChatSource>())
|
||||||
|
if (ImGui.CheckboxFlags(source.Name(), ref sources, (uint)source))
|
||||||
|
chatCodes[type] = (ChatSource)sources;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void ExtraChatSelector(string headerText, ref bool all, HashSet<Guid> extraChatChannels)
|
||||||
|
{
|
||||||
|
if (Plugin.ExtraChat.ChannelNames.Count <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
using var extraTree = ImRaii.TreeNode(headerText);
|
||||||
|
if (!extraTree.Success)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGui.Checkbox(Language.Options_Tabs_ExtraChatAll, ref all);
|
||||||
|
ImGui.Separator();
|
||||||
|
|
||||||
|
using var _ = ImRaii.Disabled(all);
|
||||||
|
foreach (var (id, name) in Plugin.ExtraChat.ChannelNames)
|
||||||
|
{
|
||||||
|
var enabled = extraChatChannels.Contains(id);
|
||||||
|
if (!ImGui.Checkbox($"{name}##ec-{id}", ref enabled))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (enabled)
|
||||||
|
extraChatChannels.Add(id);
|
||||||
|
else
|
||||||
|
extraChatChannels.Remove(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Used to avoid pops if condition is false for Push.
|
// Used to avoid pops if condition is false for Push.
|
||||||
private static void Nop() { }
|
private static void Nop() { }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,14 @@ using ChatTwo.Resources;
|
|||||||
namespace ChatTwo.Util;
|
namespace ChatTwo.Util;
|
||||||
|
|
||||||
internal static class TabsUtil {
|
internal static class TabsUtil {
|
||||||
|
internal static Dictionary<ChatType, ChatSource> AllChannels()
|
||||||
|
{
|
||||||
|
var channels = new Dictionary<ChatType, ChatSource>();
|
||||||
|
foreach (var chatType in Enum.GetValues<ChatType>())
|
||||||
|
channels[chatType] = ChatSourceExt.All;
|
||||||
|
return channels;
|
||||||
|
}
|
||||||
|
|
||||||
internal static Tab VanillaGeneral => new() {
|
internal static Tab VanillaGeneral => new() {
|
||||||
Name = Language.Tabs_Presets_General,
|
Name = Language.Tabs_Presets_General,
|
||||||
ChatCodes = new Dictionary<ChatType, ChatSource> {
|
ChatCodes = new Dictionary<ChatType, ChatSource> {
|
||||||
|
|||||||
Reference in New Issue
Block a user