Optimize rendering of large number of pairs
This commit is contained in:
		| @@ -71,7 +71,7 @@ public class CompactUi : WindowMediatorSubscriberBase | |||||||
|         _groupPanel = new(this, uiShared, _pairManager, uidDisplayHandler, _serverManager); |         _groupPanel = new(this, uiShared, _pairManager, uidDisplayHandler, _serverManager); | ||||||
|         _selectGroupForPairUi = new(tagHandler, uidDisplayHandler); |         _selectGroupForPairUi = new(tagHandler, uidDisplayHandler); | ||||||
|         _selectPairsForGroupUi = new(tagHandler, uidDisplayHandler); |         _selectPairsForGroupUi = new(tagHandler, uidDisplayHandler); | ||||||
|         _pairGroupsUi = new(configService, tagHandler, apiController, _selectPairsForGroupUi); |         _pairGroupsUi = new(configService, tagHandler, uidDisplayHandler, apiController, _selectPairsForGroupUi); | ||||||
|  |  | ||||||
| #if DEBUG | #if DEBUG | ||||||
|         string dev = "Dev Build"; |         string dev = "Dev Build"; | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ public abstract class DrawPairBase | |||||||
|         _displayHandler = uIDDisplayHandler; |         _displayHandler = uIDDisplayHandler; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public string ImGuiID => _id; | ||||||
|     public string UID => _pair.UserData.UID; |     public string UID => _pair.UserData.UID; | ||||||
|  |  | ||||||
|     public void DrawPairedClient() |     public void DrawPairedClient() | ||||||
| @@ -30,6 +31,20 @@ public abstract class DrawPairBase | |||||||
|         var pauseIconSize = UiSharedService.GetIconButtonSize(FontAwesomeIcon.Play); |         var pauseIconSize = UiSharedService.GetIconButtonSize(FontAwesomeIcon.Play); | ||||||
|         var textSize = ImGui.CalcTextSize(_pair.UserData.AliasOrUID); |         var textSize = ImGui.CalcTextSize(_pair.UserData.AliasOrUID); | ||||||
|  |  | ||||||
|  |         var startPos = ImGui.GetCursorStartPos(); | ||||||
|  |  | ||||||
|  |         var framePadding = ImGui.GetStyle().FramePadding; | ||||||
|  |         var lineHeight = textSize.Y + framePadding.Y * 2; | ||||||
|  |  | ||||||
|  |         var off = startPos.Y; | ||||||
|  |         var height = UiSharedService.GetWindowContentRegionHeight(); | ||||||
|  |  | ||||||
|  |         if ((originalY + off) < -lineHeight || (originalY + off) > height) | ||||||
|  |         { | ||||||
|  |             ImGui.Dummy(new System.Numerics.Vector2(0f, lineHeight)); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         var textPosY = originalY + pauseIconSize.Y / 2 - textSize.Y / 2; |         var textPosY = originalY + pauseIconSize.Y / 2 - textSize.Y / 2; | ||||||
|         DrawLeftSide(textPosY, originalY); |         DrawLeftSide(textPosY, originalY); | ||||||
|         ImGui.SameLine(); |         ImGui.SameLine(); | ||||||
|   | |||||||
| @@ -395,63 +395,56 @@ internal sealed class GroupPanel | |||||||
|         ImGui.Indent(20); |         ImGui.Indent(20); | ||||||
|         if (_expandedGroupState[groupDto.GID]) |         if (_expandedGroupState[groupDto.GID]) | ||||||
|         { |         { | ||||||
|             var visibleUsers = pairsInGroup.Where(u => u.IsVisible) |             var sortedPairs = pairsInGroup | ||||||
|                 .OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal)) |                 .OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal)) | ||||||
|                 .ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator()) |                 .ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator()) | ||||||
|                 .ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned()) |                 .ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned()) | ||||||
|                 .ThenBy(u => u.GetNote() ?? u.UserData.AliasOrUID, StringComparer.OrdinalIgnoreCase) |                 .ThenBy(u => u.GetNote() ?? u.UserData.AliasOrUID, StringComparer.OrdinalIgnoreCase); | ||||||
|                 .Select(c => new DrawGroupPair(groupDto.GID + c.UserData.UID, c, ApiController, _mainUi.Mediator, groupDto, c.GroupPair.Single(g => GroupDataComparer.Instance.Equals(g.Key.Group, groupDto.Group)).Value, |  | ||||||
|                     _uidDisplayHandler)) |  | ||||||
|                 .ToList(); |  | ||||||
|             var onlineUsers = pairsInGroup.Where(u => u.IsOnline && !u.IsVisible) |  | ||||||
|                 .OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal)) |  | ||||||
|                 .ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator()) |  | ||||||
|                 .ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned()) |  | ||||||
|                 .ThenBy(u => u.GetNote() ?? u.UserData.AliasOrUID, StringComparer.OrdinalIgnoreCase) |  | ||||||
|                 .Select(c => new DrawGroupPair(groupDto.GID + c.UserData.UID, c, ApiController, _mainUi.Mediator, groupDto, c.GroupPair.Single(g => GroupDataComparer.Instance.Equals(g.Key.Group, groupDto.Group)).Value, |  | ||||||
|                     _uidDisplayHandler)) |  | ||||||
|                 .ToList(); |  | ||||||
|             var offlineUsers = pairsInGroup.Where(u => !u.IsOnline && !u.IsVisible) |  | ||||||
|                 .OrderByDescending(u => string.Equals(u.UserData.UID, groupDto.OwnerUID, StringComparison.Ordinal)) |  | ||||||
|                 .ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsModerator()) |  | ||||||
|                 .ThenByDescending(u => u.GroupPair[groupDto].GroupPairStatusInfo.IsPinned()) |  | ||||||
|                 .ThenBy(u => u.GetNote() ?? u.UserData.AliasOrUID, StringComparer.OrdinalIgnoreCase) |  | ||||||
|                 .Select(c => new DrawGroupPair(groupDto.GID + c.UserData.UID, c, ApiController, _mainUi.Mediator, groupDto, c.GroupPair.Single(g => GroupDataComparer.Instance.Equals(g.Key.Group, groupDto.Group)).Value, |  | ||||||
|                     _uidDisplayHandler)) |  | ||||||
|                 .ToList(); |  | ||||||
|  |  | ||||||
|             if (visibleUsers.Any()) |             var visibleUsers = new List<DrawGroupPair>(); | ||||||
|  |             var onlineUsers = new List<DrawGroupPair>(); | ||||||
|  |             var offlineUsers = new List<DrawGroupPair>(); | ||||||
|  |  | ||||||
|  |             foreach (var pair in sortedPairs) | ||||||
|             { |             { | ||||||
|                 ImGui.Text("Visible"); |                 var drawPair = new DrawGroupPair( | ||||||
|                 ImGui.Separator(); |                     groupDto.GID + pair.UserData.UID, pair, | ||||||
|                 foreach (var entry in visibleUsers) |                     ApiController, _mainUi.Mediator, groupDto, | ||||||
|                 { |                     pair.GroupPair.Single( | ||||||
|                     using (ImRaii.PushId(groupDto.GID + entry.UID)) entry.DrawPairedClient(); |                         g => GroupDataComparer.Instance.Equals(g.Key.Group, groupDto.Group) | ||||||
|                 } |                     ).Value, | ||||||
|  |                     _uidDisplayHandler); | ||||||
|  |  | ||||||
|  |                 if (pair.IsVisible) | ||||||
|  |                     visibleUsers.Add(drawPair); | ||||||
|  |                 else if (pair.IsOnline) | ||||||
|  |                     onlineUsers.Add(drawPair); | ||||||
|  |                 else | ||||||
|  |                     offlineUsers.Add(drawPair); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (onlineUsers.Any()) |             if (visibleUsers.Count > 0) | ||||||
|             { |             { | ||||||
|                 ImGui.Text("Online"); |                 ImGui.TextUnformatted("Visible"); | ||||||
|                 ImGui.Separator(); |                 ImGui.Separator(); | ||||||
|                 foreach (var entry in onlineUsers) |                 _uidDisplayHandler.RenderPairList(visibleUsers); | ||||||
|                 { |  | ||||||
|                     using (ImRaii.PushId(groupDto.GID + entry.UID)) entry.DrawPairedClient(); |  | ||||||
|                 } |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             if (offlineUsers.Any()) |             if (onlineUsers.Count > 0) | ||||||
|             { |             { | ||||||
|                 ImGui.Text("Offline/Unknown"); |                 ImGui.TextUnformatted("Online"); | ||||||
|                 ImGui.Separator(); |                 ImGui.Separator(); | ||||||
|                 foreach (var entry in offlineUsers) |                 _uidDisplayHandler.RenderPairList(onlineUsers); | ||||||
|                 { |  | ||||||
|                     using (ImRaii.PushId(groupDto.GID + entry.UID)) entry.DrawPairedClient(); |  | ||||||
|             } |             } | ||||||
|  |  | ||||||
|  |             if (offlineUsers.Count > 0) | ||||||
|  |             { | ||||||
|  |                 ImGui.TextUnformatted("Offline/Unknown"); | ||||||
|  |                 ImGui.Separator(); | ||||||
|  |                 _uidDisplayHandler.RenderPairList(offlineUsers); | ||||||
|             } |             } | ||||||
|  |  | ||||||
|             ImGui.Separator(); |             ImGui.Separator(); | ||||||
|             ImGui.Unindent(ImGui.GetStyle().ItemSpacing.X / 2); |  | ||||||
|         } |         } | ||||||
|         ImGui.Unindent(20); |         ImGui.Unindent(20); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -15,11 +15,13 @@ public class PairGroupsUi | |||||||
|     private readonly MareConfigService _mareConfig; |     private readonly MareConfigService _mareConfig; | ||||||
|     private readonly SelectPairForGroupUi _selectGroupForPairUi; |     private readonly SelectPairForGroupUi _selectGroupForPairUi; | ||||||
|     private readonly TagHandler _tagHandler; |     private readonly TagHandler _tagHandler; | ||||||
|  |     private readonly UidDisplayHandler _uidDisplayHandler; | ||||||
|  |  | ||||||
|     public PairGroupsUi(MareConfigService mareConfig, TagHandler tagHandler, ApiController apiController, SelectPairForGroupUi selectGroupForPairUi) |     public PairGroupsUi(MareConfigService mareConfig, TagHandler tagHandler, UidDisplayHandler uidDisplayHandler, ApiController apiController, SelectPairForGroupUi selectGroupForPairUi) | ||||||
|     { |     { | ||||||
|         _mareConfig = mareConfig; |         _mareConfig = mareConfig; | ||||||
|         _tagHandler = tagHandler; |         _tagHandler = tagHandler; | ||||||
|  |         _uidDisplayHandler = uidDisplayHandler; | ||||||
|         _apiController = apiController; |         _apiController = apiController; | ||||||
|         _selectGroupForPairUi = selectGroupForPairUi; |         _selectGroupForPairUi = selectGroupForPairUi; | ||||||
|     } |     } | ||||||
| @@ -182,10 +184,7 @@ public class PairGroupsUi | |||||||
|     private void DrawPairs(string tag, IEnumerable<DrawPairBase> availablePairsInThisCategory) |     private void DrawPairs(string tag, IEnumerable<DrawPairBase> availablePairsInThisCategory) | ||||||
|     { |     { | ||||||
|         // These are all the OtherUIDs that are tagged with this tag |         // These are all the OtherUIDs that are tagged with this tag | ||||||
|         foreach (var pair in availablePairsInThisCategory) |         _uidDisplayHandler.RenderPairList(availablePairsInThisCategory); | ||||||
|         { |  | ||||||
|             using (ImRaii.PushId($"tag-{tag}-pair-${pair.UID}")) pair.DrawPairedClient(); |  | ||||||
|         } |  | ||||||
|         ImGui.Separator(); |         ImGui.Separator(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ using MareSynchronos.Services.ServerConfiguration; | |||||||
| using MareSynchronos.MareConfiguration; | using MareSynchronos.MareConfiguration; | ||||||
| using ImGuiScene; | using ImGuiScene; | ||||||
| using MareSynchronos.Services.Mediator; | using MareSynchronos.Services.Mediator; | ||||||
|  | using MareSynchronos.UI.Components; | ||||||
|  |  | ||||||
| namespace MareSynchronos.UI.Handlers; | namespace MareSynchronos.UI.Handlers; | ||||||
|  |  | ||||||
| @@ -32,6 +33,31 @@ public class UidDisplayHandler | |||||||
|         _mareConfigService = mareConfigService; |         _mareConfigService = mareConfigService; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public void RenderPairList(IEnumerable<DrawPairBase> pairs) | ||||||
|  |     { | ||||||
|  |         var textHeight = ImGui.GetFontSize(); | ||||||
|  |         var style = ImGui.GetStyle(); | ||||||
|  |         var framePadding = style.FramePadding; | ||||||
|  |         var spacing = style.ItemSpacing; | ||||||
|  |         var lineHeight = textHeight + framePadding.Y * 2 + spacing.Y; | ||||||
|  |         var startY = ImGui.GetCursorStartPos().Y; | ||||||
|  |         var cursorY = ImGui.GetCursorPosY(); | ||||||
|  |         var contentHeight = UiSharedService.GetWindowContentRegionHeight(); | ||||||
|  |  | ||||||
|  |         foreach (var entry in pairs) | ||||||
|  |         { | ||||||
|  |             if ((startY + cursorY) < -lineHeight || (startY + cursorY) > contentHeight) | ||||||
|  |             { | ||||||
|  |                 cursorY += lineHeight; | ||||||
|  |                 ImGui.SetCursorPosY(cursorY); | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             using (ImRaii.PushId(entry.ImGuiID)) entry.DrawPairedClient(); | ||||||
|  |             cursorY += lineHeight; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public void DrawPairText(string id, Pair pair, float textPosX, float originalY, Func<float> editBoxWidth) |     public void DrawPairText(string id, Pair pair, float textPosX, float originalY, Func<float> editBoxWidth) | ||||||
|     { |     { | ||||||
|         ImGui.SameLine(textPosX); |         ImGui.SameLine(textPosX); | ||||||
|   | |||||||
| @@ -326,6 +326,11 @@ public partial class UiSharedService : DisposableMediatorSubscriberBase | |||||||
|         return ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; |         return ImGui.GetWindowContentRegionMax().X - ImGui.GetWindowContentRegionMin().X; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     public static float GetWindowContentRegionHeight() | ||||||
|  |     { | ||||||
|  |         return ImGui.GetWindowContentRegionMax().Y - ImGui.GetWindowContentRegionMin().Y; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     public static Vector2 GetNormalizedIconTextButtonSize(FontAwesomeIcon icon, string text, float? width = null, bool isInPopup = false) |     public static Vector2 GetNormalizedIconTextButtonSize(FontAwesomeIcon icon, string text, float? width = null, bool isInPopup = false) | ||||||
|     { |     { | ||||||
|         var iconData = GetIconData(icon); |         var iconData = GetIconData(icon); | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Loporrit
					Loporrit