123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEditor;
- using UnityEngine;
- namespace vietlabs.fr2
- {
- public class FR2_TreeUI2
- {
- internal Drawer drawer;
- private Vector2 position;
- private TreeItem rootItem;
- internal Rect visibleRect;
- public float itemPaddingRight = 0f;
- public FR2_TreeUI2(Drawer drawer)
- {
- this.drawer = drawer;
- }
- public void Reset(params string[] root)
- {
- position = Vector2.zero;
- rootItem = new TreeItem
- {
- tree = this,
- id = "$root",
- height = 0,
- depth = -1,
- _isOpen = true,
- highlight = false,
- childCount = root.Length
- };
- rootItem.RefreshChildren(root);
- rootItem.DeepOpen();
- }
- public void Draw(Rect rect)
- {
- if (rect.width > 0)
- {
- visibleRect = rect;
- }
-
- var contentRect = new Rect(0f, 0f, 1f, rootItem.childrenHeight);
- bool noScroll = contentRect.height < visibleRect.height;
- if (noScroll)
- {
- position = Vector2.zero;
- }
- var minY = (int) position.y;
- var maxY = (int) (position.y + visibleRect.height);
- contentRect.x -= FR2_Setting.TreeIndent;
- TreeItem.DrawCall = 0;
- TreeItem.DrawRender = 0;
- position = GUI.BeginScrollView(visibleRect, position, contentRect);
- {
- var r = new Rect(0, 0, rect.width - (noScroll ? 4f : 18f)-itemPaddingRight, 16f);
- var index = 0;
- rootItem.Draw(ref index, ref r, minY, maxY);
- }
- GUI.EndScrollView();
- }
- public void DrawLayout()
- {
- EventType evtType = Event.current.type;
- Rect r = GUILayoutUtility.GetRect(1f, Screen.width, 16f, Screen.height);
- if (evtType != EventType.Layout)
- {
- visibleRect = r;
- }
-
- Draw(visibleRect);
- }
- public bool NoScroll()
- {
- return rootItem.childrenHeight < visibleRect.height;
- }
- // ------------------------ DELEGATE --------------
- public class Drawer
- {
- public virtual int GetHeight(string id)
- {
- return 16;
- }
- public virtual int GetChildCount(string id)
- {
- return 0;
- }
- public virtual string[] GetChildren(string id)
- {
- return null;
- }
- public virtual void Draw(Rect r, TreeItem item)
- {
- GUI.Label(r, item.id);
- }
- }
- public class GroupDrawer : Drawer
- {
- public Action<Rect, string, int> drawGroup;
- public Action<Rect, string> drawItem;
- private Dictionary<string, List<string>> groupDict;
- internal FR2_TreeUI2 tree;
- public GroupDrawer(Action<Rect, string, int> drawGroup, Action<Rect, string> drawItem)
- {
- this.drawItem = drawItem;
- this.drawGroup = drawGroup;
- }
- // ----------------- TREE WRAPPER ------------------
- public bool TreeNoScroll()
- {
- return tree.NoScroll();
- }
- public bool hideGroupIfPossible;
-
-
- public void Reset<T>(List<T> items, Func<T, string> idFunc, Func<T, string> groupFunc,
- Action<List<string>> customGroupSort = null)
- {
- groupDict = new Dictionary<string, List<string>>();
- for (var i = 0; i < items.Count; i++)
- {
- List<string> list;
- string groupName = groupFunc(items[i]);
- if (groupName == null) continue; // do not exclude groupName string.Empty
-
- string itemId = idFunc(items[i]);
- if (string.IsNullOrEmpty(itemId)) continue; // ignore items without id
-
- if (!groupDict.TryGetValue(groupName, out list))
- {
- list = new List<string>();
- groupDict.Add(groupName, list);
- }
-
- list.Add(itemId);
- }
- if (tree == null)
- {
- tree = new FR2_TreeUI2(this);
- }
-
- List<string> groups = groupDict.Keys.ToList();
- if (hideGroupIfPossible && groups.Count == 1) //single group : Flat list
- {
- var v = groupDict[groups[0]];
- tree.Reset(v.ToArray());
- groupDict.Clear();
- } else { //multiple groups
- if (customGroupSort != null)
- {
- customGroupSort(groups);
- }
- else
- {
- groups.Sort();
- }
- tree.Reset(groups.ToArray());
- }
- }
- public void Draw(Rect r)
- {
- if (tree != null) tree.Draw(r);
- }
- public bool hasChildren
- {
- get {
- return tree != null && tree.rootItem.childCount > 0;
- }
- }
- public bool hasValidTree
- {
- get { return groupDict != null && tree != null; }
- }
-
- public void DrawLayout()
- {
- if (tree != null) tree.DrawLayout();
- }
- // ----------------- DRAWER WRAPPER ------------------
- public override int GetChildCount(string id)
- {
- if (string.IsNullOrEmpty(id)) return 0;
-
- List<string> group;
- if (groupDict.TryGetValue(id, out group))
- {
- return group.Count;
- }
- return 0;
- }
- public override string[] GetChildren(string id)
- {
- List<string> group;
- if (groupDict.TryGetValue(id, out group))
- {
- return group.ToArray();
- }
- return null;
- }
- public override void Draw(Rect r, TreeItem item)
- {
- List<string> group;
- if (groupDict.TryGetValue(item.id, out group))
- {
- drawGroup(r, item.id, item.childCount);
- return;
- }
- drawItem(r, item.id);
- }
- }
-
- // ------------------------ TreeItem2 --------------
- public class TreeItem
- {
- public static int DrawCall;
- public static int DrawRender;
- internal bool _isOpen;
- public int childCount;
- public List<TreeItem> children;
- public int childrenHeight;
- public int depth; // item depth
- public int height;
- public bool highlight;
- public string id; // item id
- internal TreeItem parent;
- //static Color COLOR = new Color(0f, 0f, 0f, 0.05f);
- internal FR2_TreeUI2 tree;
- public bool IsOpen
- {
- get { return _isOpen; }
- set
- {
- if (_isOpen == value || childCount == 0)
- {
- return;
- }
- _isOpen = value;
- if (_isOpen)
- {
- if (children == null)
- {
- RefreshChildren(tree.drawer.GetChildren(id));
- }
- //Update height for all parents
- TreeItem p = parent;
- while (p != null)
- {
- p.childrenHeight += childrenHeight;
- p = p.parent;
- }
- }
- else
- {
- //Update height for all parents
- TreeItem p = parent;
- while (p != null)
- {
- p.childrenHeight -= childrenHeight;
- p = p.parent;
- }
- }
- }
- }
- internal void DeepOpen()
- {
- IsOpen = true;
- if (children == null)
- {
- return;
- }
- for (var i = 0; i < children.Count; i++)
- {
- children[i].DeepOpen();
- }
- }
- internal void Draw(ref int index, ref Rect rect, int minY, int maxY)
- {
- DrawCall++;
- // if (DrawCall < 10)
- // {
- // Debug.Log(index + ":" + rect + ":" + minY + ":" + maxY + ":" + height + ":" + childrenHeight);
- // }
- //var skipDraw = (rect.y >= maxY) || (height <=0);
- float min = rect.y;
- float max = rect.y + height;
- bool interMin = min >= minY && min <= maxY;
- bool interMax = max >= minY && max <= maxY;
- if (height > 0 && (interMin || interMax))
- {
- DrawRender++;
- rect.height = height;
- if (index % 2 == 1 && FR2_Setting.AlternateRowColor)
- {
- Color o = GUI.color;
- GUI.color = FR2_Setting.RowColor;
- // GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);
- GUI.DrawTexture(new Rect(rect.x - FR2_Setting.TreeIndent, rect.y, rect.width, rect.height),
- EditorGUIUtility.whiteTexture);
- GUI.color = o;
- }
- float x = (depth + 1) * 16f;
- tree.drawer.Draw(new Rect(x, rect.y, rect.width - x, rect.height), this);
- if (childCount > 0)
- {
- IsOpen = GUI.Toggle(new Rect(rect.x + x - 16f, rect.y, 16f, 16f), IsOpen, string.Empty,
- EditorStyles.foldout);
- }
- index++;
- rect.y += height;
- }
- else
- {
- rect.y += height;
- }
- if (_isOpen && rect.y <= maxY) //draw children
- {
- for (var i = 0; i < children.Count; i++)
- {
- children[i].Draw(ref index, ref rect, minY, maxY);
- if (rect.y > maxY)
- {
- break;
- }
- }
- }
- }
- internal void RefreshChildren(string[] childrenIDs)
- {
- childCount = childrenIDs.Length;
- childrenHeight = 0;
- children = new List<TreeItem>();
- for (var i = 0; i < childCount; i++)
- {
- string itemId = childrenIDs[i];
- var item = new TreeItem
- {
- tree = tree,
- parent = this,
- id = itemId,
- depth = depth + 1,
- highlight = false,
- height = tree.drawer.GetHeight(itemId),
- childCount = tree.drawer.GetChildCount(itemId)
- };
- childrenHeight += item.height;
- children.Add(item);
- }
- }
- }
- }
- }
|