-
Notifications
You must be signed in to change notification settings - Fork 446
Tree view control for displaying data performantly. #151
Tree view control for displaying data performantly. #151
Conversation
62c1516
to
a484729
Compare
I sent this PR a PR.. #372 |
Sending you a pull request in #378 |
Making an edit to say this depends on #384 |
# Conflicts: # src/GitHub.Api/Cache/CacheManager.cs
# Conflicts: # src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs
|
||
[SerializeField] public GUIStyle FolderStyle; | ||
[SerializeField] public GUIStyle TreeNodeStyle; | ||
[SerializeField] public GUIStyle ActiveTreeNodeStyle; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Normally I wouldn't serialize GUIStyles/Textures, instead I load them on demand (typically in OnEnable). This makes it more difficult to iterate on the source styles/textures without recreating the serialized object completely. Nothing particularly wrong with this approach though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few things to clean up, but overall looks good.
{ | ||
[SerializeField] public float ItemHeight = EditorGUIUtility.singleLineHeight; | ||
[SerializeField] public float ItemSpacing = EditorGUIUtility.standardVerticalSpacing; | ||
[SerializeField] public float Indentation = 12f; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't look like these three fields ever change? Why serialize them, rather than just making them const values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
for (int i = 0; i < parts.Length; i++) | ||
{ | ||
var label = parts[i]; | ||
var name = String.Join("/", parts, 0, i + 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The GC probably hates you for all of these joins/splits. You may want to take a look at how much garbage memory you're creating for this operation. And how much time is taking to clean it up.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm about to add functionality to the TreeControl to display a different type of tree. So these lines of codes are going to be a stomping ground for a little bit. I'm going to log an issue under tech-debt
for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
{ | ||
bool selectionChanged = false; | ||
var clickRect = new Rect(0f, rect.y, rect.width, rect.height); | ||
if (Event.current.type == EventType.MouseDown && clickRect.Contains(Event.current.mousePosition)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this would also intercept right click or middle click. Is that desirable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is correct. The fix to this is coming in another pull request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
if (Event.current.type == EventType.repaint) | ||
{ | ||
nodeStyle.Draw(fillRect, "", false, false, false, isSelected); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GUIContent.none rather than empty string.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
Using the Styles.TreeIndentation constant The value never changes so no need to make it serializable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo on line 215 of TreeControl.cs
{ | ||
Repository.CheckLocalAndRemoteBranchListChangedEvent(lastLocalAndRemoteBranchListChangedEvent); | ||
} | ||
Repository.CheckLocalAndRemoteBranchListChangedEvent(lastLocalAndRemoteBranchListChangedEvent); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Repository is not longer possibly null then?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By the time the BranchesView
is displayed we always have a Repository
{ | ||
if (node == null || node.Children == null) | ||
//if (IsFavorite(a.Name)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
meant to be commented out? Should it just be removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is getting cleaned up in #468
} | ||
|
||
//private bool IsFavorite(string branchName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented or deleted?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is getting cleaned up in #468
int directionX = Event.current.keyCode == KeyCode.LeftArrow ? -1 : Event.current.keyCode == KeyCode.RightArrow ? 1 : 0; | ||
if (directionY != 0 || directionX != 0) | ||
{ | ||
if (directionY < 0 || directionY < 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should be directionX on the second condition
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch!
{ | ||
int directionY = Event.current.keyCode == KeyCode.UpArrow ? -1 : Event.current.keyCode == KeyCode.DownArrow ? 1 : 0; | ||
int directionX = Event.current.keyCode == KeyCode.LeftArrow ? -1 : Event.current.keyCode == KeyCode.RightArrow ? 1 : 0; | ||
if (directionY != 0 || directionX != 0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm a bit confused by this set of if statements. I don't fully understand the functionality here, so that just might be my confusion, but it seems like a set of nested ifs with two different variables shouldn't just be an or?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are right, the wrapping if statement is redundant.
The local and remote trees are two separate tree controls.
This code lets you travel from one tree control to the other via keystroke if the scenario is correct.
return idx; | ||
} | ||
|
||
private bool HandleInput(Rect rect, TreeNode currentNode, int index, Action<TreeNode> singleClick = null, Action<TreeNode> doubleClick = null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So are singleClick and doubleClick what gets displayed if a node gets single or double clicked?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Almost... they are the function delegates that get called when a node gets single or double clicked
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thanks!
Note: This branch targets
enhancements/branches-view-rollup
#464This PR introduces a tree view control to display data in a tree view in a performant way, since the layouting system can't really handle a lot of the data we throw into it.
The approach here is to separate the data from the UI - the data gets put into a data structure (with whatever necessary processing), and then passed into the UI structure that will render it. Both can be cached separately and independently.
This tries to solve a number of problems:
Missing in this PR
This is currently applied to the branches view but the Treeview control should be generic enough to be applied to the changes view as well, hopefully fixing the performance problems there.