feat: add autohide after inactivity
After not receiving a message for X seconds (configurable) in the current tab or any tab with unread mode enabled, the chat will be hidden. Focus can be returned with return or slash as usual. Having input focus or hovering the mouse over the chat window "bumps" it every frame. Also fixes a bug that prevented focus from being restored to tabs with input disabled. The chat window will be brought back but the activated event won't be fully processed. Co-authored-by: Auri <me@aurieh.me>
This commit is contained in:
@@ -85,6 +85,9 @@ public sealed class ChatLogWindow : Window
|
||||
private const uint ChatCloseSfx = 3u;
|
||||
private bool PlayedClosingSound = true;
|
||||
|
||||
private long FrameTime; // set every frame
|
||||
private long LastActivityTime = Environment.TickCount64;
|
||||
|
||||
private readonly ExcelSheet<World> WorldSheet;
|
||||
private readonly ExcelSheet<LogFilter> LogFilterSheet;
|
||||
private readonly ExcelSheet<TextCommand> TextCommandSheet;
|
||||
@@ -148,6 +151,18 @@ public sealed class ChatLogWindow : Window
|
||||
private void Activated(ChatActivatedArgs args)
|
||||
{
|
||||
Activate = true;
|
||||
PlayedClosingSound = false;
|
||||
if (Plugin.Config.PlaySounds)
|
||||
UIModule.PlaySound(ChatOpenSfx);
|
||||
|
||||
// Don't set the channel or text content when activating a disabled tab.
|
||||
if (CurrentTab?.InputDisabled == true)
|
||||
{
|
||||
// The closing sound would've been immediately played in this case.
|
||||
PlayedClosingSound = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.AddIfNotPresent != null && !Chat.Contains(args.AddIfNotPresent))
|
||||
Chat += args.AddIfNotPresent;
|
||||
|
||||
@@ -203,10 +218,6 @@ public sealed class ChatLogWindow : Window
|
||||
|
||||
if (info.Text != null && Chat.Length == 0)
|
||||
Chat = info.Text;
|
||||
|
||||
PlayedClosingSound = false;
|
||||
if (Plugin.Config.PlaySounds)
|
||||
UIModule.PlaySound(ChatOpenSfx);
|
||||
}
|
||||
|
||||
private bool IsValidCommand(string command)
|
||||
@@ -471,7 +482,23 @@ public sealed class ChatLogWindow : Window
|
||||
|
||||
public override bool DrawConditions()
|
||||
{
|
||||
return !IsHidden;
|
||||
FrameTime = Environment.TickCount64;
|
||||
if (IsHidden)
|
||||
return false;
|
||||
if (!Plugin.Config.HideWhenInactive || Activate)
|
||||
{
|
||||
LastActivityTime = FrameTime;
|
||||
return true;
|
||||
}
|
||||
|
||||
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)
|
||||
.Max();
|
||||
lastActivityTime = Math.Max(lastActivityTime, LastActivityTime);
|
||||
return FrameTime - lastActivityTime <= 1000 * Plugin.Config.InactivityHideTimeout;
|
||||
}
|
||||
|
||||
public override void PreDraw()
|
||||
@@ -485,6 +512,12 @@ public sealed class ChatLogWindow : Window
|
||||
|
||||
public override void PostDraw()
|
||||
{
|
||||
// Set Activate to false after draw to avoid repeatedly trying to focus
|
||||
// the text input in a tab with input disabled. The usual way that
|
||||
// Activate gets disabled is via the text input callback, but that
|
||||
// doesn't get called if the input is disabled.
|
||||
if (CurrentTab?.InputDisabled == true)
|
||||
Activate = false;
|
||||
if (Plugin.Config is { OverrideStyle: true, ChosenStyle: not null })
|
||||
StyleModel.GetConfiguredStyles()?.FirstOrDefault(style => style.Name == Plugin.Config.ChosenStyle)?.Pop();
|
||||
}
|
||||
@@ -740,7 +773,10 @@ public sealed class ChatLogWindow : Window
|
||||
}
|
||||
|
||||
if (ImGui.IsItemActive())
|
||||
{
|
||||
HandleKeybinds(true);
|
||||
LastActivityTime = FrameTime;
|
||||
}
|
||||
|
||||
// Only trigger unfocused if we are currently not calling the auto complete
|
||||
if (!Activate && !ImGui.IsItemActive() && AutoCompleteInfo == null)
|
||||
@@ -785,6 +821,9 @@ public sealed class ChatLogWindow : Window
|
||||
UserHide();
|
||||
}
|
||||
|
||||
if (ImGui.IsWindowHovered(ImGuiHoveredFlags.ChildWindows))
|
||||
LastActivityTime = FrameTime;
|
||||
|
||||
if (!showNovice)
|
||||
return;
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
using ChatTwo.Resources;
|
||||
using ChatTwo.Util;
|
||||
using Dalamud.Interface.Style;
|
||||
using Dalamud.Interface.Utility.Raii;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace ChatTwo.Ui.SettingsTabs;
|
||||
@@ -39,6 +37,19 @@ internal sealed class Display : ISettingsTab
|
||||
ImGuiUtil.OptionCheckbox(ref Mutable.HideInBattle, Language.Options_HideInBattle_Name, Language.Options_HideInBattle_Description);
|
||||
ImGui.Spacing();
|
||||
|
||||
ImGuiUtil.OptionCheckbox(ref Mutable.HideWhenInactive, Language.Options_HideWhenInactive_Name, Language.Options_HideWhenInactive_Description);
|
||||
ImGui.Spacing();
|
||||
|
||||
if (Mutable.HideWhenInactive)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
ImGuiUtil.OptionCheckbox(ref Mutable.PrettierTimestamps, Language.Options_PrettierTimestamps_Name, Language.Options_PrettierTimestamps_Description);
|
||||
|
||||
if (Mutable.PrettierTimestamps)
|
||||
|
||||
Reference in New Issue
Block a user