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:
@@ -87,7 +87,7 @@ public sealed class ChatLogWindow : Window
|
||||
private bool PlayedClosingSound = true;
|
||||
|
||||
private long FrameTime; // set every frame
|
||||
private long LastActivityTime = Environment.TickCount64;
|
||||
internal long LastActivityTime = Environment.TickCount64;
|
||||
|
||||
private readonly ExcelSheet<World> WorldSheet;
|
||||
private readonly ExcelSheet<LogFilter> LogFilterSheet;
|
||||
@@ -348,7 +348,10 @@ public sealed class ChatLogWindow : Window
|
||||
return height;
|
||||
}
|
||||
|
||||
internal void ChangeTab(int index) => WantedTab = index;
|
||||
internal void ChangeTab(int index) {
|
||||
WantedTab = index;
|
||||
LastActivityTime = FrameTime;
|
||||
}
|
||||
|
||||
internal void ChangeTabDelta(int offset)
|
||||
{
|
||||
@@ -373,7 +376,7 @@ public sealed class ChatLogWindow : Window
|
||||
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 CutsceneActive => Plugin.Condition[ConditionFlag.OccupiedInCutSceneEvent] || Plugin.Condition[ConditionFlag.WatchingCutscene78];
|
||||
|
||||
@@ -448,7 +451,8 @@ public sealed class ChatLogWindow : Window
|
||||
FrameTime = Environment.TickCount64;
|
||||
if (IsHidden)
|
||||
return false;
|
||||
if (!Plugin.Config.HideWhenInactive || Activate)
|
||||
|
||||
if (!Plugin.Config.HideWhenInactive || (!Plugin.Config.InactivityHideActiveDuringBattle && InBattle) || Activate)
|
||||
{
|
||||
LastActivityTime = FrameTime;
|
||||
return true;
|
||||
@@ -456,11 +460,10 @@ public sealed class ChatLogWindow : Window
|
||||
|
||||
var currentTab = CurrentTab; // local to avoid calling the getter repeatedly
|
||||
var lastActivityTime = Plugin.Config.Tabs
|
||||
.Where(tab => tab.UnreadMode is not UnreadMode.None || tab == currentTab)
|
||||
.Select(tab => tab.LastMessageTime)
|
||||
.DefaultIfEmpty(0)
|
||||
.Where(tab => !tab.PopOut && (tab.UnhideOnActivity || tab == currentTab))
|
||||
.Select(tab => tab.LastActivity)
|
||||
.Append(LastActivityTime)
|
||||
.Max();
|
||||
lastActivityTime = Math.Max(lastActivityTime, LastActivityTime);
|
||||
return FrameTime - lastActivityTime <= 1000 * Plugin.Config.InactivityHideTimeout;
|
||||
}
|
||||
|
||||
|
||||
+20
-1
@@ -12,6 +12,9 @@ internal class Popout : Window
|
||||
private readonly Tab Tab;
|
||||
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")
|
||||
{
|
||||
ChatLogWindow = chatLogWindow;
|
||||
@@ -34,7 +37,20 @@ internal class Popout : Window
|
||||
|
||||
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()
|
||||
@@ -65,6 +81,9 @@ internal class Popout : Window
|
||||
|
||||
var handler = ChatLogWindow.HandlerLender.Borrow();
|
||||
ChatLogWindow.DrawMessageLog(Tab, handler, ImGui.GetContentRegionAvail().Y, false);
|
||||
|
||||
if (ImGui.IsWindowHovered(ImGuiHoveredFlags.ChildWindows))
|
||||
LastActivityTime = FrameTime;
|
||||
}
|
||||
|
||||
public override void PostDraw()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using ChatTwo.Resources;
|
||||
using ChatTwo.Util;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using ImGuiNET;
|
||||
|
||||
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);
|
||||
ImGui.Spacing();
|
||||
|
||||
ImGui.Separator();
|
||||
ImGui.Spacing();
|
||||
|
||||
ImGuiUtil.OptionCheckbox(ref Mutable.HideWhenInactive, Language.Options_HideWhenInactive_Name, Language.Options_HideWhenInactive_Description);
|
||||
ImGui.Spacing();
|
||||
|
||||
if (Mutable.HideWhenInactive)
|
||||
{
|
||||
using var _ = ImRaii.PushIndent();
|
||||
ImGuiUtil.InputIntVertical(Language.Options_InactivityHideTimeout_Name,
|
||||
Language.Options_InactivityHideTimeout_Description, ref Mutable.InactivityHideTimeout, 1, 10);
|
||||
// Enforce a minimum of 2 seconds to avoid people soft locking
|
||||
// themselves.
|
||||
Mutable.InactivityHideTimeout = Math.Max(2, Mutable.InactivityHideTimeout);
|
||||
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);
|
||||
|
||||
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.HideSameTimestamps, Language.Options_HideSameTimestamps_Name, Language.Options_HideSameTimestamps_Description);
|
||||
ImGui.TreePop();
|
||||
}
|
||||
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);
|
||||
if (!tab.InputDisabled)
|
||||
{
|
||||
@@ -124,81 +127,8 @@ internal sealed class Tabs : ISettingsTab
|
||||
}
|
||||
}
|
||||
|
||||
using (var channelNode = ImRaii.TreeNode(Language.Options_Tabs_Channels))
|
||||
{
|
||||
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();
|
||||
ImGuiUtil.ChannelSelector(Language.Options_Tabs_Channels, tab.ChatCodes);
|
||||
ImGuiUtil.ExtraChatSelector(Language.Options_Tabs_ExtraChatChannels, ref tab.ExtraChatAll, tab.ExtraChatChannels);
|
||||
}
|
||||
|
||||
if (toRemove > -1)
|
||||
|
||||
Reference in New Issue
Block a user