Skip to content
This repository was archived by the owner on Dec 5, 2024. It is now read-only.

Commit fb9ed25

Browse files
Merge pull request #518 from github-for-unity/fixes/changes-view-tree-focus
Clearing up focus issues
2 parents 756b7e5 + 3f8ccf9 commit fb9ed25

File tree

5 files changed

+131
-31
lines changed

5 files changed

+131
-31
lines changed

src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Styles.cs

Lines changed: 47 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -874,35 +874,68 @@ public static GUIStyle TreeNode
874874
treeNode = new GUIStyle(GUI.skin.label);
875875
treeNode.name = "Custom TreeNode";
876876

877-
var color = new Color(62f / 255f, 125f / 255f, 231f / 255f);
878-
var texture = Utility.GetTextureFromColor(color);
879-
treeNode.focused.background = texture;
880-
treeNode.onFocused.background = texture;
877+
var greyTexture = Utility.GetTextureFromColor(Color.gray);
878+
879+
treeNode.focused.background = greyTexture;
881880
treeNode.focused.textColor = Color.white;
882-
treeNode.onFocused.textColor = Color.white;
883881
}
884882

885883
return treeNode;
886884
}
887885
}
888886

889-
private static GUIStyle treeNodeActive;
890-
public static GUIStyle TreeNodeActive
887+
private static GUIStyle activeTreeNode;
888+
public static GUIStyle ActiveTreeNode
889+
{
890+
get
891+
{
892+
if (activeTreeNode == null)
893+
{
894+
activeTreeNode = new GUIStyle(TreeNode);
895+
activeTreeNode.name = "Custom Active TreeNode";
896+
897+
activeTreeNode.fontStyle = FontStyle.Bold;
898+
}
899+
900+
return activeTreeNode;
901+
}
902+
}
903+
904+
private static GUIStyle focusedTreeNode;
905+
public static GUIStyle FocusedTreeNode
891906
{
892907
get
893908
{
894-
if (treeNodeActive == null)
909+
if (focusedTreeNode == null)
895910
{
896-
treeNodeActive = new GUIStyle(TreeNode);
897-
treeNodeActive.name = "Custom TreeNode Active";
898-
treeNodeActive.fontStyle = FontStyle.Bold;
899-
treeNodeActive.focused.textColor = Color.white;
900-
treeNodeActive.active.textColor = Color.white;
911+
focusedTreeNode = new GUIStyle(TreeNode);
912+
focusedTreeNode.name = "Custom Focused TreeNode";
913+
914+
var blueColor = new Color(62f / 255f, 125f / 255f, 231f / 255f);
915+
var blueTexture = Utility.GetTextureFromColor(blueColor);
916+
917+
focusedTreeNode.focused.background = blueTexture;
901918
}
902919

903-
return treeNodeActive;
920+
return focusedTreeNode;
904921
}
905922
}
906923

924+
private static GUIStyle focusedActiveTreeNode;
925+
public static GUIStyle FocusedActiveTreeNode
926+
{
927+
get
928+
{
929+
if (focusedActiveTreeNode == null)
930+
{
931+
focusedActiveTreeNode = new GUIStyle(FocusedTreeNode);
932+
focusedActiveTreeNode.name = "Custom Focused Active TreeNode";
933+
934+
focusedActiveTreeNode.fontStyle = FontStyle.Bold;
935+
}
936+
937+
return focusedActiveTreeNode;
938+
}
939+
}
907940
}
908941
}

src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ public override void InitializeView(IView parent)
6262
public override void OnEnable()
6363
{
6464
base.OnEnable();
65-
UpdateTreeIcons();
65+
TreeOnEnable();
6666
AttachHandlers(Repository);
6767
Repository.CheckLocalAndRemoteBranchListChangedEvent(lastLocalAndRemoteBranchListChangedEvent);
6868
}
@@ -79,6 +79,12 @@ public override void OnDataUpdate()
7979
MaybeUpdateData();
8080
}
8181

