From a4847295c58914cef35e705397d7835201b65b6f Mon Sep 17 00:00:00 2001 From: Andreia Gaita Date: Mon, 3 Jul 2017 20:33:36 +0200 Subject: [PATCH 1/5] Custom treeview control and cache manager --- .../Application/ApplicationManagerBase.cs | 8 + .../Application/IApplicationManager.cs | 1 + src/GitHub.Api/Cache/CacheManager.cs | 46 + src/GitHub.Api/GitHub.Api.csproj | 1 + .../GitHub.Unity/IconsAndLogos/globe.png | 3 + .../GitHub.Unity/IconsAndLogos/globe@2x.png | 3 + .../Assets/Editor/GitHub.Unity/Misc/Styles.cs | 79 +- .../Editor/GitHub.Unity/Misc/Utility.cs | 10 +- .../Services/AuthenticationService.cs | 1 - .../UI/AuthenticationWindow.cs.meta | 12 - .../Editor/GitHub.Unity/UI/BranchesView.cs | 1047 +++++++++-------- 11 files changed, 716 insertions(+), 495 deletions(-) create mode 100644 src/GitHub.Api/Cache/CacheManager.cs create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/globe.png create mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/globe@2x.png delete mode 100644 src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationWindow.cs.meta diff --git a/src/GitHub.Api/Application/ApplicationManagerBase.cs b/src/GitHub.Api/Application/ApplicationManagerBase.cs index 002b61122..0135a7d95 100644 --- a/src/GitHub.Api/Application/ApplicationManagerBase.cs +++ b/src/GitHub.Api/Application/ApplicationManagerBase.cs @@ -12,6 +12,7 @@ abstract class ApplicationManagerBase : IApplicationManager protected static ILogging Logger { get; } = Logging.GetLogger(); private RepositoryManager repositoryManager; + private IBranchCache branchCache; public ApplicationManagerBase(SynchronizationContext synchronizationContext) { @@ -21,6 +22,7 @@ public ApplicationManagerBase(SynchronizationContext synchronizationContext) UIScheduler = TaskScheduler.FromCurrentSynchronizationContext(); ThreadingHelper.MainThreadScheduler = UIScheduler; TaskManager = new TaskManager(UIScheduler); + CacheManager = new CacheManager(); } protected void Initialize() @@ -73,6 +75,11 @@ private async Task SetupGit() } + public void SetupCache(IBranchCache bcache) + { + branchCache = bcache; + } + public ITask InitializeRepository() { Logger.Trace("Running Repository Initialize"); @@ -207,6 +214,7 @@ public void Dispose() public ISettings LocalSettings { get; protected set; } public ISettings SystemSettings { get; protected set; } public ISettings UserSettings { get; protected set; } + public CacheManager CacheManager { get; private set; } public IUsageTracker UsageTracker { get; protected set; } protected TaskScheduler UIScheduler { get; private set; } diff --git a/src/GitHub.Api/Application/IApplicationManager.cs b/src/GitHub.Api/Application/IApplicationManager.cs index a8b086c6f..a46ced88c 100644 --- a/src/GitHub.Api/Application/IApplicationManager.cs +++ b/src/GitHub.Api/Application/IApplicationManager.cs @@ -15,6 +15,7 @@ interface IApplicationManager : IDisposable ISettings LocalSettings { get; } ISettings UserSettings { get; } ITaskManager TaskManager { get; } + CacheManager CacheManager { get; } IGitClient GitClient { get; } IUsageTracker UsageTracker { get; } diff --git a/src/GitHub.Api/Cache/CacheManager.cs b/src/GitHub.Api/Cache/CacheManager.cs new file mode 100644 index 000000000..11e038756 --- /dev/null +++ b/src/GitHub.Api/Cache/CacheManager.cs @@ -0,0 +1,46 @@ +using System; +using System.Linq; + +namespace GitHub.Unity +{ + class CacheManager + { + private IBranchCache branchCache; + public IBranchCache BranchCache + { + get { return branchCache; } + set + { + if (branchCache == null) + branchCache = value; + } + } + + private Action onLocalBranchListChanged; + + public void SetupCache(IBranchCache branchCache, IRepository repository) + { + if (repository == null) + return; + + BranchCache = branchCache; + UpdateCache(repository); + if (onLocalBranchListChanged != null) + repository.OnLocalBranchListChanged -= onLocalBranchListChanged; + onLocalBranchListChanged = () => + { + if (!ThreadingHelper.InUIThread) + new ActionTask(TaskManager.Instance.Token, () => UpdateCache(repository)) { Affinity = TaskAffinity.UI }.Start(); + else + UpdateCache(repository); + }; + repository.OnLocalBranchListChanged += onLocalBranchListChanged; + } + + private void UpdateCache(IRepository repository) + { + BranchCache.LocalBranches = repository.LocalBranches.ToList(); + BranchCache.RemoteBranches = repository.RemoteBranches.ToList(); + } + } +} \ No newline at end of file diff --git a/src/GitHub.Api/GitHub.Api.csproj b/src/GitHub.Api/GitHub.Api.csproj index 388b9cbab..a84a695cc 100644 --- a/src/GitHub.Api/GitHub.Api.csproj +++ b/src/GitHub.Api/GitHub.Api.csproj @@ -107,6 +107,7 @@ + diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/globe.png b/src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/globe.png new file mode 100644 index 000000000..0b1353981 --- /dev/null +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/globe.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b65bf8e330ede5edc0ae8d620a01f7003fbfdcd1053667c016a103b8ad49a934 +size 594 diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/globe@2x.png b/src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/globe@2x.png new file mode 100644 index 000000000..792045838 --- /dev/null +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/IconsAndLogos/globe@2x.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3051c3d5ba2726bf3b9877a44f41ec7f3a68a79afe40bf7fde0f65db1a542b18 +size 1318 diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Styles.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Styles.cs index f2ec9bf92..145a316a4 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Styles.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Styles.cs @@ -26,13 +26,14 @@ class Styles MinCommitTreePadding = 20f, FoldoutWidth = 11f, FoldoutIndentation = -2f, + TreePadding = 12f, TreeIndentation = 12f, TreeRootIndentation = -5f, TreeVerticalSpacing = 3f, CommitIconSize = 16f, CommitIconHorizontalPadding = -5f, BranchListIndentation = 20f, - BranchListSeperation = 15f, + BranchListSeparation = 15f, RemotesTotalHorizontalMargin = 37f, RemotesNameRatio = .2f, RemotesUserRatio = .2f, @@ -212,7 +213,7 @@ public static GUIStyle Label label = new GUIStyle(GUI.skin.label); label.name = "CustomLabel"; - var hierarchyStyle = GUI.skin.FindStyle("PR Label"); + GUIStyle hierarchyStyle = GUI.skin.FindStyle("PR Label"); label.onNormal.background = hierarchyStyle.onNormal.background; label.onNormal.textColor = hierarchyStyle.onNormal.textColor; label.onFocused.background = hierarchyStyle.onFocused.background; @@ -815,5 +816,79 @@ public static Texture2D DropdownListIcon return dropdownListIcon; } } + + private static Texture2D rootFolderIcon; + public static Texture2D RootFolderIcon + { + get + { + if (rootFolderIcon == null) + { + rootFolderIcon = Utility.GetIcon("globe.png", "globe@2x.png"); + } + return rootFolderIcon; + } + } + + private static GUIStyle foldout; + public static GUIStyle Foldout + { + get + { + if (foldout == null) + { + foldout = new GUIStyle(EditorStyles.foldout); + foldout.name = "CustomFoldout"; + + foldout.focused.textColor = Color.white; + foldout.onFocused.textColor = Color.white; + foldout.focused.background = foldout.active.background; + foldout.onFocused.background = foldout.onActive.background; + } + + return foldout; + } + } + + private static GUIStyle treeNode; + public static GUIStyle TreeNode + { + get + { + if (treeNode == null) + { + treeNode = new GUIStyle(GUI.skin.label); + treeNode.name = "Custom TreeNode"; + + var color = new Color(62f / 255f, 125f / 255f, 231f / 255f); + var texture = Utility.CreateTextureFromColor(color); + treeNode.focused.background = texture; + treeNode.onFocused.background = texture; + treeNode.focused.textColor = Color.white; + treeNode.onFocused.textColor = Color.white; + } + + return treeNode; + } + } + + private static GUIStyle treeNodeActive; + public static GUIStyle TreeNodeActive + { + get + { + if (treeNodeActive == null) + { + treeNodeActive = new GUIStyle(TreeNode); + treeNodeActive.name = "Custom TreeNode Active"; + treeNodeActive.fontStyle = FontStyle.Bold; + treeNodeActive.focused.textColor = Color.white; + treeNodeActive.active.textColor = Color.white; + } + + return treeNodeActive; + } + } + } } diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs index ab7df1acc..bee54d6e9 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs @@ -87,12 +87,10 @@ public static Texture2D GetIcon(string filename, string filename2x = "") public static Texture2D CreateTextureFromColor(Color color) { - Texture2D backgroundTexture = new Texture2D(1, 1); - Color c = color; - backgroundTexture.SetPixel(1, 1, c); - backgroundTexture.Apply(); - - return backgroundTexture; + var texture = new Texture2D(1, 1); + texture.SetPixel(0, 0, color); + texture.Apply(); + return texture; } public static string GitInstallPath diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Services/AuthenticationService.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Services/AuthenticationService.cs index c8564cfda..3d81553cf 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Services/AuthenticationService.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Services/AuthenticationService.cs @@ -1,5 +1,4 @@ using System; -using GitHub.Unity; namespace GitHub.Unity { diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationWindow.cs.meta b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationWindow.cs.meta deleted file mode 100644 index c4f091563..000000000 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/AuthenticationWindow.cs.meta +++ /dev/null @@ -1,12 +0,0 @@ -fileFormatVersion: 2 -guid: e2d6e39e204f64948889a54be539bbac -timeCreated: 1487020974 -licenseType: Pro -MonoImporter: - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs index 015aa1244..44f6c0c9b 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Linq; using GitHub.Unity.Helpers; @@ -35,29 +36,24 @@ class BranchesView : Subview private const string DeleteBranchButton = "Delete"; private const string CancelButtonLabel = "Cancel"; - private bool showLocalBranches = true; - private bool showRemoteBranches = true; - - [NonSerialized] private List favorites = new List(); [NonSerialized] private int listID = -1; - [NonSerialized] private List newLocalBranches; - [NonSerialized] private BranchTreeNode newNodeSelection; [NonSerialized] private BranchesMode targetMode; [NonSerialized] private bool favoritesHasChanged; + [NonSerialized] private List favoritesList; + [NonSerialized] private bool disableDelete; - [SerializeField] private BranchTreeNode activeBranchNode; - [SerializeField] private BranchTreeNode localRoot; + [SerializeField] private Tree treeLocals = new Tree(); + [SerializeField] private Tree treeRemotes = new Tree(); + [SerializeField] private Tree treefFavorites = new Tree(); [SerializeField] private BranchesMode mode = BranchesMode.Default; [SerializeField] private string newBranchName; - [SerializeField] private List remotes = new List(); [SerializeField] private Vector2 scroll; - [SerializeField] private BranchTreeNode selectedNode; - private List favoritesList; public override void InitializeView(IView parent) { base.InitializeView(parent); targetMode = mode; + Manager.CacheManager.SetupCache(BranchCache.Instance, Environment.Repository); } public override void OnEnable() @@ -81,13 +77,21 @@ public override void OnDataUpdate() private void MaybeUpdateData() { + if (treeLocals == null || !treeLocals.IsInitialized) + { + BuildTree(BranchCache.Instance.LocalBranches, BranchCache.Instance.RemoteBranches); + } + if (favoritesHasChanged) { favoritesList = Manager.LocalSettings.Get(FavoritesSetting, new List()); favoritesHasChanged = false; } + + disableDelete = treeLocals.SelectedNode == null || treeLocals.SelectedNode.IsFolder || treeLocals.SelectedNode.IsActive; } + public override void OnRepositoryChanged(IRepository oldRepository) { base.OnRepositoryChanged(oldRepository); @@ -95,12 +99,23 @@ public override void OnRepositoryChanged(IRepository oldRepository) AttachHandlers(Repository); } + public override void Refresh() + { + base.Refresh(); + RefreshBranchList(); + } + + public override void OnGUI() + { + Render(); + } + private void AttachHandlers(IRepository repository) { if (repository == null) return; - repository.OnLocalBranchListChanged += RunRefreshEmbeddedOnMainThread; + repository.OnLocalBranchListChanged += RunRefreshOnMainThread; repository.OnActiveBranchChanged += HandleRepositoryBranchChangeEvent; repository.OnActiveRemoteChanged += HandleRepositoryBranchChangeEvent; } @@ -109,46 +124,33 @@ private void DetachHandlers(IRepository repository) { if (repository == null) return; - repository.OnLocalBranchListChanged -= RunRefreshEmbeddedOnMainThread; + repository.OnLocalBranchListChanged -= RunRefreshOnMainThread; repository.OnActiveBranchChanged -= HandleRepositoryBranchChangeEvent; repository.OnActiveRemoteChanged -= HandleRepositoryBranchChangeEvent; } - private void RunRefreshEmbeddedOnMainThread() + private void RunRefreshOnMainThread() { - new ActionTask(TaskManager.Token, _ => RefreshEmbedded()) - .ScheduleUI(TaskManager); + new ActionTask(TaskManager.Token, RefreshBranchList) { Affinity = TaskAffinity.UI }.Start(); } private void HandleRepositoryBranchChangeEvent(string obj) { - RunRefreshEmbeddedOnMainThread(); - } - - public override void Refresh() - { - base.Refresh(); - - RefreshEmbedded(); - } - - public void RefreshEmbedded() - { - if (Repository == null) - return; - - OnLocalBranchesUpdate(Repository.LocalBranches); - OnRemoteBranchesUpdate(Repository.RemoteBranches); + RunRefreshOnMainThread(); } - public override void OnGUI() + private void RefreshBranchList() { - OnEmbeddedGUI(); + var localBranches = BranchCache.Instance.LocalBranches; + localBranches.Sort(CompareBranches); + var remoteBranches = BranchCache.Instance.RemoteBranches; + remoteBranches.Sort(CompareBranches); + BuildTree(localBranches, remoteBranches); } - public void OnEmbeddedGUI() + private void Render() { - scroll = GUILayout.BeginScrollView(scroll); + scroll = GUILayout.BeginScrollView(scroll, false, true); { listID = GUIUtility.GetControlID(FocusType.Keyboard); @@ -158,310 +160,44 @@ public void OnEmbeddedGUI() } GUILayout.EndHorizontal(); - GUILayout.BeginVertical(Styles.CommitFileAreaStyle); - { - // Favorites list - if (favorites.Count > 0) - { - GUILayout.Label(FavoritesTitle); - GUILayout.BeginHorizontal(); - { - GUILayout.BeginVertical(); - { - for (var index = 0; index < favorites.Count; ++index) - { - OnTreeNodeGUI(favorites[index]); - } - } - - GUILayout.EndVertical(); - } - - GUILayout.EndHorizontal(); - - GUILayout.Space(Styles.BranchListSeperation); - } - - // Local branches and "create branch" button - showLocalBranches = EditorGUILayout.Foldout(showLocalBranches, LocalTitle); - if (showLocalBranches) - { - GUILayout.BeginHorizontal(); - { - GUILayout.BeginVertical(); - { - OnTreeNodeChildrenGUI(localRoot); - } - GUILayout.EndVertical(); - } - GUILayout.EndHorizontal(); - } - - // Remotes - showRemoteBranches = EditorGUILayout.Foldout(showRemoteBranches, RemoteTitle); - if (showRemoteBranches) - { - GUILayout.BeginHorizontal(); - { - GUILayout.BeginVertical(); - for (var index = 0; index < remotes.Count; ++index) - { - var remote = remotes[index]; - GUILayout.Label(new GUIContent(remote.Name, Styles.FolderIcon), GUILayout.MaxHeight(EditorGUIUtility.singleLineHeight)); - - // Branches of the remote - GUILayout.BeginHorizontal(); - { - GUILayout.Space(Styles.TreeIndentation); - GUILayout.BeginVertical(); - { - OnTreeNodeChildrenGUI(remote.Root); - } - GUILayout.EndVertical(); - } - GUILayout.EndHorizontal(); - - GUILayout.Space(Styles.BranchListSeperation); - } - - GUILayout.EndVertical(); - } - GUILayout.EndHorizontal(); - } - - GUILayout.FlexibleSpace(); - } - GUILayout.EndVertical(); + var rect = GUILayoutUtility.GetLastRect(); + OnTreeGUI(new Rect(0f, rect.height + Styles.CommitAreaPadding, Position.width, Position.height - rect.height + Styles.CommitAreaPadding)); } - GUILayout.EndScrollView(); - - if (Event.current.type == EventType.Repaint) - { - // Effectuating selection - if (newNodeSelection != null) - { - selectedNode = newNodeSelection; - newNodeSelection = null; - GUIUtility.keyboardControl = listID; - Redraw(); - } - - // Effectuating mode switch - if (mode != targetMode) - { - mode = targetMode; - - if (mode == BranchesMode.Create) - { - selectedNode = activeBranchNode; - } - - Redraw(); - } - } - } - - private int CompareBranches(GitBranch a, GitBranch b) - { - if (IsFavorite(a.Name)) - { - return -1; - } - - if (IsFavorite(b.Name)) - { - return 1; - } - - if (a.Name.Equals("master")) - { - return -1; - } - - if (b.Name.Equals("master")) - { - return 1; - } - - return 0; } - private bool IsFavorite(string branchName) + private void BuildTree(List localBranches, List remoteBranches) { - return !String.IsNullOrEmpty(branchName) && favoritesList.Contains(branchName); - } - - private void OnLocalBranchesUpdate(IEnumerable list) - { - newLocalBranches = new List(list); - } - - private void OnRemoteBranchesUpdate(IEnumerable list) - { - BuildTree(newLocalBranches, list); - newLocalBranches.Clear(); - } - - private void BuildTree(IEnumerable local, IEnumerable remote) - { - //Clear the selected node - selectedNode = null; - - // Sort - var localBranches = new List(local); - var remoteBranches = new List(remote); localBranches.Sort(CompareBranches); remoteBranches.Sort(CompareBranches); - - // Prepare for tracking - var tracking = new List>(); - var localBranchNodes = new List(); - - // Prepare for updated favorites listing - favorites.Clear(); - - // Just build directly on the local root, keep track of active branch - localRoot = new BranchTreeNode("", NodeType.Folder, false); - for (var index = 0; index < localBranches.Count; ++index) - { - var branch = localBranches[index]; - var node = new BranchTreeNode(branch.Name, NodeType.LocalBranch, branch.IsActive); - localBranchNodes.Add(node); - - // Keep active node for quick reference - if (branch.IsActive) - { - activeBranchNode = node; - } - - // Add to tracking - if (!string.IsNullOrEmpty(branch.Tracking)) - { - var trackingIndex = !remoteBranches.Any() - ? -1 - : Enumerable.Range(0, remoteBranches.Count).FirstOrDefault(i => remoteBranches[i].Name.Equals(branch.Tracking)); - - if (trackingIndex > -1) - { - tracking.Add(new KeyValuePair(index, trackingIndex)); - } - } - - // Add to favorites - if (favoritesList.Contains(branch.Name)) - { - favorites.Add(node); - } - - // Build into tree - BuildTree(localRoot, node); - } - - // Maintain list of remotes before building their roots, ignoring active state - remotes.Clear(); - for (var index = 0; index < remoteBranches.Count; ++index) - { - var branch = remoteBranches[index]; - - // Remote name is always the first level - var remoteName = branch.Name.Substring(0, branch.Name.IndexOf('/')); - - // Get or create this remote - var remoteIndex = Enumerable.Range(1, remotes.Count + 1) - .FirstOrDefault(i => remotes.Count > i - 1 && remotes[i - 1].Name.Equals(remoteName)) - 1; - if (remoteIndex < 0) - { - remotes.Add(new Remote { Name = remoteName, Root = new BranchTreeNode("", NodeType.Folder, false) }); - remoteIndex = remotes.Count - 1; - } - - // Create the branch - var node = new BranchTreeNode(branch.Name, NodeType.RemoteBranch, false) { - Label = branch.Name.Substring(remoteName.Length + 1) - }; - - // Establish tracking link - for (var trackingIndex = 0; trackingIndex < tracking.Count; ++trackingIndex) - { - var pair = tracking[trackingIndex]; - - if (pair.Value == index) - { - localBranchNodes[pair.Key].Tracking = node; - } - } - - // Add to favorites - if (favoritesList.Contains(branch.Name)) - { - favorites.Add(node); - } - - // Build on the root of the remote, just like with locals - BuildTree(remotes[remoteIndex].Root, node); - } - + treeLocals = new Tree(); + treeLocals.ActiveNodeIcon = Styles.ActiveBranchIcon; + treeLocals.NodeIcon = Styles.BranchIcon; + treeLocals.RootFolderIcon = Styles.RootFolderIcon; + treeLocals.FolderIcon = Styles.FolderIcon; + + treeRemotes = new Tree(); + treeRemotes.ActiveNodeIcon = Styles.ActiveBranchIcon; + treeRemotes.NodeIcon = Styles.BranchIcon; + treeRemotes.RootFolderIcon = Styles.RootFolderIcon; + treeRemotes.FolderIcon = Styles.FolderIcon; + + treeLocals.Load(localBranches.Cast(), LocalTitle); + treeRemotes.Load(remoteBranches.Cast(), RemoteTitle); Redraw(); } - private void BuildTree(BranchTreeNode parent, BranchTreeNode child) - { - var firstSplit = child.Label.IndexOf('/'); - - // No nesting needed here, this is just a straight add - if (firstSplit < 0) - { - parent.Children.Add(child); - return; - } - - // Get or create the next folder level - var folderName = child.Label.Substring(0, firstSplit); - var folder = parent.Children.FirstOrDefault(f => f.Label.Equals(folderName)); - if (folder == null) - { - folder = new BranchTreeNode("", NodeType.Folder, false) { Label = folderName }; - parent.Children.Add(folder); - } - - // Pop the folder name from the front of the child label and add it to the folder - child.Label = child.Label.Substring(folderName.Length + 1); - BuildTree(folder, child); - } - - private void SetFavorite(BranchTreeNode branch, bool favorite) - { - if (string.IsNullOrEmpty(branch.Name)) - { - return; - } - - if (!favorite) - { - favorites.Remove(branch); - Manager.LocalSettings.Set(FavoritesSetting, favorites.Select(x => x.Name).ToList()); - } - else - { - favorites.Remove(branch); - favorites.Add(branch); - Manager.LocalSettings.Set(FavoritesSetting, favorites.Select(x => x.Name).ToList()); - } - } - private void OnButtonBarGUI() { if (mode == BranchesMode.Default) { // Delete button // If the current branch is selected, then do not enable the Delete button - var disableDelete = selectedNode == null || selectedNode.Type == NodeType.Folder || activeBranchNode == selectedNode; EditorGUI.BeginDisabledGroup(disableDelete); { if (GUILayout.Button(DeleteBranchButton, EditorStyles.miniButton, GUILayout.ExpandWidth(false))) { - var selectedBranchName = selectedNode.Name; + var selectedBranchName = treeLocals.SelectedNode.Name; var dialogMessage = string.Format(DeleteBranchMessageFormatString, selectedBranchName); if (EditorUtility.DisplayDialog(DeleteBranchTitle, dialogMessage, DeleteBranchButton, CancelButtonLabel)) { @@ -485,8 +221,8 @@ private void OnButtonBarGUI() { var createBranch = false; var cancelCreate = false; - var cannotCreate = selectedNode == null || - selectedNode.Type == NodeType.Folder || + var cannotCreate = treeLocals.SelectedNode == null || + treeLocals.SelectedNode.IsFolder || !Validation.IsBranchNameValid(newBranchName); // Create on return/enter or cancel on escape @@ -532,7 +268,7 @@ private void OnButtonBarGUI() // Effectuate create if (createBranch) { - GitClient.CreateBranch(newBranchName, selectedNode.Name) + GitClient.CreateBranch(newBranchName, treeLocals.SelectedNode.Name) .FinallyInUI((success, e) => { if (success) { @@ -563,191 +299,583 @@ private void OnButtonBarGUI() } } - private void OnTreeNodeGUI(BranchTreeNode node) + private void OnTreeGUI(Rect rect) + { + if (!treeLocals.IsInitialized) + RefreshBranchList(); + + if (treeLocals.FolderStyle == null) + { + treeLocals.FolderStyle = Styles.Foldout; + treeLocals.TreeNodeStyle = Styles.TreeNode; + treeLocals.ActiveTreeNodeStyle = Styles.TreeNodeActive; + treeRemotes.FolderStyle = Styles.Foldout; + treeRemotes.TreeNodeStyle = Styles.TreeNode; + treeRemotes.ActiveTreeNodeStyle = Styles.TreeNodeActive; + } + + var treeHadFocus = treeLocals.SelectedNode != null; + + rect = treeLocals.Render(rect, _ => { }, node => + { + if (EditorUtility.DisplayDialog(ConfirmSwitchTitle, String.Format(ConfirmSwitchMessage, node.Name), ConfirmSwitchOK, + ConfirmSwitchCancel)) + { + GitClient.SwitchBranch(node.Name) + .FinallyInUI((success, e) => + { + if (success) + { + Refresh(); + } + else + { + EditorUtility.DisplayDialog(Localization.SwitchBranchTitle, + String.Format(Localization.SwitchBranchFailedDescription, node.Name), + Localization.Ok); + } + }).Start(); + } + }); + + if (treeHadFocus && treeLocals.SelectedNode == null) + treeRemotes.Focus(); + else if (!treeHadFocus && treeLocals.SelectedNode != null) + treeRemotes.Blur(); + + if (treeLocals.RequiresRepaint) + Redraw(); + + treeHadFocus = treeRemotes.SelectedNode != null; + + rect.y += Styles.TreePadding; + + treeRemotes.Render(rect, _ => {}, selectedNode => + { + var indexOfFirstSlash = selectedNode.Name.IndexOf('/'); + var originName = selectedNode.Name.Substring(0, indexOfFirstSlash); + var branchName = selectedNode.Name.Substring(indexOfFirstSlash + 1); + + if (Repository.LocalBranches.Any(localBranch => localBranch.Name == branchName)) + { + EditorUtility.DisplayDialog(WarningCheckoutBranchExistsTitle, + String.Format(WarningCheckoutBranchExistsMessage, branchName), + WarningCheckoutBranchExistsOK); + } + else + { + var confirmCheckout = EditorUtility.DisplayDialog(ConfirmCheckoutBranchTitle, + String.Format(ConfirmCheckoutBranchMessage, selectedNode.Name, originName), + ConfirmCheckoutBranchOK, + ConfirmCheckoutBranchCancel); + + if (confirmCheckout) + { + GitClient + .CreateBranch(branchName, selectedNode.Name) + .FinallyInUI((success, e) => + { + if (success) + { + Refresh(); + } + else + { + EditorUtility.DisplayDialog(Localization.SwitchBranchTitle, + String.Format(Localization.SwitchBranchFailedDescription, selectedNode.Name), + Localization.Ok); + } + }) + .Start(); + } + } + }); + + if (treeHadFocus && treeRemotes.SelectedNode == null) + { + treeLocals.Focus(); + } + else if (!treeHadFocus && treeRemotes.SelectedNode != null) + { + treeLocals.Blur(); + } + + if (treeRemotes.RequiresRepaint) + Redraw(); + } + + private int CompareBranches(GitBranch a, GitBranch b) { - // Content, style, and rects + //if (IsFavorite(a.Name)) + //{ + // return -1; + //} + + //if (IsFavorite(b.Name)) + //{ + // return 1; + //} - Texture2D iconContent; + if (a.Name.Equals("master")) + { + return -1; + } - if (node.Active == true) + if (b.Name.Equals("master")) { - iconContent = Styles.ActiveBranchIcon; + return 1; } - else + + return a.Name.CompareTo(b.Name); + } + + //private bool IsFavorite(string branchName) + //{ + // return !String.IsNullOrEmpty(branchName) && favoritesList.Contains(branchName); + //} + + //private void SetFavorite(TreeNode branch, bool favorite) + //{ + // if (string.IsNullOrEmpty(branch.Name)) + // { + // return; + // } + + // if (!favorite) + // { + // favorites.Remove(branch); + // Manager.LocalSettings.Set(FavoritesSetting, favorites.Select(x => x.Name).ToList()); + // } + // else + // { + // favorites.Remove(branch); + // favorites.Add(branch); + // Manager.LocalSettings.Set(FavoritesSetting, favorites.Select(x => x.Name).ToList()); + // } + //} + + + [Serializable] + public class Tree + { + [SerializeField] private List nodes = new List(); + [SerializeField] private TreeNode selectedNode = null; + [SerializeField] private TreeNode activeNode = null; + [SerializeField] public float ItemHeight = EditorGUIUtility.singleLineHeight; + [SerializeField] public float ItemSpacing = EditorGUIUtility.standardVerticalSpacing; + [SerializeField] public float Indentation = 12f; + [SerializeField] public Rect Margin = new Rect(); + [SerializeField] public Rect Padding = new Rect(); + [SerializeField] private List foldersKeys = new List(); + [SerializeField] public Texture2D ActiveNodeIcon; + [SerializeField] public Texture2D NodeIcon; + [SerializeField] public Texture2D FolderIcon; + [SerializeField] public Texture2D RootFolderIcon; + [SerializeField] public GUIStyle FolderStyle; + [SerializeField] public GUIStyle TreeNodeStyle; + [SerializeField] public GUIStyle ActiveTreeNodeStyle; + + [NonSerialized] + private Stack indents = new Stack(); + [NonSerialized] + private Hashtable folders; + + public bool IsInitialized { get { return nodes != null && nodes.Count > 0 && !String.IsNullOrEmpty(nodes[0].Name); } } + public bool RequiresRepaint { get; private set; } + + public TreeNode SelectedNode { - if (node.Children.Count > 0) + get { - iconContent = Styles.FolderIcon; + if (selectedNode != null && String.IsNullOrEmpty(selectedNode.Name)) + selectedNode = null; + return selectedNode; } - else + private set { - iconContent = Styles.BranchIcon; + selectedNode = value; } } - var content = new GUIContent(node.Label, iconContent); - var style = node.Active ? Styles.BoldLabel : Styles.Label; - var rect = GUILayoutUtility.GetRect(content, style, GUILayout.MaxHeight(EditorGUIUtility.singleLineHeight)); - var clickRect = new Rect(0f, rect.y, Position.width, rect.height); - var favoriteRect = new Rect(clickRect.xMax - clickRect.height * 2f, clickRect.y, clickRect.height, clickRect.height); + public TreeNode ActiveNode { get { return activeNode; } } - var selected = selectedNode == node; - var keyboardFocus = GUIUtility.keyboardControl == listID; + private Hashtable Folders + { + get + { + if (folders == null) + { + folders = new Hashtable(); + for (int i = 0; i < foldersKeys.Count; i++) + { + folders.Add(foldersKeys[i], null); + } + } + return folders; + } + } - // Selection highlight and favorite toggle - if (selected) + public void Load(IEnumerable data, string title) { - if (Event.current.type == EventType.Repaint) + foldersKeys.Clear(); + Folders.Clear(); + nodes.Clear(); + + var titleNode = new TreeNode() + { + Name = title, + Label = title, + Level = 0, + IsFolder = true + }; + titleNode.Load(); + nodes.Add(titleNode); + + foreach (var d in data) { - style.Draw(clickRect, GUIContent.none, false, false, true, keyboardFocus); + var parts = d.Name.Split('/'); + for (int i = 0; i < parts.Length; i++) + { + var label = parts[i]; + var name = String.Join("/", parts, 0, i + 1); + var isFolder = i < parts.Length - 1; + var alreadyExists = Folders.ContainsKey(name); + if (!alreadyExists) + { + var node = new TreeNode() + { + Name = name, + IsActive = d.IsActive, + Label = label, + Level = i + 1, + IsFolder = isFolder + }; + + if (node.IsActive) + { + activeNode = node; + node.Icon = ActiveNodeIcon; + } + else if (node.IsFolder) + { + if (node.Level == 1) + node.Icon = RootFolderIcon; + else + node.Icon = FolderIcon; + } + else + { + node.Icon = NodeIcon; + } + + node.Load(); + + nodes.Add(node); + if (isFolder) + { + Folders.Add(name, null); + } + } + } } + foldersKeys = Folders.Keys.Cast().ToList(); + } - if (node.Type != NodeType.Folder) + public Rect Render(Rect rect, Action singleClick = null, Action doubleClick = null) + { + RequiresRepaint = false; + rect = new Rect(0f, rect.y, rect.width, ItemHeight); + + var titleNode = nodes[0]; + bool selectionChanged = titleNode.Render(rect, 0f, selectedNode == titleNode, FolderStyle, TreeNodeStyle, ActiveTreeNodeStyle); + + if (selectionChanged) + { + ToggleNodeVisibility(0, titleNode); + } + + RequiresRepaint = HandleInput(rect, titleNode, 0); + rect.y += ItemHeight + ItemSpacing; + + Indent(); + + int level = 1; + for (int i = 1; i < nodes.Count; i++) { - var favorite = IsFavorite(node.Name); - if (Event.current.type == EventType.Repaint) + var node = nodes[i]; + + if (node.Level > level && !node.IsHidden) { - GUI.DrawTexture(favoriteRect, favorite ? Styles.FavoriteIconOn : Styles.FavoriteIconOff); + Indent(); } - else if (Event.current.type == EventType.MouseDown && favoriteRect.Contains(Event.current.mousePosition)) + + var changed = node.Render(rect, Indentation, selectedNode == node, FolderStyle, TreeNodeStyle, ActiveTreeNodeStyle); + + if (node.IsFolder && changed) { - SetFavorite(node, !favorite); - Event.current.Use(); + // toggle visibility for all the nodes under this one + ToggleNodeVisibility(i, node); + } + + if (node.Level < level) + { + for (; node.Level > level && indents.Count > 1; level--) + { + Unindent(); + } + } + level = node.Level; + + if (!node.IsHidden) + { + RequiresRepaint = HandleInput(rect, node, i, singleClick, doubleClick); + rect.y += ItemHeight + ItemSpacing; } } + + Unindent(); + + foldersKeys = Folders.Keys.Cast().ToList(); + return rect; } - // Favorite status - else if (Event.current.type == EventType.Repaint && node.Type != NodeType.Folder && IsFavorite(node.Name)) + + public void Focus() { - GUI.DrawTexture(favoriteRect, Styles.FavoriteIconOn); + bool selectionChanged = false; + if (Event.current.type == EventType.KeyDown) + { + 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) + { + if (directionY < 0 || directionY < 0) + { + SelectedNode = nodes[nodes.Count - 1]; + selectionChanged = true; + Event.current.Use(); + } + else if (directionY > 0 || directionX > 0) + { + SelectedNode = nodes[0]; + selectionChanged = true; + Event.current.Use(); + } + } + } + RequiresRepaint = selectionChanged; } - // The actual icon and label - if (Event.current.type == EventType.Repaint) + public void Blur() { - style.Draw(rect, content, false, false, selected, keyboardFocus); + SelectedNode = null; + RequiresRepaint = true; } - // Children - GUILayout.BeginHorizontal(); + private int ToggleNodeVisibility(int idx, TreeNode rootNode) { - GUILayout.Space(Styles.TreeIndentation); - GUILayout.BeginVertical(); + var rootNodeLevel = rootNode.Level; + rootNode.IsCollapsed = !rootNode.IsCollapsed; + idx++; + for (; idx < nodes.Count && nodes[idx].Level > rootNodeLevel; idx++) + { + nodes[idx].IsHidden = rootNode.IsCollapsed; + if (nodes[idx].IsFolder && !rootNode.IsCollapsed && nodes[idx].IsCollapsed) + { + var level = nodes[idx].Level; + for (idx++; idx < nodes.Count && nodes[idx].Level > level; idx++) { } + idx--; + } + } + if (SelectedNode != null && SelectedNode.IsHidden) { - OnTreeNodeChildrenGUI(node); + SelectedNode = rootNode; } - GUILayout.EndVertical(); + return idx; } - GUILayout.EndHorizontal(); - // Click selection of the node as well as branch switch - if (Event.current.type == EventType.MouseDown && clickRect.Contains(Event.current.mousePosition)) + private bool HandleInput(Rect rect, TreeNode currentNode, int index, Action singleClick = null, Action doubleClick = null) { - newNodeSelection = node; - Event.current.Use(); - - if (Event.current.clickCount > 1 && mode == BranchesMode.Default) + 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)) { - if (node.Type == NodeType.LocalBranch) + Event.current.Use(); + SelectedNode = currentNode; + selectionChanged = true; + var clickCount = Event.current.clickCount; + if (clickCount == 1 && singleClick != null) { - if (EditorUtility.DisplayDialog(ConfirmSwitchTitle, String.Format(ConfirmSwitchMessage, node.Name), ConfirmSwitchOK, ConfirmSwitchCancel)) - { - GitClient.SwitchBranch(node.Name) - .FinallyInUI((success, e) => - { - if (success) - { - Refresh(); - } - else - { - EditorUtility.DisplayDialog(Localization.SwitchBranchTitle, - String.Format(Localization.SwitchBranchFailedDescription, node.Name), - Localization.Ok); - } - }).Start(); - } + singleClick(currentNode); } - else if (node.Type == NodeType.RemoteBranch) + if (clickCount > 1 && doubleClick != null) { - var indexOfFirstSlash = selectedNode.Name.IndexOf('/'); - var originName = selectedNode.Name.Substring(0, indexOfFirstSlash); - var branchName = selectedNode.Name.Substring(indexOfFirstSlash + 1); + doubleClick(currentNode); + } + } - if (Repository.LocalBranches.Any(localBranch => localBranch.Name == branchName)) + // Keyboard navigation if this child is the current selection + if (currentNode == selectedNode && Event.current.type == EventType.KeyDown) + { + 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) + { + if (directionY > 0) { - EditorUtility.DisplayDialog(WarningCheckoutBranchExistsTitle, - String.Format(WarningCheckoutBranchExistsMessage, branchName), - WarningCheckoutBranchExistsOK); + selectionChanged = SelectNext(index, false) != index; } - else + else if (directionY < 0) { - var confirmCheckout = EditorUtility.DisplayDialog(ConfirmCheckoutBranchTitle, - String.Format(ConfirmCheckoutBranchMessage, node.Name, originName), - ConfirmCheckoutBranchOK, ConfirmCheckoutBranchCancel); - - if (confirmCheckout) + selectionChanged = SelectPrevious(index, false) != index; + } + else if (directionX > 0) + { + if (currentNode.IsFolder && currentNode.IsCollapsed) { - GitClient.CreateBranch(branchName, selectedNode.Name) - .FinallyInUI((success, e) => - { - if (success) - { - Refresh(); - } - else - { - EditorUtility.DisplayDialog(Localization.SwitchBranchTitle, - String.Format(Localization.SwitchBranchFailedDescription, node.Name), - Localization.Ok); - } - }).Start(); + ToggleNodeVisibility(index, currentNode); + Event.current.Use(); + } + else + { + selectionChanged = SelectNext(index, true) != index; + } + } + else if (directionX < 0) + { + if (currentNode.IsFolder && !currentNode.IsCollapsed) + { + ToggleNodeVisibility(index, currentNode); + Event.current.Use(); + } + else + { + selectionChanged = SelectPrevious(index, true) != index; } } } } + return selectionChanged; + } + + private int SelectNext(int index, bool foldersOnly) + { + for (index++; index < nodes.Count; index++) + { + if (nodes[index].IsHidden) + continue; + if (!nodes[index].IsFolder && foldersOnly) + continue; + break; + } + + if (index < nodes.Count) + { + SelectedNode = nodes[index]; + Event.current.Use(); + } + else + { + SelectedNode = null; + } + return index; + } + + private int SelectPrevious(int index, bool foldersOnly) + { + for (index--; index >= 0; index--) + { + if (nodes[index].IsHidden) + continue; + if (!nodes[index].IsFolder && foldersOnly) + continue; + break; + } + + if (index >= 0) + { + SelectedNode = nodes[index]; + Event.current.Use(); + } + else + { + SelectedNode = null; + } + return index; + } + + private void Indent() + { + indents.Push(true); + } + + private void Unindent() + { + indents.Pop(); } } - private void OnTreeNodeChildrenGUI(BranchTreeNode node) + [Serializable] + public class TreeNode { - if (node == null || node.Children == null) + public string Name; + public string Label; + public int Level; + public bool IsFolder; + public bool IsCollapsed; + public bool IsHidden; + public bool IsActive; + public GUIContent content; + public Texture2D Icon; + + public void Load() { - return; + content = new GUIContent(Label, Icon); } - for (var index = 0; index < node.Children.Count; ++index) + public bool Render(Rect rect, float indentation, bool isSelected, GUIStyle folderStyle, GUIStyle nodeStyle, GUIStyle activeNodeStyle) { - // The actual GUI of the child - OnTreeNodeGUI(node.Children[index]); + if (IsHidden) + return false; - // Keyboard navigation if this child is the current selection - if (selectedNode == node.Children[index] && GUIUtility.keyboardControl == listID && Event.current.type == EventType.KeyDown) + GUIStyle style; + if (IsFolder) + { + style = folderStyle; + } + else { - int directionY = Event.current.keyCode == KeyCode.UpArrow ? -1 : Event.current.keyCode == KeyCode.DownArrow ? 1 : 0, - directionX = Event.current.keyCode == KeyCode.LeftArrow ? -1 : Event.current.keyCode == KeyCode.RightArrow ? 1 : 0; + style = IsActive ? activeNodeStyle : nodeStyle; + } - if (directionY < 0 && index > 0) - { - newNodeSelection = node.Children[index - 1]; - Event.current.Use(); - } - else if (directionY > 0 && index < node.Children.Count - 1) - { - newNodeSelection = node.Children[index + 1]; - Event.current.Use(); - } - else if (directionX < 0) - { - newNodeSelection = node; - Event.current.Use(); - } - else if (directionX > 0 && node.Children[index].Children.Count > 0) + bool changed = false; + var fillRect = rect; + var nodeRect = new Rect(Level * indentation, rect.y, rect.width, rect.height); + + if (Event.current.type == EventType.repaint) + { + nodeStyle.Draw(fillRect, "", false, false, false, isSelected); + if (IsFolder) + style.Draw(nodeRect, content, false, false, !IsCollapsed, isSelected); + else { - newNodeSelection = node.Children[index].Children[0]; - Event.current.Use(); + style.Draw(nodeRect, content, false, false, false, isSelected); } } + + if (IsFolder) + { + EditorGUI.BeginChangeCheck(); + GUI.Toggle(nodeRect, !IsCollapsed, "", GUIStyle.none); + changed = EditorGUI.EndChangeCheck(); + } + + return changed; + } + + public override string ToString() + { + return String.Format("name:{0} label:{1} level:{2} isFolder:{3} isCollapsed:{4} isHidden:{5} isActive:{6}", + Name, Label, Level, IsFolder, IsCollapsed, IsHidden, IsActive); } } @@ -768,34 +896,5 @@ private enum BranchesMode Default, Create } - - [Serializable] - private class BranchTreeNode - { - private readonly List children = new List(); - - public string Label; - public BranchTreeNode Tracking; - - public BranchTreeNode(string name, NodeType type, bool active) - { - Label = Name = name; - Type = type; - Active = active; - } - - public string Name { get; private set; } - public NodeType Type { get; private set; } - public bool Active { get; private set; } - - public IList Children { get { return children; } } - } - - private struct Remote - { - // TODO: Pull in and store more data from GitListRemotesTask - public string Name; - public BranchTreeNode Root; - } } } From 1ae828a27c8bc6a3f60bec25576122d4f8a514a8 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 17 Oct 2017 14:28:33 -0400 Subject: [PATCH 2/5] Making CacheManager public --- src/GitHub.Api/Cache/CacheManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitHub.Api/Cache/CacheManager.cs b/src/GitHub.Api/Cache/CacheManager.cs index 11e038756..5e3cdaadc 100644 --- a/src/GitHub.Api/Cache/CacheManager.cs +++ b/src/GitHub.Api/Cache/CacheManager.cs @@ -3,7 +3,7 @@ namespace GitHub.Unity { - class CacheManager + public class CacheManager { private IBranchCache branchCache; public IBranchCache BranchCache From 1b39f19d0f39426070328d07f1fcae92e3548989 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 17 Oct 2017 14:33:04 -0400 Subject: [PATCH 3/5] Make another class public --- src/GitHub.Api/Cache/IBranchCache.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/GitHub.Api/Cache/IBranchCache.cs b/src/GitHub.Api/Cache/IBranchCache.cs index fce1b4c63..026d4f6bb 100644 --- a/src/GitHub.Api/Cache/IBranchCache.cs +++ b/src/GitHub.Api/Cache/IBranchCache.cs @@ -2,7 +2,7 @@ namespace GitHub.Unity { - interface IBranchCache + public interface IBranchCache { List LocalBranches { get; set; } List RemoteBranches { get; set; } From 1f0093f8279ae17a7b7760402c0e6ebfc4b4f588 Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 17 Oct 2017 14:33:22 -0400 Subject: [PATCH 4/5] Restoring method Utility.CreateTextureFromColor --- .../Assets/Editor/GitHub.Unity/Misc/Utility.cs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs index e645e5654..d0671f3f3 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/Misc/Utility.cs @@ -23,6 +23,14 @@ public static Texture2D GetIcon(string filename, string filename2x = "") var iconPath = EntryPoint.Environment.ExtensionInstallPath.Combine("IconsAndLogos", filename).ToString(SlashMode.Forward); return AssetDatabase.LoadAssetAtPath(iconPath); } + + public static Texture2D CreateTextureFromColor(Color color) + { + var texture = new Texture2D(1, 1); + texture.SetPixel(0, 0, color); + texture.Apply(); + return texture; + } } static class StreamExtensions From ac7e2ac3d40100bebdae7b9aadc5ff606eaf293f Mon Sep 17 00:00:00 2001 From: Stanley Goldman Date: Tue, 17 Oct 2017 14:34:21 -0400 Subject: [PATCH 5/5] Removing unused method --- .../Assets/Editor/GitHub.Unity/UI/BranchesView.cs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs index 2d74daa3f..fcbbe08c9 100644 --- a/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs +++ b/src/UnityExtension/Assets/Editor/GitHub.Unity/UI/BranchesView.cs @@ -149,20 +149,6 @@ private void RefreshBranchList() BuildTree(localBranches, remoteBranches); } - private void RunUpdateBranchesOnMainThread() - { - new ActionTask(TaskManager.Token, _ => UpdateBranches()) - .ScheduleUI(TaskManager); - } - - public void UpdateBranches() - { - if (Repository == null) - return; - - BuildTree(Repository.LocalBranches, Repository.RemoteBranches); - } - private void Render() { scroll = GUILayout.BeginScrollView(scroll, false, true);