added more customization to the notifs, settings improvemnts, left and right notifs, animations for sliding in and out

This commit is contained in:
choco
2025-10-12 18:00:49 +02:00
parent c0b8e15380
commit a8a01b3034
5 changed files with 335 additions and 161 deletions

View File

@@ -26,6 +26,8 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
private readonly List<LightlessNotification> _notifications = new();
private readonly object _notificationLock = new();
private readonly LightlessConfigService _configService;
private readonly Dictionary<string, float> _notificationYOffsets = new();
private readonly Dictionary<string, float> _notificationTargetYOffsets = new();
public LightlessNotificationUI(ILogger<LightlessNotificationUI> logger, LightlessMediator mediator, PerformanceCollectorService performanceCollector, LightlessConfigService configService)
: base(logger, mediator, "Lightless Notifications##LightlessNotifications", performanceCollector)
@@ -49,12 +51,11 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
Mediator.Subscribe<LightlessNotificationMessage>(this, HandleNotificationMessage);
Mediator.Subscribe<LightlessNotificationDismissMessage>(this, HandleNotificationDismissMessage);
Mediator.Subscribe<ClearAllNotificationsMessage>(this, HandleClearAllNotifications);
}
private void HandleNotificationMessage(LightlessNotificationMessage message) =>
AddNotification(message.Notification);
private void HandleNotificationDismissMessage(LightlessNotificationDismissMessage message) =>
RemoveNotification(message.NotificationId);
private void HandleNotificationMessage(LightlessNotificationMessage message) => AddNotification(message.Notification);
private void HandleNotificationDismissMessage(LightlessNotificationDismissMessage message) => RemoveNotification(message.NotificationId);
private void HandleClearAllNotifications(ClearAllNotificationsMessage message) => ClearAllNotifications();
public void AddNotification(LightlessNotification notification)
{
@@ -96,20 +97,34 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
}
}
public void ClearAllNotifications()
{
lock (_notificationLock)
{
foreach (var notification in _notifications)
{
StartOutAnimation(notification);
}
}
}
private void StartOutAnimation(LightlessNotification notification)
{
notification.IsAnimatingOut = true;
notification.IsAnimatingIn = false;
}
private bool ShouldRemoveNotification(LightlessNotification notification) =>
notification.IsAnimatingOut && notification.AnimationProgress <= 0.01f;
protected override void DrawInternal()
{
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
lock (_notificationLock)
{
UpdateNotifications();
if (_notifications.Count == 0)
{
ImGui.PopStyleVar();
@@ -118,33 +133,49 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
}
var viewport = ImGui.GetMainViewport();
// Set window to full viewport height
var width = _configService.Current.NotificationWidth;
Size = new Vector2(width, viewport.WorkSize.Y);
SizeCondition = ImGuiCond.Always;
Position = CalculateWindowPosition(viewport);
PositionCondition = ImGuiCond.Always;
DrawAllNotifications();
}
ImGui.PopStyleVar();
}
private Vector2 CalculateWindowPosition(ImGuiViewportPtr viewport)
{
var x = viewport.WorkPos.X + viewport.WorkSize.X -
_configService.Current.NotificationWidth -
_configService.Current.NotificationOffsetX -
WindowPaddingOffset;
var y = viewport.WorkPos.Y + _configService.Current.NotificationOffsetY;
return new Vector2(x, y);
var corner = _configService.Current.NotificationCorner;
var offsetX = _configService.Current.NotificationOffsetX;
var width = _configService.Current.NotificationWidth;
float posX = corner == NotificationCorner.Left
? viewport.WorkPos.X + offsetX - WindowPaddingOffset
: viewport.WorkPos.X + viewport.WorkSize.X - width - offsetX - WindowPaddingOffset;
return new Vector2(posX, viewport.WorkPos.Y);
}
private void DrawAllNotifications()
{
var offsetY = _configService.Current.NotificationOffsetY;
var startY = ImGui.GetCursorPosY() + offsetY;
for (int i = 0; i < _notifications.Count; i++)
{
DrawNotification(_notifications[i], i);
var notification = _notifications[i];
if (i < _notifications.Count - 1)
if (_notificationYOffsets.TryGetValue(notification.Id, out var yOffset))
{
ImGui.Dummy(new Vector2(0, _configService.Current.NotificationSpacing));
ImGui.SetCursorPosY(startY + yOffset);
}
DrawNotification(notification, i);
}
}
@@ -174,18 +205,65 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
private void UpdateAnimationsAndRemoveExpired(float deltaTime)
{
UpdateTargetYPositions();
for (int i = _notifications.Count - 1; i >= 0; i--)
{
var notification = _notifications[i];
UpdateNotificationAnimation(notification, deltaTime);
UpdateNotificationYOffset(notification, deltaTime);
if (ShouldRemoveNotification(notification))
{
_notifications.RemoveAt(i);
_notificationYOffsets.Remove(notification.Id);
_notificationTargetYOffsets.Remove(notification.Id);
}
}
}
private void UpdateTargetYPositions()
{
float currentY = 0f;
for (int i = 0; i < _notifications.Count; i++)
{
var notification = _notifications[i];
if (!_notificationTargetYOffsets.ContainsKey(notification.Id))
{
_notificationTargetYOffsets[notification.Id] = currentY;
_notificationYOffsets[notification.Id] = currentY;
}
else
{
_notificationTargetYOffsets[notification.Id] = currentY;
}
currentY += CalculateNotificationHeight(notification) + _configService.Current.NotificationSpacing;
}
}
private void UpdateNotificationYOffset(LightlessNotification notification, float deltaTime)
{
if (!_notificationYOffsets.ContainsKey(notification.Id) || !_notificationTargetYOffsets.ContainsKey(notification.Id))
return;
var current = _notificationYOffsets[notification.Id];
var target = _notificationTargetYOffsets[notification.Id];
var diff = target - current;
if (Math.Abs(diff) < 0.5f)
{
_notificationYOffsets[notification.Id] = target;
}
else
{
var speed = _configService.Current.NotificationSlideSpeed;
_notificationYOffsets[notification.Id] = current + (diff * deltaTime * speed);
}
}
private void UpdateNotificationAnimation(LightlessNotification notification, float deltaTime)
{
if (notification.IsAnimatingIn && notification.AnimationProgress < 1f)
@@ -209,20 +287,24 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
}
}
private bool ShouldRemoveNotification(LightlessNotification notification) =>
notification.IsAnimatingOut && notification.AnimationProgress <= 0.01f;
private Vector2 CalculateSlideOffset(float alpha)
{
var distance = (1f - alpha) * SlideAnimationDistance;
var corner = _configService.Current.NotificationCorner;
return corner == NotificationCorner.Left ? new Vector2(-distance, 0) : new Vector2(distance, 0);
}
private void DrawNotification(LightlessNotification notification, int index)
{
var alpha = notification.AnimationProgress;
if (alpha <= 0f) return;
var slideOffset = (1f - alpha) * SlideAnimationDistance;
var slideOffset = CalculateSlideOffset(alpha);
var originalCursorPos = ImGui.GetCursorPos();
ImGui.SetCursorPosX(originalCursorPos.X + slideOffset);
ImGui.SetCursorPos(originalCursorPos + slideOffset);
var notificationHeight = CalculateNotificationHeight(notification);
var notificationWidth = _configService.Current.NotificationWidth - slideOffset;
var notificationWidth = _configService.Current.NotificationWidth - Math.Abs(slideOffset.X);
ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
@@ -308,15 +390,28 @@ public class LightlessNotificationUI : WindowMediatorSubscriberBase
private void DrawAccentBar(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, Vector4 accentColor)
{
var accentWidth = _configService.Current.NotificationAccentBarWidth;
if (accentWidth > 0f)
if (accentWidth <= 0f) return;
var corner = _configService.Current.NotificationCorner;
Vector2 accentStart, accentEnd;
if (corner == NotificationCorner.Left)
{
drawList.AddRectFilled(
windowPos,
windowPos + new Vector2(accentWidth, windowSize.Y),
ImGui.ColorConvertFloat4ToU32(accentColor),
3f
);
accentStart = windowPos + new Vector2(windowSize.X - accentWidth, 0);
accentEnd = windowPos + windowSize;
}
else
{
accentStart = windowPos;
accentEnd = windowPos + new Vector2(accentWidth, windowSize.Y);
}
drawList.AddRectFilled(
accentStart,
accentEnd,
ImGui.ColorConvertFloat4ToU32(accentColor),
3f
);
}
private void DrawDurationProgressBar(LightlessNotification notification, float alpha, Vector2 windowPos, Vector2 windowSize, ImDrawListPtr drawList)

View File

@@ -3493,69 +3493,162 @@ public class SettingsUi : WindowMediatorSubscriberBase
if (useLightlessNotifications)
{
// Lightless notification locations
ImGui.Indent();
var lightlessLocations = GetLightlessNotificationLocations();
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Info Notifications:");
ImGui.SameLine();
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
_uiShared.DrawCombo("###enhanced_info", lightlessLocations, GetNotificationLocationLabel, (location) =>
{
_configService.Current.LightlessInfoNotification = location;
_configService.Save();
}, _configService.Current.LightlessInfoNotification);
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Warning Notifications:");
ImGui.SameLine();
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
_uiShared.DrawCombo("###enhanced_warning", lightlessLocations, GetNotificationLocationLabel,
(location) =>
{
_configService.Current.LightlessWarningNotification = location;
_configService.Save();
}, _configService.Current.LightlessWarningNotification);
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Error Notifications:");
ImGui.SameLine();
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
_uiShared.DrawCombo("###enhanced_error", lightlessLocations, GetNotificationLocationLabel, (location) =>
{
_configService.Current.LightlessErrorNotification = location;
_configService.Save();
}, _configService.Current.LightlessErrorNotification);
ImGuiHelpers.ScaledDummy(3);
_uiShared.DrawHelpText("Special notification types:");
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Pair Request Notifications:");
ImGui.SameLine();
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
_uiShared.DrawCombo("###enhanced_pairrequest", lightlessLocations, GetNotificationLocationLabel,
(location) =>
{
_configService.Current.LightlessPairRequestNotification = location;
_configService.Save();
}, _configService.Current.LightlessPairRequestNotification);
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Download Progress Notifications:");
ImGui.SameLine();
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
var downloadLocations = GetDownloadNotificationLocations();
_uiShared.DrawCombo("###enhanced_download", downloadLocations, GetNotificationLocationLabel,
(location) =>
if (ImGui.BeginTable("##NotificationLocationTable", 3, ImGuiTableFlags.Borders | ImGuiTableFlags.RowBg | ImGuiTableFlags.SizingFixedFit))
{
ImGui.TableSetupColumn("Notification Type", ImGuiTableColumnFlags.WidthFixed, 200f * ImGuiHelpers.GlobalScale);
ImGui.TableSetupColumn("Location", ImGuiTableColumnFlags.WidthStretch);
ImGui.TableSetupColumn("Actions", ImGuiTableColumnFlags.WidthFixed, 40f * ImGuiHelpers.GlobalScale);
ImGui.TableHeadersRow();
ImGui.TableNextRow();
ImGui.TableSetColumnIndex(0);
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Info Notifications");
ImGui.TableSetColumnIndex(1);
ImGui.SetNextItemWidth(-1);
_uiShared.DrawCombo("###enhanced_info", lightlessLocations, GetNotificationLocationLabel, (location) =>
{
_configService.Current.LightlessDownloadNotification = location;
_configService.Current.LightlessInfoNotification = location;
_configService.Save();
}, _configService.Current.LightlessDownloadNotification);
}, _configService.Current.LightlessInfoNotification);
ImGui.TableSetColumnIndex(2);
var availableWidth = ImGui.GetContentRegionAvail().X;
using (ImRaii.PushFont(UiBuilder.IconFont))
{
if (ImGui.Button($"{FontAwesomeIcon.Play.ToIconString()}##test_info", new Vector2(availableWidth, 0)))
{
Mediator.Publish(new NotificationMessage("Test Info",
"This is a test info notification to let you know Chocola is cute :3", NotificationType.Info));
}
}
UiSharedService.AttachToolTip("Test info notification");
ImGui.TableNextRow();
ImGui.TableSetColumnIndex(0);
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Warning Notifications");
ImGui.TableSetColumnIndex(1);
ImGui.SetNextItemWidth(-1);
_uiShared.DrawCombo("###enhanced_warning", lightlessLocations, GetNotificationLocationLabel,
(location) =>
{
_configService.Current.LightlessWarningNotification = location;
_configService.Save();
}, _configService.Current.LightlessWarningNotification);
ImGui.TableSetColumnIndex(2);
availableWidth = ImGui.GetContentRegionAvail().X;
using (ImRaii.PushFont(UiBuilder.IconFont))
{
if (ImGui.Button($"{FontAwesomeIcon.Play.ToIconString()}##test_warning", new Vector2(availableWidth, 0)))
{
Mediator.Publish(new NotificationMessage("Test Warning", "This is a test warning notification!",
NotificationType.Warning));
}
}
UiSharedService.AttachToolTip("Test warning notification");
ImGui.Unindent();
ImGui.TableNextRow();
ImGui.TableSetColumnIndex(0);
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Error Notifications");
ImGui.TableSetColumnIndex(1);
ImGui.SetNextItemWidth(-1);
_uiShared.DrawCombo("###enhanced_error", lightlessLocations, GetNotificationLocationLabel, (location) =>
{
_configService.Current.LightlessErrorNotification = location;
_configService.Save();
}, _configService.Current.LightlessErrorNotification);
ImGui.TableSetColumnIndex(2);
availableWidth = ImGui.GetContentRegionAvail().X;
using (ImRaii.PushFont(UiBuilder.IconFont))
{
if (ImGui.Button($"{FontAwesomeIcon.Play.ToIconString()}##test_error", new Vector2(availableWidth, 0)))
{
Mediator.Publish(new NotificationMessage("Test Error", "This is a test error notification!",
NotificationType.Error));
}
}
UiSharedService.AttachToolTip("Test error notification");
ImGui.TableNextRow();
ImGui.TableSetColumnIndex(0);
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Pair Request Notifications");
ImGui.TableSetColumnIndex(1);
ImGui.SetNextItemWidth(-1);
_uiShared.DrawCombo("###enhanced_pairrequest", lightlessLocations, GetNotificationLocationLabel,
(location) =>
{
_configService.Current.LightlessPairRequestNotification = location;
_configService.Save();
}, _configService.Current.LightlessPairRequestNotification);
ImGui.TableSetColumnIndex(2);
availableWidth = ImGui.GetContentRegionAvail().X;
using (ImRaii.PushFont(UiBuilder.IconFont))
{
if (ImGui.Button($"{FontAwesomeIcon.Play.ToIconString()}##test_pair", new Vector2(availableWidth, 0)))
{
_lightlessNotificationService.ShowPairRequestNotification(
"Test User",
"test-uid-123",
() =>
{
Mediator.Publish(new NotificationMessage("Accepted", "You accepted the test pair request.",
NotificationType.Info));
},
() =>
{
Mediator.Publish(new NotificationMessage("Declined", "You declined the test pair request.",
NotificationType.Info));
}
);
}
}
UiSharedService.AttachToolTip("Test pair request notification");
ImGui.TableNextRow();
ImGui.TableSetColumnIndex(0);
ImGui.AlignTextToFramePadding();
ImGui.TextUnformatted("Download Progress Notifications");
ImGui.TableSetColumnIndex(1);
ImGui.SetNextItemWidth(-1);
_uiShared.DrawCombo("###enhanced_download", downloadLocations, GetNotificationLocationLabel,
(location) =>
{
_configService.Current.LightlessDownloadNotification = location;
_configService.Save();
}, _configService.Current.LightlessDownloadNotification);
ImGui.TableSetColumnIndex(2);
availableWidth = ImGui.GetContentRegionAvail().X;
using (ImRaii.PushFont(UiBuilder.IconFont))
{
if (ImGui.Button($"{FontAwesomeIcon.Play.ToIconString()}##test_download", new Vector2(availableWidth, 0)))
{
_lightlessNotificationService.ShowPairDownloadNotification(
new List<(string playerName, float progress, string status)>
{
("Player One", 0.35f, "downloading"),
("Player Two", 0.75f, "downloading"),
("Player Three", 1.0f, "downloading")
},
queueWaiting: 2
);
}
}
UiSharedService.AttachToolTip("Test download progress notification");
ImGui.EndTable();
}
ImGuiHelpers.ScaledDummy(5);
if (_uiShared.IconTextButton(FontAwesomeIcon.Trash, "Clear All Notifications"))
{
Mediator.Publish(new ClearAllNotificationsMessage());
}
_uiShared.DrawHelpText("Dismiss all active notifications immediately.");
}
else
{
@@ -3602,73 +3695,6 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Separator();
if (useLightlessNotifications)
{
if (_uiShared.MediumTreeNode("Test Notifications", UIColors.Get("LightlessPurple")))
{
ImGui.Indent();
// Test notification buttons
if (_uiShared.IconTextButton(FontAwesomeIcon.Bell, "Test Info"))
{
Mediator.Publish(new NotificationMessage("Test Info",
"This is a test info notification to let you know Chocola is cute :3", NotificationType.Info));
}
ImGui.SameLine();
if (_uiShared.IconTextButton(FontAwesomeIcon.ExclamationTriangle, "Test Warning"))
{
Mediator.Publish(new NotificationMessage("Test Warning", "This is a test warning notification!",
NotificationType.Warning));
}
ImGui.SameLine();
if (_uiShared.IconTextButton(FontAwesomeIcon.ExclamationCircle, "Test Error"))
{
Mediator.Publish(new NotificationMessage("Test Error", "This is a test error notification!",
NotificationType.Error));
}
ImGuiHelpers.ScaledDummy(3);
if (_uiShared.IconTextButton(FontAwesomeIcon.UserPlus, "Test Pair Request"))
{
_lightlessNotificationService.ShowPairRequestNotification(
"Test User",
"test-uid-123",
() =>
{
Mediator.Publish(new NotificationMessage("Accepted", "You accepted the test pair request.",
NotificationType.Info));
},
() =>
{
Mediator.Publish(new NotificationMessage("Declined", "You declined the test pair request.",
NotificationType.Info));
}
);
}
ImGui.SameLine();
if (_uiShared.IconTextButton(FontAwesomeIcon.Download, "Test Download Progress"))
{
_lightlessNotificationService.ShowPairDownloadNotification(
new List<(string playerName, float progress, string status)>
{
("Player One", 0.35f, "downloading"),
("Player Two", 0.75f, "downloading"),
("Player Three", 1.0f, "downloading")
},
queueWaiting: 2
);
}
_uiShared.DrawHelpText("Preview how notifications will appear with your current settings.");
ImGui.Unindent();
_uiShared.ColoredSeparator(UIColors.Get("LightlessPurple"), 1.5f);
ImGui.TreePop();
}
ImGui.Separator();
if (_uiShared.MediumTreeNode("Basic Settings", UIColors.Get("LightlessPurple")))
{
int maxNotifications = _configService.Current.MaxSimultaneousNotifications;
@@ -3768,10 +3794,28 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Spacing();
ImGui.TextUnformatted("Position");
int offsetY = _configService.Current.NotificationOffsetY;
if (ImGui.SliderInt("Vertical Offset", ref offsetY, 0, 500))
var currentCorner = _configService.Current.NotificationCorner;
if (ImGui.BeginCombo("Notification Position", GetNotificationCornerLabel(currentCorner)))
{
_configService.Current.NotificationOffsetY = Math.Clamp(offsetY, 0, 500);
foreach (NotificationCorner corner in Enum.GetValues(typeof(NotificationCorner)))
{
bool isSelected = currentCorner == corner;
if (ImGui.Selectable(GetNotificationCornerLabel(corner), isSelected))
{
_configService.Current.NotificationCorner = corner;
_configService.Save();
}
if (isSelected)
ImGui.SetItemDefaultFocus();
}
ImGui.EndCombo();
}
_uiShared.DrawHelpText("Choose which corner of the screen notifications appear in.");
int offsetY = _configService.Current.NotificationOffsetY;
if (ImGui.SliderInt("Vertical Offset", ref offsetY, 0, 1000))
{
_configService.Current.NotificationOffsetY = Math.Clamp(offsetY, 0, 1000);
_configService.Save();
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
@@ -3781,7 +3825,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Right click to reset to default (50).");
_uiShared.DrawHelpText("Move notifications down from the top-right corner.");
_uiShared.DrawHelpText("Distance from the top edge of the screen.");
int offsetX = _configService.Current.NotificationOffsetX;
if (ImGui.SliderInt("Horizontal Offset", ref offsetX, 0, 500))
@@ -3802,9 +3846,9 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.TextUnformatted("Animation Settings");
float animSpeed = _configService.Current.NotificationAnimationSpeed;
if (ImGui.SliderFloat("Animation Speed", ref animSpeed, 1f, 30f, "%.1f"))
if (ImGui.SliderFloat("Animation Speed", ref animSpeed, 1f, 20f, "%.1f"))
{
_configService.Current.NotificationAnimationSpeed = Math.Clamp(animSpeed, 1f, 30f);
_configService.Current.NotificationAnimationSpeed = Math.Clamp(animSpeed, 1f, 20f);
_configService.Save();
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
@@ -3816,6 +3860,21 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.SetTooltip("Right click to reset to default (10).");
_uiShared.DrawHelpText("How fast notifications slide in/out. Higher = faster.");
float slideSpeed = _configService.Current.NotificationSlideSpeed;
if (ImGui.SliderFloat("Slide Speed", ref slideSpeed, 1f, 20f, "%.1f"))
{
_configService.Current.NotificationSlideSpeed = Math.Clamp(slideSpeed, 1f, 20f);
_configService.Save();
}
if (ImGui.IsItemClicked(ImGuiMouseButton.Right))
{
_configService.Current.NotificationSlideSpeed = 10f;
_configService.Save();
}
if (ImGui.IsItemHovered())
ImGui.SetTooltip("Right click to reset to default (10).");
_uiShared.DrawHelpText("How fast notifications slide into position when others disappear. Higher = faster.");
ImGui.Spacing();
ImGui.TextUnformatted("Visual Effects");
@@ -3999,6 +4058,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
ImGui.Separator();
// Location descriptions removed - information is now inline with each setting
}
}
@@ -4043,6 +4103,16 @@ public class SettingsUi : WindowMediatorSubscriberBase
};
}
private string GetNotificationCornerLabel(NotificationCorner corner)
{
return corner switch
{
NotificationCorner.Right => "Right",
NotificationCorner.Left => "Left",
_ => corner.ToString()
};
}
private void DrawSoundTable()
{
var soundEffects = new[]
@@ -4087,7 +4157,7 @@ public class SettingsUi : WindowMediatorSubscriberBase
var currentIndex = Array.FindIndex(soundEffects, s => s.Item1 == currentSoundId);
if (currentIndex == -1) currentIndex = 1;
ImGui.SetNextItemWidth(200 * ImGuiHelpers.GlobalScale);
ImGui.SetNextItemWidth(-1);
if (ImGui.Combo($"##sound_{typeIndex}", ref currentIndex,
soundEffects.Select(s => s.Item2).ToArray(), soundEffects.Length))
{