82+
public override void OnSelectionChange()
83+
{
84+
base.OnSelectionChange();
85+
Redraw();
86+
}
87+
8288
private void RepositoryOnLocalAndRemoteBranchListChanged(CacheUpdateEvent cacheUpdateEvent)
8389
{
8490
if (!lastLocalAndRemoteBranchListChangedEvent.Equals(cacheUpdateEvent))
@@ -158,7 +164,7 @@ private void BuildTree()
158164
treeRemotes.Title = RemoteTitle;
159165
treeRemotes.IsRemote = true;
160166

161-
UpdateTreeIcons();
167+
TreeOnEnable();
162168
}
163169

164170
localBranches.Sort(CompareBranches);
@@ -169,15 +175,17 @@ private void BuildTree()
169175
Redraw();
170176
}
171177

172-
private void UpdateTreeIcons()
178+
private void TreeOnEnable()
173179
{
174180
if (treeLocals != null)
175181
{
182+
treeLocals.OnEnable();
176183
treeLocals.UpdateIcons(Styles.ActiveBranchIcon, Styles.BranchIcon, Styles.FolderIcon, Styles.GlobeIcon);
177184
}
178185

179186
if (treeRemotes != null)
180187
{
188+
treeRemotes.OnEnable();
181189
treeRemotes.UpdateIcons(Styles.ActiveBranchIcon, Styles.BranchIcon, Styles.FolderIcon, Styles.GlobeIcon);
182190
}
183191
}
@@ -301,11 +309,15 @@ private void OnTreeGUI(Rect rect)
301309
{
302310
treeLocals.FolderStyle = Styles.Foldout;
303311
treeLocals.TreeNodeStyle = Styles.TreeNode;
304-
treeLocals.ActiveTreeNodeStyle = Styles.TreeNodeActive;
312+
treeLocals.ActiveTreeNodeStyle = Styles.ActiveTreeNode;
313+
treeLocals.FocusedTreeNodeStyle = Styles.FocusedTreeNode;
314+
treeLocals.FocusedActiveTreeNodeStyle = Styles.FocusedActiveTreeNode;
305315

306316
treeRemotes.FolderStyle = Styles.Foldout;
307317
treeRemotes.TreeNodeStyle = Styles.TreeNode;
308-
treeRemotes.ActiveTreeNodeStyle = Styles.TreeNodeActive;
318+
treeRemotes.ActiveTreeNodeStyle = Styles.ActiveTreeNode;
319+
treeRemotes.FocusedTreeNodeStyle = Styles.FocusedTreeNode;
320+
treeRemotes.FocusedActiveTreeNodeStyle = Styles.FocusedActiveTreeNode;
309321

310322
var treeHadFocus = treeLocals.SelectedNode != null;
311323

src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesTreeControl.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,10 @@ public override ChangesTreeNode SelectedNode
7878
set
7979
{
8080
selectedNode = value;
81+
if (value != null && selectionObject)
82+
{
83+
Selection.activeObject = selectionObject;
84+
}
8185
}
8286
}
8387

src/UnityExtension/Assets/Editor/GitHub.Unity/UI/ChangesView.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class ChangesView : Subview
3535
public override void OnEnable()
3636
{
3737
base.OnEnable();
38-
UpdateTreeIcons();
38+
TreeOnEnable();
3939
AttachHandlers(Repository);
4040
Repository.CheckCurrentBranchChangedEvent(lastCurrentBranchChangedEvent);
4141
Repository.CheckStatusEntriesChangedEvent(lastStatusEntriesChangedEvent);
@@ -94,14 +94,22 @@ public override void OnGUI()
9494
OnCommitDetailsAreaGUI();
9595
}
9696

