/// <inheritdoc/> public override void Update() { int numVisibleEntries = MathEx.CeilToInt(height / (float)entryHeight) + 1; numVisibleEntries = MathEx.Min(numVisibleEntries, entries.Count); while (visibleEntries.Count < numVisibleEntries) { TEntry newEntry = new TEntry(); newEntry.Initialize(this); newEntry.panel.SetHeight(entryHeight); visibleEntries.Add(newEntry); contentsDirty = true; } while (numVisibleEntries < visibleEntries.Count) { int lastIdx = visibleEntries.Count - 1; visibleEntries[lastIdx].Destroy(); visibleEntries.RemoveAt(lastIdx); contentsDirty = true; } if (scrollPct != scrollArea.VerticalScroll) { scrollPct = scrollArea.VerticalScroll; contentsDirty = true; } if (contentsDirty) { int newHeight = entries.Count * entryHeight; if (scrollToLatest) { if (totalHeight > height && scrollPct < 1.0f) { scrollToLatest = false; } } else { if (totalHeight <= height || scrollPct >= 1.0f) { scrollToLatest = true; } } totalHeight = newHeight; int maxScrollOffset = MathEx.Max(0, totalHeight - height - 1); float newScrollPct; if (!scrollToLatest) { // Calculate the new scroll pct (which will be active after we change the top/bottom padding element // sizes). If we use the existing scroll pct instead then the elements will lag one frame behind, which // can be very noticeable on quickly updating lists. newScrollPct = (scrollPct * scrollArea.Layout.Bounds.height) / totalHeight; } else { newScrollPct = 1.0f; } int startPos = MathEx.FloorToInt(newScrollPct * maxScrollOffset); int startIndex = MathEx.FloorToInt(startPos / (float)entryHeight); // Check if we're at the list bottom and the extra element is out of bounds if ((startIndex + visibleEntries.Count) > entries.Count) { startIndex--; // Keep the extra element at the top always } topPadding.SetHeight(startIndex * entryHeight); for (int i = 0; i < visibleEntries.Count; i++) { visibleEntries[i].UpdateContents(startIndex + i, entries[startIndex + i]); } int bottomPosition = MathEx.Min(totalHeight, (startIndex + visibleEntries.Count) * entryHeight); bottomPadding.SetHeight(totalHeight - bottomPosition); if (scrollToLatest) { if (newHeight <= height) { scrollArea.VerticalScroll = 0.0f; } else { scrollArea.VerticalScroll = 1.0f; } } contentsDirty = false; } }