|
|
@@ -1,332 +1,334 @@
|
|
|
-using System.Collections.Generic;
|
|
|
-
|
|
|
-namespace BansheeEngine
|
|
|
-{
|
|
|
- /// <summary>
|
|
|
- /// GUI element that can efficiently display a list of entries that share the same height. This element is mostly an
|
|
|
- /// optimization as only visible entries have actual GUI elements, as opposed to just adding GUI elements directly
|
|
|
- /// in a vertical GUI layout. This allows the list view to have thousands of elements with little performance impact.
|
|
|
- ///
|
|
|
- /// Contains shared functionality used by all instances of <see cref="GUIListView{TEntry,TData}"/>.
|
|
|
- /// </summary>
|
|
|
- /// <typeparam name="TData">>Type used for storing the data for all list entries.</typeparam>
|
|
|
- public abstract class GUIListViewBase<TData>
|
|
|
- where TData : GUIListViewData
|
|
|
- {
|
|
|
- // TODO - Only fixed size is supported. It should be nice if this object could just be placed in layout like any
|
|
|
- // other GUI element. Would likely need some kind of a way to get notified when parent layout changes.
|
|
|
- // (Possibly add a callback to GUIPanel when updateLayout is called?)
|
|
|
-
|
|
|
- protected List<TData> entries = new List<TData>();
|
|
|
- protected GUIScrollArea scrollArea;
|
|
|
- protected GUILabel topPadding;
|
|
|
- protected GUILabel bottomPadding;
|
|
|
- protected int width;
|
|
|
- protected int height;
|
|
|
- protected int entryHeight;
|
|
|
- protected float scrollPct = 0.0f;
|
|
|
- protected bool scrollToLatest = true;
|
|
|
- protected internal bool contentsDirty = true;
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Total number of entries in the list.
|
|
|
- /// </summary>
|
|
|
- public int NumEntries
|
|
|
- {
|
|
|
- get { return entries.Count; }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Height of a single entry in the list, in pixels.
|
|
|
- /// </summary>
|
|
|
- public int EntryHeight
|
|
|
- {
|
|
|
- get { return entryHeight; }
|
|
|
- set { entryHeight = value; }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Primary GUI scroll area that all entries are contained within.
|
|
|
- /// </summary>
|
|
|
- internal GUIScrollArea ScrollArea
|
|
|
- {
|
|
|
- get { return scrollArea; }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Creates a new empty list view.
|
|
|
- /// </summary>
|
|
|
- /// <param name="width">Width of the list view, in pixels.</param>
|
|
|
- /// <param name="height">Height of the list view, in pixels.</param>
|
|
|
- /// <param name="entryHeight">Height of a single element in the list, in pixels.</param>
|
|
|
- /// <param name="layout">GUI layout into which the list view will be placed into.</param>
|
|
|
- protected GUIListViewBase(int width, int height, int entryHeight, GUILayout layout)
|
|
|
- {
|
|
|
- scrollArea = new GUIScrollArea(ScrollBarType.ShowIfDoesntFit, ScrollBarType.NeverShow,
|
|
|
- GUIOption.FixedWidth(width), GUIOption.FixedHeight(height));
|
|
|
- layout.AddElement(scrollArea);
|
|
|
-
|
|
|
- topPadding = new GUILabel(new LocString());
|
|
|
- bottomPadding = new GUILabel(new LocString());
|
|
|
-
|
|
|
- scrollArea.Layout.AddElement(topPadding);
|
|
|
- scrollArea.Layout.AddElement(bottomPadding);
|
|
|
-
|
|
|
- this.width = width;
|
|
|
- this.height = height;
|
|
|
- this.entryHeight = entryHeight;
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Adds a new entry to the end of the list.
|
|
|
- /// </summary>
|
|
|
- /// <param name="data">Data of the entry to add.</param>
|
|
|
- public void AddEntry(TData data)
|
|
|
- {
|
|
|
- entries.Add(data);
|
|
|
- contentsDirty = true;
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Removes an entry from the specified index. If the index is out of range nothing happens.
|
|
|
- /// </summary>
|
|
|
- /// <param name="index">Sequential index of the element to remove from the list.</param>
|
|
|
- public void RemoveEntry(int index)
|
|
|
- {
|
|
|
- if (index >= 0 && index < entries.Count)
|
|
|
- {
|
|
|
- entries.RemoveAt(index);
|
|
|
- contentsDirty = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Removes all entries from the list.
|
|
|
- /// </summary>
|
|
|
- public void Clear()
|
|
|
- {
|
|
|
- entries.Clear();
|
|
|
- contentsDirty = true;
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Finds an index of the specified entry in the list.
|
|
|
- /// </summary>
|
|
|
- /// <param name="data">Data of the entry to search for.</param>
|
|
|
- /// <returns>Index of the entry if found, -1 otherwise.</returns>
|
|
|
- public int FindEntry(TData data)
|
|
|
- {
|
|
|
- return entries.FindIndex(x => x.Equals(data));
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Adds a new entry at the specified index. If the index is out of range the entry is added at the end of the list.
|
|
|
- /// </summary>
|
|
|
- /// <param name="index">Sequential index at which to insert the entry. </param>
|
|
|
- /// <param name="data">Data of the entry to insert.</param>
|
|
|
- public void InsertEntry(int index, TData data)
|
|
|
- {
|
|
|
- if (index >= 0 && index <= entries.Count)
|
|
|
- entries.Insert(index, data);
|
|
|
- else
|
|
|
- entries.Add(data);
|
|
|
-
|
|
|
- contentsDirty = true;
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Changes the size of the list view.
|
|
|
- /// </summary>
|
|
|
- /// <param name="width">Width in pixels.</param>
|
|
|
- /// <param name="height">Height in pixels.</param>
|
|
|
- public void SetSize(int width, int height)
|
|
|
- {
|
|
|
- if (width != this.width || height != this.height)
|
|
|
- {
|
|
|
- this.width = width;
|
|
|
- this.height = height;
|
|
|
-
|
|
|
- Rect2I bounds = scrollArea.Bounds;
|
|
|
- bounds.width = width;
|
|
|
- bounds.height = height;
|
|
|
- scrollArea.Bounds = bounds;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Updates the visuals of the list view. Should be called once per frame.
|
|
|
- /// </summary>
|
|
|
- public abstract void Update();
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// GUI element that can efficiently display a list of entries that share the same height. This element is mostly an
|
|
|
- /// optimization as only visible entries have actual GUI elements, as opposed to just adding GUI elements directly
|
|
|
- /// in a vertical GUI layout. This allows the list view to have thousands of elements with little performance impact.
|
|
|
- /// </summary>
|
|
|
- /// <typeparam name="TEntry">Type used for creating and updating the GUI elements of the visible entries.</typeparam>
|
|
|
- /// <typeparam name="TData">Type used for storing the data for all list entries.</typeparam>
|
|
|
- public class GUIListView<TEntry, TData> : GUIListViewBase<TData>
|
|
|
- where TEntry : GUIListViewEntry<TData>, new()
|
|
|
- where TData : GUIListViewData
|
|
|
- {
|
|
|
- private List<TEntry> visibleEntries = new List<TEntry>();
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Creates a new empty list view.
|
|
|
- /// </summary>
|
|
|
- /// <param name="width">Width of the list view, in pixels.</param>
|
|
|
- /// <param name="height">Height of the list view, in pixels.</param>
|
|
|
- /// <param name="entryHeight">Height of a single element in the list, in pixels.</param>
|
|
|
- /// <param name="layout">GUI layout into which the list view will be placed into.</param>
|
|
|
- public GUIListView(int width, int height, int entryHeight, GUILayout layout)
|
|
|
- :base(width, height, entryHeight, layout)
|
|
|
- { }
|
|
|
-
|
|
|
- /// <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;
|
|
|
- }
|
|
|
-
|
|
|
- int totalElementHeight = entries.Count * entryHeight;
|
|
|
- if (scrollPct != scrollArea.VerticalScroll)
|
|
|
- {
|
|
|
- scrollPct = scrollArea.VerticalScroll;
|
|
|
- contentsDirty = true;
|
|
|
-
|
|
|
- if (scrollToLatest)
|
|
|
- {
|
|
|
- if (scrollPct < 1.0f)
|
|
|
- scrollToLatest = false;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- if (totalElementHeight <= height || scrollPct >= 1.0f)
|
|
|
- scrollToLatest = true;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (contentsDirty)
|
|
|
- {
|
|
|
- int maxScrollOffset = MathEx.Max(0, totalElementHeight - height - 1);
|
|
|
-
|
|
|
- int startPos = MathEx.FloorToInt(scrollPct * 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]);
|
|
|
- visibleEntries[i].panel.SetPosition(0, i * entryHeight);
|
|
|
- }
|
|
|
-
|
|
|
- int bottomPosition = MathEx.Min(totalElementHeight, (startIndex + visibleEntries.Count) * entryHeight);
|
|
|
- bottomPadding.SetHeight(totalElementHeight - bottomPosition);
|
|
|
-
|
|
|
- if (scrollToLatest)
|
|
|
- {
|
|
|
- if (totalElementHeight <= height)
|
|
|
- scrollArea.VerticalScroll = 0.0f;
|
|
|
- else
|
|
|
- scrollArea.VerticalScroll = 1.0f;
|
|
|
- }
|
|
|
-
|
|
|
- contentsDirty = false;
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Base class that contains data for individual entries used in <see cref="GUIListView{TEntry,TData}"/>.
|
|
|
- /// </summary>
|
|
|
- public class GUIListViewData
|
|
|
- {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Base class that displays GUI elements for visible entries used in <see cref="GUIListView{TEntry,TData}"/>.
|
|
|
- /// </summary>
|
|
|
- /// <typeparam name="TData">Type of object that contains data used for initializing the GUI elements.</typeparam>
|
|
|
- public abstract class GUIListViewEntry<TData>
|
|
|
- where TData : GUIListViewData
|
|
|
- {
|
|
|
- private GUIListViewBase<TData> parent;
|
|
|
- internal GUIPanel panel;
|
|
|
- internal GUILayoutY layout;
|
|
|
-
|
|
|
- protected GUILayout Layout { get { return layout; } }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Initializes the GUI elements for the entry.
|
|
|
- /// </summary>
|
|
|
- /// <param name="parent">Scroll area into whose layout to insert the GUI elements.</param>
|
|
|
- internal void Initialize(GUIListViewBase<TData> parent)
|
|
|
- {
|
|
|
- this.parent = parent;
|
|
|
-
|
|
|
- GUIScrollArea scrollArea = parent.ScrollArea;
|
|
|
- int numElements = scrollArea.Layout.ChildCount;
|
|
|
-
|
|
|
- // Last panel is always the padding panel, so keep it there
|
|
|
- panel = scrollArea.Layout.InsertPanel(numElements - 1);
|
|
|
- layout = panel.AddLayoutY();
|
|
|
-
|
|
|
- BuildGUI();
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Destoys the GUI elements for the entry.
|
|
|
- /// </summary>
|
|
|
- internal void Destroy()
|
|
|
- {
|
|
|
- panel.Destroy();
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Causes all visible entries in the parent list to be updated.
|
|
|
- /// </summary>
|
|
|
- protected void RefreshEntries()
|
|
|
- {
|
|
|
- parent.contentsDirty = true;
|
|
|
- }
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Allows child classes to create GUI elements required by their entry specialization.
|
|
|
- /// </summary>
|
|
|
- public abstract void BuildGUI();
|
|
|
-
|
|
|
- /// <summary>
|
|
|
- /// Allows child classes to update GUI element(s) with new contents.
|
|
|
- /// </summary>
|
|
|
- /// <param name="index">Sequential index of the entry in the list.</param>
|
|
|
- /// <param name="data">Data of the entry to display.</param>
|
|
|
- public abstract void UpdateContents(int index, TData data);
|
|
|
- }
|
|
|
-}
|
|
|
+using System.Collections.Generic;
|
|
|
+
|
|
|
+namespace BansheeEngine
|
|
|
+{
|
|
|
+ /// <summary>
|
|
|
+ /// GUI element that can efficiently display a list of entries that share the same height. This element is mostly an
|
|
|
+ /// optimization as only visible entries have actual GUI elements, as opposed to just adding GUI elements directly
|
|
|
+ /// in a vertical GUI layout. This allows the list view to have thousands of elements with little performance impact.
|
|
|
+ ///
|
|
|
+ /// Contains shared functionality used by all instances of <see cref="GUIListView{TEntry,TData}"/>.
|
|
|
+ /// </summary>
|
|
|
+ /// <typeparam name="TData">>Type used for storing the data for all list entries.</typeparam>
|
|
|
+ public abstract class GUIListViewBase<TData>
|
|
|
+ where TData : GUIListViewData
|
|
|
+ {
|
|
|
+ // TODO - Only fixed size is supported. It should be nice if this object could just be placed in layout like any
|
|
|
+ // other GUI element. Would likely need some kind of a way to get notified when parent layout changes.
|
|
|
+ // (Possibly add a callback to GUIPanel when updateLayout is called?)
|
|
|
+
|
|
|
+ protected List<TData> entries = new List<TData>();
|
|
|
+ protected GUIScrollArea scrollArea;
|
|
|
+ protected GUILabel topPadding;
|
|
|
+ protected GUILabel bottomPadding;
|
|
|
+ protected int width;
|
|
|
+ protected int height;
|
|
|
+ protected int entryHeight;
|
|
|
+ protected float scrollPct;
|
|
|
+ protected bool scrollToLatest;
|
|
|
+ protected int totalHeight;
|
|
|
+ protected internal bool contentsDirty = true;
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Total number of entries in the list.
|
|
|
+ /// </summary>
|
|
|
+ public int NumEntries
|
|
|
+ {
|
|
|
+ get { return entries.Count; }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Height of a single entry in the list, in pixels.
|
|
|
+ /// </summary>
|
|
|
+ public int EntryHeight
|
|
|
+ {
|
|
|
+ get { return entryHeight; }
|
|
|
+ set { entryHeight = value; }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Primary GUI scroll area that all entries are contained within.
|
|
|
+ /// </summary>
|
|
|
+ internal GUIScrollArea ScrollArea
|
|
|
+ {
|
|
|
+ get { return scrollArea; }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Creates a new empty list view.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="width">Width of the list view, in pixels.</param>
|
|
|
+ /// <param name="height">Height of the list view, in pixels.</param>
|
|
|
+ /// <param name="entryHeight">Height of a single element in the list, in pixels.</param>
|
|
|
+ /// <param name="layout">GUI layout into which the list view will be placed into.</param>
|
|
|
+ protected GUIListViewBase(int width, int height, int entryHeight, GUILayout layout)
|
|
|
+ {
|
|
|
+ scrollArea = new GUIScrollArea(ScrollBarType.ShowIfDoesntFit, ScrollBarType.NeverShow,
|
|
|
+ GUIOption.FixedWidth(width), GUIOption.FixedHeight(height));
|
|
|
+ layout.AddElement(scrollArea);
|
|
|
+
|
|
|
+ topPadding = new GUILabel(new LocString());
|
|
|
+ bottomPadding = new GUILabel(new LocString());
|
|
|
+
|
|
|
+ scrollArea.Layout.AddElement(topPadding);
|
|
|
+ scrollArea.Layout.AddElement(bottomPadding);
|
|
|
+
|
|
|
+ this.width = width;
|
|
|
+ this.height = height;
|
|
|
+ this.entryHeight = entryHeight;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Adds a new entry to the end of the list.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="data">Data of the entry to add.</param>
|
|
|
+ public void AddEntry(TData data)
|
|
|
+ {
|
|
|
+ entries.Add(data);
|
|
|
+ contentsDirty = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Removes an entry from the specified index. If the index is out of range nothing happens.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="index">Sequential index of the element to remove from the list.</param>
|
|
|
+ public void RemoveEntry(int index)
|
|
|
+ {
|
|
|
+ if (index >= 0 && index < entries.Count)
|
|
|
+ {
|
|
|
+ entries.RemoveAt(index);
|
|
|
+ contentsDirty = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Removes all entries from the list.
|
|
|
+ /// </summary>
|
|
|
+ public void Clear()
|
|
|
+ {
|
|
|
+ entries.Clear();
|
|
|
+ contentsDirty = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Finds an index of the specified entry in the list.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="data">Data of the entry to search for.</param>
|
|
|
+ /// <returns>Index of the entry if found, -1 otherwise.</returns>
|
|
|
+ public int FindEntry(TData data)
|
|
|
+ {
|
|
|
+ return entries.FindIndex(x => x.Equals(data));
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Adds a new entry at the specified index. If the index is out of range the entry is added at the end of the list.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="index">Sequential index at which to insert the entry. </param>
|
|
|
+ /// <param name="data">Data of the entry to insert.</param>
|
|
|
+ public void InsertEntry(int index, TData data)
|
|
|
+ {
|
|
|
+ if (index >= 0 && index <= entries.Count)
|
|
|
+ entries.Insert(index, data);
|
|
|
+ else
|
|
|
+ entries.Add(data);
|
|
|
+
|
|
|
+ contentsDirty = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Changes the size of the list view.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="width">Width in pixels.</param>
|
|
|
+ /// <param name="height">Height in pixels.</param>
|
|
|
+ public void SetSize(int width, int height)
|
|
|
+ {
|
|
|
+ if (width != this.width || height != this.height)
|
|
|
+ {
|
|
|
+ this.width = width;
|
|
|
+ this.height = height;
|
|
|
+
|
|
|
+ Rect2I bounds = scrollArea.Bounds;
|
|
|
+ bounds.width = width;
|
|
|
+ bounds.height = height;
|
|
|
+ scrollArea.Bounds = bounds;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Updates the visuals of the list view. Should be called once per frame.
|
|
|
+ /// </summary>
|
|
|
+ public abstract void Update();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// GUI element that can efficiently display a list of entries that share the same height. This element is mostly an
|
|
|
+ /// optimization as only visible entries have actual GUI elements, as opposed to just adding GUI elements directly
|
|
|
+ /// in a vertical GUI layout. This allows the list view to have thousands of elements with little performance impact.
|
|
|
+ /// </summary>
|
|
|
+ /// <typeparam name="TEntry">Type used for creating and updating the GUI elements of the visible entries.</typeparam>
|
|
|
+ /// <typeparam name="TData">Type used for storing the data for all list entries.</typeparam>
|
|
|
+ public class GUIListView<TEntry, TData> : GUIListViewBase<TData>
|
|
|
+ where TEntry : GUIListViewEntry<TData>, new()
|
|
|
+ where TData : GUIListViewData
|
|
|
+ {
|
|
|
+ private List<TEntry> visibleEntries = new List<TEntry>();
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Creates a new empty list view.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="width">Width of the list view, in pixels.</param>
|
|
|
+ /// <param name="height">Height of the list view, in pixels.</param>
|
|
|
+ /// <param name="entryHeight">Height of a single element in the list, in pixels.</param>
|
|
|
+ /// <param name="layout">GUI layout into which the list view will be placed into.</param>
|
|
|
+ public GUIListView(int width, int height, int entryHeight, GUILayout layout)
|
|
|
+ :base(width, height, entryHeight, layout)
|
|
|
+ { }
|
|
|
+
|
|
|
+ /// <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);
|
|
|
+
|
|
|
+ int startPos = MathEx.FloorToInt(scrollPct * 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]);
|
|
|
+ visibleEntries[i].panel.SetPosition(0, i * entryHeight);
|
|
|
+ }
|
|
|
+
|
|
|
+ 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;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Base class that contains data for individual entries used in <see cref="GUIListView{TEntry,TData}"/>.
|
|
|
+ /// </summary>
|
|
|
+ public class GUIListViewData
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Base class that displays GUI elements for visible entries used in <see cref="GUIListView{TEntry,TData}"/>.
|
|
|
+ /// </summary>
|
|
|
+ /// <typeparam name="TData">Type of object that contains data used for initializing the GUI elements.</typeparam>
|
|
|
+ public abstract class GUIListViewEntry<TData>
|
|
|
+ where TData : GUIListViewData
|
|
|
+ {
|
|
|
+ private GUIListViewBase<TData> parent;
|
|
|
+ internal GUIPanel panel;
|
|
|
+ internal GUILayoutY layout;
|
|
|
+
|
|
|
+ protected GUILayout Layout { get { return layout; } }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Initializes the GUI elements for the entry.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="parent">Scroll area into whose layout to insert the GUI elements.</param>
|
|
|
+ internal void Initialize(GUIListViewBase<TData> parent)
|
|
|
+ {
|
|
|
+ this.parent = parent;
|
|
|
+
|
|
|
+ GUIScrollArea scrollArea = parent.ScrollArea;
|
|
|
+ int numElements = scrollArea.Layout.ChildCount;
|
|
|
+
|
|
|
+ // Last panel is always the padding panel, so keep it there
|
|
|
+ panel = scrollArea.Layout.InsertPanel(numElements - 1);
|
|
|
+ layout = panel.AddLayoutY();
|
|
|
+
|
|
|
+ BuildGUI();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Destoys the GUI elements for the entry.
|
|
|
+ /// </summary>
|
|
|
+ internal void Destroy()
|
|
|
+ {
|
|
|
+ panel.Destroy();
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Causes all visible entries in the parent list to be updated.
|
|
|
+ /// </summary>
|
|
|
+ protected void RefreshEntries()
|
|
|
+ {
|
|
|
+ parent.contentsDirty = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Allows child classes to create GUI elements required by their entry specialization.
|
|
|
+ /// </summary>
|
|
|
+ public abstract void BuildGUI();
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Allows child classes to update GUI element(s) with new contents.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="index">Sequential index of the entry in the list.</param>
|
|
|
+ /// <param name="data">Data of the entry to display.</param>
|
|
|
+ public abstract void UpdateContents(int index, TData data);
|
|
|
+ }
|
|
|
+}
|