97+
public override void OnSelectionChange()
98+
{
99+
base.OnSelectionChange();
100+
Redraw();
101+
}
102+
97103
private void OnTreeGUI(Rect rect)
98104
{
99105
var initialRect = rect;
100106
if (treeChanges != null)
101107
{
102108
treeChanges.FolderStyle = Styles.Foldout;
103109
treeChanges.TreeNodeStyle = Styles.TreeNode;
104-
treeChanges.ActiveTreeNodeStyle = Styles.TreeNodeActive;
110+
treeChanges.ActiveTreeNodeStyle = Styles.ActiveTreeNode;
111+
treeChanges.FocusedTreeNodeStyle = Styles.FocusedTreeNode;
112+
treeChanges.FocusedActiveTreeNodeStyle = Styles.FocusedActiveTreeNode;
105113

106114
rect = treeChanges.Render(initialRect, rect, scroll,
107115
node => { },
@@ -192,17 +200,18 @@ private void BuildTree()
192200
treeChanges.IsCheckable = true;
193201
treeChanges.PathSeparator = Environment.FileSystem.DirectorySeparatorChar.ToString();
194202

195-
UpdateTreeIcons();
203+
TreeOnEnable();
196204
}
197205

198206
treeChanges.Load(gitStatusEntries.Select(entry => new GitStatusEntryTreeData(entry)));
199207
Redraw();
200208
}
201209

202-
private void UpdateTreeIcons()
210+
private void TreeOnEnable()
203211
{
204212
if (treeChanges != null)
205213
{
214+
treeChanges.OnEnable();
206215
treeChanges.UpdateIcons(Styles.FolderIcon);
207216
}
208217
}

src/UnityExtension/Assets/Editor/GitHub.Unity/UI/TreeControl.cs

Lines changed: 50 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ namespace GitHub.Unity
99
[Serializable]
1010
public class TreeNodeDictionary : SerializableDictionary<string, TreeNode> { }
1111

12+
public class TreeSelection : ScriptableObject { }
13+
1214
[Serializable]
1315
public abstract class Tree<TNode, TData>: TreeBase<TNode, TData>
1416
where TNode : TreeNode
@@ -20,16 +22,41 @@ public abstract class Tree<TNode, TData>: TreeBase<TNode, TData>
2022
[NonSerialized] public GUIStyle FolderStyle;
2123
[NonSerialized] public GUIStyle TreeNodeStyle;
2224
[NonSerialized] public GUIStyle ActiveTreeNodeStyle;
25+
[NonSerialized] public GUIStyle FocusedTreeNodeStyle;
26+
[NonSerialized] public GUIStyle FocusedActiveTreeNodeStyle;
2327

2428
[NonSerialized] private Stack<bool> indents = new Stack<bool>();
2529
[NonSerialized] private Action<TNode> rightClickNextRender;
2630
[NonSerialized] private TNode rightClickNextRenderNode;
2731

32+
[NonSerialized] private int controlId;
33+
[NonSerialized] protected TreeSelection selectionObject;
34+
2835
public bool IsInitialized { get { return Nodes != null && Nodes.Count > 0 && !String.IsNullOrEmpty(Nodes[0].Path); } }
2936
public bool RequiresRepaint { get; private set; }
3037

3138
public Rect Render(Rect containingRect, Rect rect, Vector2 scroll, Action<TNode> singleClick = null, Action<TNode> doubleClick = null, Action<TNode> rightClick = null)
3239
{
40+
if (Selection.activeObject != selectionObject)
41+
{
42+
SelectedNode = null;
43+
}
44+
45+
controlId = GUIUtility.GetControlID(FocusType.Keyboard);
46+
var treeHasFocus = GUIUtility.keyboardControl == controlId;
47+
48+
if (!Nodes.Any())
49+
return new Rect(0f, rect.y, 0f, 0f);
50+
51+
var treeNodeStyle = TreeNodeStyle;
52+
var activeTreeNodeStyle = ActiveTreeNodeStyle;
53+
54+
if (treeHasFocus)
55+
{
56+
treeNodeStyle = FocusedTreeNodeStyle;
57+
activeTreeNodeStyle = FocusedActiveTreeNodeStyle;
58+
}
59+
3360
if (Event.current.type != EventType.Repaint)
3461
{
3562
if (rightClickNextRender != null)
@@ -56,7 +83,8 @@ public Rect Render(Rect containingRect, Rect rect, Vector2 scroll, Action<TNode>
5683
var titleDisplay = !(rect.y > endDisplay || rect.yMax < startDisplay);
5784
if (titleDisplay)
5885
{
59-
renderResult = titleNode.Render(rect, Styles.TreeIndentation, SelectedNode == titleNode, FolderStyle, TreeNodeStyle, ActiveTreeNodeStyle);
86+
var isSelected = SelectedNode == titleNode;
87+
renderResult = titleNode.Render(rect, Styles.TreeIndentation, isSelected, FolderStyle, treeNodeStyle, activeTreeNodeStyle);
6088
}
6189

6290
if (renderResult == TreeNodeRenderResult.VisibilityChange)
@@ -89,7 +117,8 @@ public Rect Render(Rect containingRect, Rect rect, Vector2 scroll, Action<TNode>
89117
var display = !(rect.y > endDisplay || rect.yMax < startDisplay);
90118
if (display)
91119
{
92-
renderResult = node.Render(rect, Styles.TreeIndentation, SelectedNode == node, FolderStyle, TreeNodeStyle, ActiveTreeNodeStyle);
120+
var isSelected = SelectedNode == node;
121+
renderResult = node.Render(rect, Styles.TreeIndentation, isSelected, FolderStyle, treeNodeStyle, activeTreeNodeStyle);
93122
}
94123

95124
if (renderResult == TreeNodeRenderResult.VisibilityChange)
@@ -160,6 +189,8 @@ private bool HandleInput(Rect rect, TNode currentNode, int index, Action<TNode>
160189
if (Event.current.type == EventType.MouseDown && clickRect.Contains(Event.current.mousePosition))
161190
{
162191
Event.current.Use();
192+
GUIUtility.keyboardControl = controlId;
193+
163194
SelectedNode = currentNode;
164195
requiresRepaint = true;
165196
var clickCount = Event.current.clickCount;
@@ -181,7 +212,7 @@ private bool HandleInput(Rect rect, TNode currentNode, int index, Action<TNode>
181212
}
182213

183214
// Keyboard navigation if this child is the current selection
184-
if (currentNode == SelectedNode && Event.current.type == EventType.KeyDown)
215+
if (GUIUtility.keyboardControl == controlId && currentNode == SelectedNode && Event.current.type == EventType.KeyDown)
185216
{
186217
int directionY = Event.current.keyCode == KeyCode.UpArrow ? -1 : Event.current.keyCode == KeyCode.DownArrow ? 1 : 0;
187218
int directionX = Event.current.keyCode == KeyCode.LeftArrow ? -1 : Event.current.keyCode == KeyCode.RightArrow ? 1 : 0;
@@ -287,14 +318,21 @@ private void Unindent()
287318
indents.Pop();
288319
}
289320

290-
291321
protected void LoadNodeIcons()
292322
{
293323
foreach (var treeNode in Nodes)
294324
{
295325
SetNodeIcon(treeNode);
296326
}
297327
}
328+
329+
public void OnEnable()
330+
{
331+
if (!selectionObject)
332+
{
333+
selectionObject = ScriptableObject.CreateInstance<TreeSelection>();
334+
}
335+
}
298336
}
299337

300338
[Serializable]
@@ -406,9 +444,11 @@ public TreeNodeRenderResult Render(Rect rect, float indentation, bool isSelected
406444
var iconRect = new Rect(nodeStartX, nodeRect.y, fillRect.width - nodeStartX, nodeRect.height);
407445
var statusRect = new Rect(iconRect.x + 6, iconRect.yMax - 9, 9, 9);
408446

447+
var contentStyle = IsActive ? activeNodeStyle : nodeStyle;
448+
409449
if (Event.current.type == EventType.repaint)
410450
{
411-
nodeStyle.Draw(fillRect, GUIContent.none, false, false, false, isSelected);
451+
contentStyle.Draw(fillRect, GUIContent.none, false, false, false, isSelected);
412452
}
413453

414454
var styleOn = false;
@@ -455,11 +495,9 @@ public TreeNodeRenderResult Render(Rect rect, float indentation, bool isSelected
455495
}
456496
}
457497

458-
var contentStyle = IsActive ? activeNodeStyle : nodeStyle;
459-
460498
if (Event.current.type == EventType.repaint)
461499
{
462-
contentStyle.Draw(iconRect, content, false, false, styleOn, isSelected);
500+
contentStyle.Draw(iconRect, content, false, false, false, isSelected);
463501
}
464502

465503
if (IconBadge != null)
@@ -531,6 +569,10 @@ public override TreeNode SelectedNode
531569
set
532570
{
533571
selectedNode = value;
572+
if (value != null && selectionObject)
573+
{
574+
Selection.activeObject = selectionObject;
575+
}
534576
}
535577
}
536578

0 commit comments

Comments
 (0)