Adaug proiectul Unity

This commit is contained in:
2026-11-01 23:39:55 +02:00
parent cb14d9d37d
commit 863eac8f2c
23463 changed files with 5412601 additions and 0 deletions
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6d49fec91584fde45ad08f2f316792bb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 132f4852ac624340a1662611b86b2bf7
timeCreated: 1746021263
@@ -0,0 +1,58 @@
using System;
using Codice.CM.Common;
using PlasticGui;
using PlasticGui.WorkspaceWindow.Topbar.WorkingObjectInfo.BranchesList;
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow.BranchesList
{
internal class BranchesListModel
{
internal ClassifiedBranchesList Branches { get; private set; }
internal RepositorySpec RepSpec { get; private set; }
internal Exception Exception { get; private set; }
internal bool IsLoading { get { return Branches == null && Exception == null; } }
internal bool HasErrors { get { return Exception != null; } }
internal bool IsEmpty { get { return Branches != null && Branches.IsEmpty; } }
internal static BranchesListModel FromException(Exception exception)
{
return new BranchesListModel(null, null, exception);
}
internal static BranchesListModel FromBranches(
ClassifiedBranchesList branches,
RepositorySpec repSpec)
{
return new BranchesListModel(branches, repSpec, null);
}
internal static BranchesListModel BuildEmpty()
{
return new BranchesListModel(null, null, null);
}
internal void ResetFilter()
{
if (Branches == null)
return;
Branches.ResetFilter();
}
internal void ApplyFilter(Filter filter)
{
if (Branches == null)
return;
Branches.ApplyFilter(filter);
}
BranchesListModel(ClassifiedBranchesList branches, RepositorySpec repSpec, Exception ex)
{
Branches = branches;
RepSpec = repSpec;
Exception = ex;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6c114cb79a4a4da99813e9526b36080f
timeCreated: 1746177660
@@ -0,0 +1,380 @@
using System;
using System.Collections.Generic;
using Codice.CM.Common;
using PlasticGui;
using PlasticGui.WorkspaceWindow.Topbar.WorkingObjectInfo.BranchesList;
using Unity.PlasticSCM.Editor.UI;
using UnityEditor.IMGUI.Controls;
using UnityEngine;
#if UNITY_6000_2_OR_NEWER
using TreeView = UnityEditor.IMGUI.Controls.TreeView<int>;
using TreeViewItem = UnityEditor.IMGUI.Controls.TreeViewItem<int>;
using TreeViewState = UnityEditor.IMGUI.Controls.TreeViewState<int>;
#endif
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow.BranchesList
{
internal class BranchesTreeView : TreeView
{
internal interface IClickListener
{
void OnItemClicked(BranchTreeViewItem item);
}
internal BranchesTreeView(IClickListener listener) : base(new TreeViewState())
{
mClickListener = listener;
}
internal void SetWorkingBranch(Func<BranchInfo> fetchWorkingBranch)
{
mFetchWorkingBranch = fetchWorkingBranch;
}
internal void SetBranches(ClassifiedBranchesList branches)
{
mBranches = branches;
if (!string.IsNullOrEmpty(mSearchString))
{
SetSearchString(mSearchString);
return;
}
Reload();
}
internal void SetSearchString(string searchString)
{
mSearchString = searchString;
}
protected override bool CanMultiSelect(TreeViewItem item)
{
return false;
}
protected override float GetCustomRowHeight(int row, TreeViewItem item)
{
if (IsCategory(item))
return 26;
else
return 38f;
}
public override void OnGUI(Rect rect)
{
if (Event.current.type == EventType.MouseMove)
{
Vector2 localMousePos = Event.current.mousePosition - rect.position + state.scrollPos;
int newHoveredId = GetHoveredItemId(localMousePos);
if (newHoveredId != mLastHoveredItemId)
{
mLastHoveredItemId = newHoveredId;
Repaint();
}
}
base.OnGUI(rect);
}
protected override void RowGUI(RowGUIArgs args)
{
Rect rowRect = args.rowRect;
Event evt = Event.current;
switch (evt.type)
{
case EventType.MouseDown:
if (rowRect.Contains(evt.mousePosition) &&
evt.button == 0)
{
mClickedItemId = args.item.id;
evt.Use();
}
break;
case EventType.MouseUp:
if (rowRect.Contains(evt.mousePosition) &&
evt.button == 0 &&
mClickedItemId == args.item.id &&
!IsCategory(args.item))
{
mClickedItemId = -1;
evt.Use();
mClickListener.OnItemClicked((BranchTreeViewItem)args.item);
}
break;
case EventType.Repaint:
DrawRowGUI(args);
break;
}
}
bool IsCategory(TreeViewItem item)
{
return item is CategoryTreeViewItem;
}
void DrawRowGUI(RowGUIArgs args)
{
if (IsCategory(args.item))
{
DrawCategory(args);
return;
}
DrawBranch(args);
}
void DrawBranch(RowGUIArgs args)
{
bool isHover = args.rowRect.Contains(Event.current.mousePosition);
GUIStyle titleStyle = isHover ?
UnityStyles.EditorToolbar.Popup.BranchesList.TitleHover :
UnityStyles.EditorToolbar.Popup.BranchesList.Title;
GUIStyle descriptionStyle = isHover ?
UnityStyles.EditorToolbar.Popup.BranchesList.DescriptionHover :
UnityStyles.EditorToolbar.Popup.BranchesList.Description;
GUIStyle timeAgoStyle = isHover ?
UnityStyles.EditorToolbar.Popup.BranchesList.TimeAgoHover :
UnityStyles.EditorToolbar.Popup.BranchesList.TimeAgo;
if (isHover)
{
GUI.Label(args.rowRect, GUIContent.none, UnityStyles.EditorToolbar.Popup.Hover);
}
BranchTreeViewItem branchItem = (BranchTreeViewItem)args.item;
bool isWorkingBranch = branchItem.BranchInfo.Equals(mFetchWorkingBranch());
Texture icon = isWorkingBranch ? Images.GetCurrentBranchIcon() : Images.GetBranchIcon();
GUIContent titleContent = new GUIContent(args.item.displayName, icon);
GUIContent descriptionContent = new GUIContent(branchItem.FormattedComment);
string tooltip = string.Format("{0}, {1}",
branchItem.BranchInfo.LocalTimeStamp.ToLongDateString(),
branchItem.BranchInfo.LocalTimeStamp.ToLongTimeString());
GUIContent timeAgoContent = new GUIContent(Codice.Client.Common.Time.GetTimeAgoString(
branchItem.BranchInfo.LocalTimeStamp), tooltip);
Vector2 titleContentSize = titleStyle.CalcSize(titleContent);
Vector2 descriptionContentSize = descriptionStyle.CalcSize(descriptionContent);
Vector2 timeAgoSize = timeAgoStyle.CalcSize(timeAgoContent);
Rect timeAgoRect = new Rect(
args.rowRect.x + args.rowRect.width - timeAgoSize.x,
args.rowRect.y + (args.rowRect.height - timeAgoSize.y) / 2,
timeAgoSize.x,
timeAgoSize.y);
float titleAndDescriptionHeight = titleContentSize.y + descriptionContentSize.y;
Rect titleRect = new Rect(
args.rowRect.x,
args.rowRect.y + (args.rowRect.height - titleAndDescriptionHeight) / 2,
args.rowRect.width - timeAgoSize.x,
titleContentSize.y);
Rect desciptionRect = new Rect(
args.rowRect.x,
args.rowRect.y + (args.rowRect.height - titleAndDescriptionHeight) / 2 + titleContentSize.y,
args.rowRect.width - timeAgoSize.x,
descriptionContentSize.y);
// add a tooltip if title or description is not completely displayed
if (titleContentSize.x > args.rowRect.width - timeAgoSize.x)
titleContent.tooltip = titleContent.text;
if (descriptionContentSize.x > args.rowRect.width - timeAgoSize.x)
descriptionContent.tooltip = descriptionContent.text;
DrawContentWithSearchString(
titleRect,
titleContent,
mSearchString,
titleStyle);
DrawContentWithSearchString(
desciptionRect,
descriptionContent,
mSearchString,
descriptionStyle);
GUI.Label(timeAgoRect, timeAgoContent, timeAgoStyle);
}
static void DrawCategory(RowGUIArgs args)
{
GUI.Label(
args.rowRect,
args.item.displayName,
UnityStyles.EditorToolbar.Popup.BranchesList.Category);
}
static void DrawContentWithSearchString(
Rect rect,
GUIContent content,
string searchString,
GUIStyle style)
{
int titleSearchStringIndex = string.IsNullOrEmpty(searchString)
? -1
: content.text.IndexOf(searchString, StringComparison.Ordinal);
float iconWidth = content.image != null ? 16 : 0f;
Rect iconRect = new Rect(
rect.x + style.padding.left,
rect.y,
iconWidth,
rect.height);
Rect textRect = new Rect(
rect.x + iconWidth + style.margin.left,
rect.y,
rect.width - iconWidth,
rect.height);
if (content.image != null)
{
GUI.DrawTexture(iconRect, content.image);
}
if (titleSearchStringIndex == -1)
{
GUI.Label(textRect, new GUIContent(content.text, content.tooltip), style);
}
else
{
style.DrawWithTextSelection(
textRect,
new GUIContent(content.text, content.tooltip),
-1,
titleSearchStringIndex,
titleSearchStringIndex + searchString.Length
);
}
}
int GetHoveredItemId(Vector2 mousePos)
{
int firstVisibleRow,
lastVisibleRow;
this.GetFirstAndLastVisibleRows(out firstVisibleRow, out lastVisibleRow);
for (int i = firstVisibleRow; i <= lastVisibleRow; i++)
{
Rect rowRect = GetRowRect(i);
if (rowRect.Contains(mousePos))
{
return i;
}
}
return -1; // No hover
}
protected override TreeViewItem BuildRoot()
{
var root = new TreeViewItem { id = -1, depth = -1 };
root.children = new List<TreeViewItem>();
if (mBranches == null)
return root;
int currentId = -1;
if (mBranches.IsMainBranchVisible)
{
root.AddChild(new CategoryTreeViewItem(
currentId++,
PlasticLocalization.Name.MainBranchSection.GetString()));
root.AddChild(new BranchTreeViewItem(currentId++, mBranches.MainBranch));
}
if (mBranches.AreRecentBranchesVisible)
{
root.AddChild(new CategoryTreeViewItem(
currentId++,
PlasticLocalization.Name.RecentBranchesSection.GetString()));
foreach (BranchInfo branch in mBranches.RecentBranches)
{
root.AddChild(new BranchTreeViewItem(currentId++, branch));
}
}
if (mBranches.AreOtherBranchesVisible)
{
root.AddChild(new CategoryTreeViewItem(
currentId++,
PlasticLocalization.Name.OtherBranchesSection.GetString()));
foreach (BranchInfo branch in mBranches.OtherBranches)
{
root.AddChild(new BranchTreeViewItem(currentId++, branch));
}
}
return root;
}
readonly IClickListener mClickListener;
int mClickedItemId;
string mSearchString;
ClassifiedBranchesList mBranches;
Func<BranchInfo> mFetchWorkingBranch;
int mLastHoveredItemId = -1;
}
class BranchTreeViewItem : TreeViewItem
{
string mFormattedComment;
internal BranchInfo BranchInfo { get; private set; }
public string FormattedComment
{
get
{
if (string.IsNullOrEmpty(mFormattedComment))
mFormattedComment = GetFormattedComment(BranchInfo.Comment);
return mFormattedComment;
}
}
internal BranchTreeViewItem(int id, BranchInfo branchInfo)
{
this.id = id;
this.displayName = branchInfo.Name;
BranchInfo = branchInfo;
}
static string GetFormattedComment(string comment)
{
if (string.IsNullOrEmpty(comment))
return PlasticLocalization.Name.NoCommentSet.GetString();
return CommentFormatter.GetFormattedComment(comment);
}
}
class CategoryTreeViewItem : TreeViewItem
{
internal CategoryTreeViewItem(int id, string displayName)
{
this.id = id;
this.displayName = displayName;
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cef1fd4b45bd4bbfabb7b27325107045
timeCreated: 1744301481
@@ -0,0 +1,77 @@
using System;
using UnityEditor;
using UnityEngine;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.UI.Tree;
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow.BranchesList
{
internal class ErrorEmptyState : CenteredContentPanel
{
internal bool HasError
{
get { return mError != null; }
}
internal ErrorEmptyState(Action retryAction, Action repaintAction) : base(repaintAction)
{
mRetryAction = retryAction;
}
internal void SetError(Exception error)
{
mError = error;
mIsRetryButtonEnabled = true;
}
protected override void DrawGUI()
{
CenterContent(
() =>
{
GUILayout.Label(
PlasticLocalization.Name.CannotLoadBranches.GetString(),
EditorStyles.boldLabel);
if (HasError)
{
GUILayout.Label(
new GUIContent(Images.GetInfoDialogIcon(), mError.Message),
GUILayout.Width(16), GUILayout.Height(16));
}
},
() =>
{
GUIStyle labelWrapStyle = new GUIStyle(EditorStyles.label);
labelWrapStyle.wordWrap = true;
labelWrapStyle.alignment = TextAnchor.MiddleCenter;
labelWrapStyle.padding = new RectOffset(15, 15, 0, 0);
GUILayout.Label(
PlasticLocalization.Name.CannotLoadBranchesExplanation.GetString(),
labelWrapStyle);
},
() =>
{
GUI.enabled = mIsRetryButtonEnabled;
if (GUILayout.Button(PlasticLocalization.Name.RetryButton.GetString()))
{
mRetryAction();
mIsRetryButtonEnabled = false;
mRepaintAction();
}
GUI.enabled = true;
}
);
}
readonly Action mRetryAction;
Exception mError;
bool mIsRetryButtonEnabled = true;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8e6494de947444dc9a132f39b8faa02c
timeCreated: 1746174901
@@ -0,0 +1,26 @@
using System;
using UnityEngine;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI.Tree;
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow.BranchesList
{
internal class LoadingEmptyState : CenteredContentPanel
{
public LoadingEmptyState(Action repaintAction)
: base(repaintAction)
{
}
protected override void DrawGUI()
{
CenterContent(() =>
{
GUILayout.Label(PlasticLocalization.Name.
LoadingBranches.GetString());
});
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0ac2f78c10614679a284c28dd3a8d8e8
timeCreated: 1746028788
@@ -0,0 +1,46 @@
using System;
using UnityEditor;
using UnityEngine;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI.Tree;
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow.BranchesList
{
internal class NoBranchesEmptyState : CenteredContentPanel
{
internal NoBranchesEmptyState(Action createBranchAction, Action repaintAction)
: base(repaintAction)
{
mCreateBranchAction = createBranchAction;
}
protected override void DrawGUI()
{
CenterContent(
() =>
{
GUILayout.Label(
PlasticLocalization.Name.NoBranchesMatchingFilters.GetString(),
EditorStyles.boldLabel);
},
() =>
{
GUILayout.Label(
PlasticLocalization.Name.CreateANewBranchInstead.GetString(),
EditorStyles.label);
},
() =>
{
if (GUILayout.Button(
PlasticLocalization.Name.CreateNewBranchButton.GetString()))
{
mCreateBranchAction();
}
});
}
readonly Action mCreateBranchAction;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f4e5325f424d436485dacca7a8d05f0c
timeCreated: 1746028559
@@ -0,0 +1,53 @@
using System;
using UnityEditor;
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow.BranchesList
{
internal class PopupupProgressBar
{
internal PopupupProgressBar(
Action repaint,
float cycleDurationSeconds = 1.5f)
{
mRepaint = repaint;
mCycleDurationSeconds = cycleDurationSeconds;
}
internal bool IsVisible { get; set; }
internal float Progress
{
get { return mProgress; }
}
internal void Reset()
{
mProgressBarLastTime = 0;
mProgressBarAccumulatedTime = 0;
mProgress = 0;
}
internal void OnEditorApplicationUpdate()
{
if (!IsVisible)
return;
double currentTime = EditorApplication.timeSinceStartup;
double deltaTime = currentTime - mProgressBarLastTime;
mProgressBarLastTime = currentTime;
mProgressBarAccumulatedTime += deltaTime;
mProgress = (float)(mProgressBarAccumulatedTime % mCycleDurationSeconds) / mCycleDurationSeconds;
mRepaint();
}
readonly Action mRepaint;
readonly float mCycleDurationSeconds;
double mProgressBarLastTime = 0f;
double mProgressBarAccumulatedTime = 0f;
float mProgress = 0f;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fc962e8f744f4e80962b46b05d1c2d27
timeCreated: 1746195401
@@ -0,0 +1,307 @@
using System;
using UnityEditor;
using UnityEngine;
using Codice.CM.Common;
using PlasticGui;
using Unity.PlasticSCM.Editor.Toolbar.PopupWindow.BranchesList;
using Unity.PlasticSCM.Editor.Toolbar.PopupWindow.Operations;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow
{
internal class ControlledPopupWindow : PopupWindowContent, BranchesTreeView.IClickListener
{
internal ControlledPopupWindow(
ControlledPopupOperations operations,
Action<ControlledPopupWindow> refreshBranches,
Func<BranchInfo> fetchWorkingBranch,
Action repaintToolbar,
Vector2 size)
{
mOperations = operations;
mRefreshBranches = refreshBranches;
mRepaintToolbar = repaintToolbar;
mSize = size;
mProgressBar = new PopupupProgressBar(Repaint);
mTreeView = new BranchesTreeView(this);
mTreeView.SetWorkingBranch(fetchWorkingBranch);
mEmptyState = new NoBranchesEmptyState(CreateBranch, Repaint);
mLoadingEmptyState = new LoadingEmptyState(Repaint);
mErrorEmptyState = new ErrorEmptyState(RefreshBranches, Repaint);
mDelayedFilterAction = new DelayedActionBySecondsRunner(
DelayedSearchChanged,
UnityConstants.SEARCH_DELAYED_INPUT_ACTION_INTERVAL);
}
public override Vector2 GetWindowSize()
{
return mSize;
}
internal void ShowProgressBar()
{
mProgressBar.Reset();
mProgressBar.IsVisible = true;
EditorApplication.update += RepaintOnce;
}
internal void HideProgressBar()
{
mProgressBar.IsVisible = false;
EditorApplication.update += RepaintOnce;
}
internal void SetModel(BranchesListModel model)
{
mModel = model;
if (model != null)
{
mTreeView.SetBranches(model.Branches);
mErrorEmptyState.SetError(model.Exception);
}
Repaint();
}
void Repaint()
{
if (editorWindow == null)
return;
editorWindow.Repaint();
}
void RepaintOnce()
{
Repaint();
EditorApplication.update -= RepaintOnce;
}
public override void OnOpen()
{
mTreeView.Reload();
EditorApplication.update += mProgressBar.OnEditorApplicationUpdate;
}
public override void OnClose()
{
EditorApplication.update -= mProgressBar.OnEditorApplicationUpdate;
RepaintToolbar();
}
void BranchesTreeView.IClickListener.OnItemClicked(BranchTreeViewItem item)
{
mOperations.SwitchToBranch(item.BranchInfo, mModel.RepSpec);
editorWindow.Close();
}
void RepaintToolbar()
{
if (mRepaintToolbar == null)
return;
mRepaintToolbar();
}
void CreateBranch()
{
ExecuteAndClosePopup(() => mOperations.CreateBranch(mSearchTerm));
}
void RefreshBranches()
{
mRefreshBranches(this);
}
void DelayedSearchChanged()
{
mTreeView.SetSearchString(mSearchTerm);
mModel.ApplyFilter(new Filter(mSearchTerm));
mTreeView.SetBranches(mModel.Branches);
mTreeView.Reload();
}
public override void OnGUI(Rect rect)
{
if (Keyboard.IsKeyPressed(Event.current, KeyCode.Escape))
{
editorWindow.Close();
return;
}
#if UNITY_EDITOR_WIN && !UNITY_6000_3_OR_NEWER
// Workaround for Unity 6.0-6.2 on Windows: close popup if mouse goes above toolbar
if (ToolbarMouseBoundary.IsAboveToolbar(rect, Event.current.mousePosition))
{
editorWindow.Close();
return;
}
#endif
EditorGUILayout.BeginVertical();
GUILayout.Space(1);
Rect checkinRect;
if (PopupWindowDrawing.DrawMenuItem(
PlasticLocalization.Name.CheckinPendingChanges.GetString(),
Images.GetPendingChangesIcon(),
ToolbarOperationsShortcut.GetPendingChangesShortcutString(),
out checkinRect))
{
ExecuteAndClosePopup(mOperations.ShowPendingChangesView);
return;
}
Rect incomingChangesRect;
if (PopupWindowDrawing.DrawMenuItem(
PlasticLocalization.Name.ViewIncomingChanges.GetString(),
Images.GetOutOfSyncIcon(),
ToolbarOperationsShortcut.GetIncomingChangesShortcutString(),
out incomingChangesRect))
{
ExecuteAndClosePopup(mOperations.ShowIncomingChangesView);
return;
}
Rect delimiterRect = new Rect(
incomingChangesRect.x,
incomingChangesRect.y + incomingChangesRect.height,
incomingChangesRect.width,
PopupWindowDrawing.DELIMITER_HEIGHT);
PopupWindowDrawing.DrawDelimiterRect(
delimiterRect,
UnityStyles.Colors.SplitLineColor);
mLastHoveredMenuIndex = PopupWindowDrawing.RepaintWhenHoveredMenuItemChanged(
editorWindow.Repaint,
mLastHoveredMenuIndex,
checkinRect,
incomingChangesRect);
if (mProgressBar.IsVisible)
{
float progressWidth = delimiterRect.width * mProgressBar.Progress;
Rect progressRect = new Rect(
delimiterRect.x,
delimiterRect.y,
progressWidth,
PopupWindowDrawing.PROGRESS_BAR_HEIGHT);
GUIStyle progressBarStyle = GUI.skin.FindStyle("ProgressBarBar");
if (progressBarStyle != null)
{
GUI.DrawTexture(progressRect, progressBarStyle.normal.background);
}
}
GUILayout.Space(5);
GUILayout.BeginHorizontal();
GUI.SetNextControlName("SearchField");
Rect searchRect = GUILayoutUtility.GetRect(
new GUIContent(string.Empty),
UnityStyles.EditorToolbar.Popup.SearchField,
GUILayout.ExpandWidth(true));
string previousSearchTerm = mSearchTerm;
string newSearchTerm = GUI.TextField(
searchRect,
mSearchTerm);
EditorGUIUtility.AddCursorRect(GUILayoutUtility.GetLastRect(), MouseCursor.Text);
if (GUILayout.Button(
PlasticLocalization.Name.NewBranchButton.GetString(),
GUILayout.ExpandWidth(false),
GUILayout.MinWidth(110)))
{
CreateBranch();
return;
}
if (newSearchTerm != previousSearchTerm)
{
mSearchTerm = newSearchTerm;
mDelayedFilterAction.Run();
}
GUILayout.EndHorizontal();
GUILayout.Space(5);
DrawBranchesModel(mModel);
EditorGUILayout.EndVertical();
EditorGUI.FocusTextInControl("SearchField");
#if UNITY_EDITOR_WIN && !UNITY_6000_3_OR_NEWER
// Request continuous repaint to track mouse position even outside popup rect
if (editorWindow != null)
editorWindow.Repaint();
#endif
}
void DrawBranchesModel(BranchesListModel model)
{
Rect treeViewRect = GUILayoutUtility.GetRect(
0,
0,
GUILayout.ExpandWidth(true),
GUILayout.ExpandHeight(true));
if (model == null || model.IsLoading)
{
mLoadingEmptyState.OnGUI(treeViewRect);
return;
}
if (model.HasErrors)
{
mErrorEmptyState.OnGUI(treeViewRect);
return;
}
if (model.IsEmpty)
{
mEmptyState.OnGUI(treeViewRect);
return;
}
mTreeView.OnGUI(treeViewRect);
}
void ExecuteAndClosePopup(Action action)
{
editorWindow.Close();
EditorDispatcher.Dispatch(action);
}
Action mRepaintToolbar;
readonly PopupupProgressBar mProgressBar;
readonly BranchesTreeView mTreeView;
readonly ControlledPopupOperations mOperations;
readonly NoBranchesEmptyState mEmptyState;
readonly LoadingEmptyState mLoadingEmptyState;
readonly ErrorEmptyState mErrorEmptyState;
readonly DelayedActionBySecondsRunner mDelayedFilterAction;
readonly Action<ControlledPopupWindow> mRefreshBranches;
readonly Vector2 mSize;
BranchesListModel mModel = BranchesListModel.BuildEmpty();
string mSearchTerm = string.Empty;
int mLastHoveredMenuIndex = -1;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2f1b1f864205414fb1d64a6c465e0378
timeCreated: 1745564990
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 22d315e8026b2304fb40b8cc8fdc1dac
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,337 @@
using System;
using UnityEditor;
using UnityEditor.ShortcutManagement;
using Codice.Client.Common.EventTracking;
using Codice.Client.Common.Threading;
using Codice.CM.Common;
using GluonGui.WorkspaceWindow.Views.WorkspaceExplorer.Explorer;
using PlasticGui;
using PlasticGui.WorkspaceWindow;
using PlasticGui.WorkspaceWindow.QueryViews.Branches;
using Unity.PlasticSCM.Editor.AssetUtils;
using Unity.PlasticSCM.Editor.Headless;
using Unity.PlasticSCM.Editor.UI;
using Unity.PlasticSCM.Editor.Views;
using Unity.PlasticSCM.Editor.Views.Branches.Dialogs;
using Unity.PlasticSCM.Editor.Views.Merge;
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow.Operations
{
internal class ControlledPopupOperations : IQueryRefreshableView
{
internal ControlledPopupOperations(
WorkspaceInfo wkInfo,
UVCSPlugin uvcsPlugin,
bool isGluonMode,
Action refreshWorkspaceWorkingInfo,
IRefreshableView branchesListPopupPanel,
Action<WorkingObjectInfo> setWorkingBranch,
Func<RepositorySpec> fetchRepSpec,
Func<BranchInfo> fetchMainBranch,
Func<BranchInfo> fetchWorkingBranch)
{
mWkInfo = wkInfo;
mUVCSPlugin = uvcsPlugin;
mIsGluonMode = isGluonMode;
mRefreshWorkspaceWorkingInfo = refreshWorkspaceWorkingInfo;
mBranchesListPopupPanel = branchesListPopupPanel;
mFetchRepSpec = fetchRepSpec;
mFetchMainBranch = fetchMainBranch;
mFetchWorkingBranch = fetchWorkingBranch;
mWindow = FindEditorWindow.FirstAvailableWindow();
mSaveAssets = new SaveAssets();
mShelvePendingChangesQuestionerBuilder = new ShelvePendingChangesQuestionerBuilder(mWindow);
mEnableSwitchAndShelveFeatureDialog = new EnableSwitchAndShelveFeature(null, mWindow);
mProgressControls = new HeadlessProgressControls();
mViewHost = new HeadlessGluonViewHost(branchesListPopupPanel);
mBranchOperations = new BranchOperations(
wkInfo,
new HeadlessWorkspaceWindow(refreshWorkspaceWorkingInfo, setWorkingBranch),
new HeadlessMergeViewLauncher(uvcsPlugin),
this,
ViewType.BranchesListPopup,
mProgressControls,
new HeadlessUpdateReport(),
new ApplyShelveReport(mWindow),
new ContinueWithPendingChangesQuestionerBuilder(new HeadlessViewSwitcher(), mWindow),
mShelvePendingChangesQuestionerBuilder,
new ApplyShelveWithConflictsQuestionerBuilder(),
mUVCSPlugin.PendingChangesUpdater,
mUVCSPlugin.DeveloperIncomingChangesUpdater,
GetShelvedChangesUpdater(),
mEnableSwitchAndShelveFeatureDialog);
}
internal void ShowPendingChangesView()
{
DoShowPendingChangesView(mUVCSPlugin);
}
internal void ShowIncomingChangesView()
{
DoShowIncomingChangesView(mUVCSPlugin);
}
internal void SwitchToBranch(
BranchInfo branchInfo,
RepositorySpec repSpec)
{
TrackFeatureUseEvent.For(
repSpec,
TrackFeatureUseEvent.Features.Toolbar.SwitchToBranch);
bool isCancelled;
mSaveAssets.UnderWorkspaceWithConfirmation(
mWkInfo.ClientPath,
mUVCSPlugin.WorkspaceOperationsMonitor,
canContinueWithDirtyScenes: false,
out isCancelled);
if (isCancelled)
return;
if (mIsGluonMode)
{
SwitchToBranchForGluonMode(branchInfo, repSpec);
return;
}
SwitchToBranchForDeveloperMode(branchInfo, repSpec);
}
internal void CreateBranch(string proposedBranchName)
{
RepositorySpec repSpec = mFetchRepSpec();
BranchInfo mainBranch = mFetchMainBranch();
BranchInfo workingBranch = mFetchWorkingBranch();
if (repSpec == null)
return;
TrackFeatureUseEvent.For(
repSpec,
TrackFeatureUseEvent.Features.Toolbar.CreateBranch);
if (workingBranch != null)
{
CreateBranch(repSpec, mainBranch, workingBranch, proposedBranchName);
return;
}
CalculateBranchBaseAndCreateBranch(repSpec, mainBranch, proposedBranchName);
}
void CalculateBranchBaseAndCreateBranch(
RepositorySpec repSpec,
BranchInfo mainBranch,
string proposedBranchName)
{
BranchInfo baseBranchInfo = null;
IThreadWaiter waiter = ThreadWaiter.GetWaiter();
waiter.Execute(
/*threadOperationDelegate*/ delegate
{
baseBranchInfo = PlasticGui.Plastic.API.GetWorkingBranch(mWkInfo);
},
/*afterOperationDelegate*/ delegate
{
if (waiter.Exception != null)
{
ExceptionsHandler.LogException(typeof(ControlledPopupOperations).Name, waiter.Exception);
return;
}
if (baseBranchInfo == null)
{
return;
}
CreateBranch(repSpec, mainBranch, baseBranchInfo, proposedBranchName);
});
}
void CreateBranch(
RepositorySpec repSpec,
BranchInfo mainBranch,
BranchInfo workingBranch,
string proposedBranchName)
{
BranchCreationData branchCreationData = CreateBranchDialog.CreateBranchFromMainOrCurrentBranch(
mWindow,
repSpec,
mainBranch,
workingBranch,
proposedBranchName);
CreateBranchForMode(branchCreationData);
}
void CreateBranchForMode(BranchCreationData branchCreationData)
{
if (mIsGluonMode)
{
CreateBranchForGluonMode(branchCreationData);
return;
}
CreateBranchForDeveloperMode(branchCreationData);
}
void CreateBranchForGluonMode(BranchCreationData branchCreationData)
{
CreateBranchOperation.CreateBranch(
mWkInfo,
branchCreationData,
mViewHost.ViewHost,
mUVCSPlugin.PendingChangesUpdater,
mUVCSPlugin.GluonIncomingChangesUpdater,
new UnityPlasticGuiMessage(),
mProgressControls,
new HeadlessGluonUpdateProgress(),
new HeadlessGluonUpdateReport(),
new HeadlessWorkspaceStatusChangeListener(mRefreshWorkspaceWorkingInfo),
mShelvePendingChangesQuestionerBuilder,
GetShelvedChangesUpdater(),
mEnableSwitchAndShelveFeatureDialog,
RefreshAsset.BeforeLongAssetOperation,
items => RefreshAsset.AfterLongAssetOperation(
mUVCSPlugin.AssetStatusCache,
ProjectPackages.ShouldBeResolvedFromPaths(mWkInfo, items)));
}
void CreateBranchForDeveloperMode(BranchCreationData branchCreationData)
{
mBranchOperations.CreateBranch(
branchCreationData,
RefreshAsset.BeforeLongAssetOperation,
items => RefreshAsset.AfterLongAssetOperation(
mUVCSPlugin.AssetStatusCache,
ProjectPackages.ShouldBeResolvedFromUpdateReport(mWkInfo, items)));
}
void IQueryRefreshableView.RefreshAndSelect(RepObjectInfo repObj)
{
//TODO: The repObj is not used
mBranchesListPopupPanel.Refresh();
}
void SwitchToBranchForGluonMode(
BranchInfo branchInfo,
RepositorySpec repSpec)
{
new SwitchToUIOperation().SwitchToBranch(
mWkInfo,
branchInfo,
mViewHost.ViewHost,
mUVCSPlugin.PendingChangesUpdater,
mUVCSPlugin.GluonIncomingChangesUpdater,
new UnityPlasticGuiMessage(),
mProgressControls,
new HeadlessGluonUpdateProgress(),
new HeadlessGluonUpdateReport(),
new HeadlessWorkspaceStatusChangeListener(mRefreshWorkspaceWorkingInfo),
mShelvePendingChangesQuestionerBuilder,
GetShelvedChangesUpdater(),
mEnableSwitchAndShelveFeatureDialog,
RefreshAsset.BeforeLongAssetOperation,
items => RefreshAsset.AfterLongAssetOperation(
mUVCSPlugin.AssetStatusCache,
ProjectPackages.ShouldBeResolvedFromPaths(mWkInfo, items)));
}
void SwitchToBranchForDeveloperMode(
BranchInfo branchInfo,
RepositorySpec repSpec)
{
mBranchOperations.SwitchToBranch(
repSpec,
branchInfo,
RefreshAsset.BeforeLongAssetOperation,
items => RefreshAsset.AfterLongAssetOperation(
mUVCSPlugin.AssetStatusCache,
ProjectPackages.ShouldBeResolvedFromUpdateReport(mWkInfo, items)));
}
[Shortcut("UVCS/ShowPendingChangesView",
ToolbarOperationsShortcut.PendingChangesShortcutKey,
ToolbarOperationsShortcut.PendingChangesShortcutModifiers)]
static void ExecuteShowPendingChangesViewShortcut()
{
if (!UVCSPlugin.Instance.IsEnabled())
return;
if (!UVCSToolbar.Controller.IsControlledProject())
return;
DoShowPendingChangesView(UVCSPlugin.Instance);
}
[Shortcut("UVCS/ShowIncomingChangesView",
ToolbarOperationsShortcut.IncomingChangesShortcutKey,
ToolbarOperationsShortcut.IncomingChangesShortcutModifiers)]
static void ExecuteShowIncomingViewShortcut()
{
if (!UVCSPlugin.Instance.IsEnabled())
return;
if (!UVCSToolbar.Controller.IsControlledProject())
return;
DoShowIncomingChangesView(UVCSPlugin.Instance);
}
static void DoShowPendingChangesView(UVCSPlugin uvcsPlugin)
{
UVCSWindow window = SwitchUVCSPlugin.OnIfNeeded(uvcsPlugin);
TrackFeatureUseEvent.For(
window.RepSpec,
TrackFeatureUseEvent.Features.Toolbar.ShowPendingChangesView);
window.ShowPendingChangesView();
}
static void DoShowIncomingChangesView(UVCSPlugin uvcsPlugin)
{
UVCSWindow window = SwitchUVCSPlugin.OnIfNeeded(uvcsPlugin);
TrackFeatureUseEvent.For(
window.RepSpec,
TrackFeatureUseEvent.Features.Toolbar.ShowIncomingChangesView);
window.ShowIncomingChangesView();
}
static IShelvedChangesUpdater GetShelvedChangesUpdater()
{
UVCSWindow window = GetWindowIfOpened.UVCS();
if (window == null)
return null;
return window.ShelvedChangesUpdater;
}
readonly WorkspaceInfo mWkInfo;
readonly UVCSPlugin mUVCSPlugin;
readonly bool mIsGluonMode;
readonly Action mRefreshWorkspaceWorkingInfo;
readonly IRefreshableView mBranchesListPopupPanel;
readonly ISaveAssets mSaveAssets;
readonly ShelvePendingChangesQuestionerBuilder mShelvePendingChangesQuestionerBuilder;
readonly EnableSwitchAndShelveFeature mEnableSwitchAndShelveFeatureDialog;
readonly IProgressControls mProgressControls;
readonly Func<RepositorySpec> mFetchRepSpec;
readonly BranchOperations mBranchOperations;
readonly Func<BranchInfo> mFetchMainBranch;
readonly Func<BranchInfo> mFetchWorkingBranch;
readonly HeadlessGluonViewHost mViewHost;
readonly EditorWindow mWindow;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4acd46006c88d7844ac06086ca0b1481
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,34 @@
using UnityEditor.ShortcutManagement;
using UnityEngine;
using Codice.Utils;
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow.Operations
{
internal static class ToolbarOperationsShortcut
{
internal const KeyCode PendingChangesShortcutKey = KeyCode.K;
internal const ShortcutModifiers PendingChangesShortcutModifiers =
ShortcutModifiers.Alt | ShortcutModifiers.Action;
internal static string GetPendingChangesShortcutString()
{
if (PlatformIdentifier.IsMac())
return "⌥ ⌘ K";
return "Alt+Ctrl+K";
}
internal const KeyCode IncomingChangesShortcutKey = KeyCode.I;
internal const ShortcutModifiers IncomingChangesShortcutModifiers =
ShortcutModifiers.Alt | ShortcutModifiers.Action;
internal static string GetIncomingChangesShortcutString()
{
if (PlatformIdentifier.IsMac())
return "⌥ ⌘ I";
return "Alt+Ctrl+I";
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 306e2c310ad3b7a4794346ffb0088c69
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,40 @@
using Codice.Utils;
using Unity.PlasticSCM.Editor.Settings;
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow.Operations
{
internal class UncontrolledPopupOperations
{
internal UncontrolledPopupOperations(
UVCSPlugin uvcsPlugin,
IUpdateToolbarButtonVisibility updateToolbarButtonVisibility)
{
mUVCSPlugin = uvcsPlugin;
mUpdateToolbarButtonVisibility = updateToolbarButtonVisibility;
}
internal void ShowUVCSWindow()
{
SwitchUVCSPlugin.OnIfNeeded(mUVCSPlugin);
}
internal void ShowUVCSSettings()
{
VCSBuiltInPlugin.EnsureProviderAsync();
OpenUVCSProjectSettings.ByDefault();
}
internal void HideUVCSToolbarButton()
{
mUpdateToolbarButtonVisibility.Hide();
}
internal void OpenUVCSLandingPageInBrowser()
{
OpenBrowser.TryOpen("https://unity.com/solutions/version-control");
}
readonly IUpdateToolbarButtonVisibility mUpdateToolbarButtonVisibility;
readonly UVCSPlugin mUVCSPlugin;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e2d43d3b3af668e4fb7dbf4f2b7384e5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,114 @@
using System;
using UnityEditor;
using UnityEngine;
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow
{
using UI;
internal static class PopupWindowDrawing
{
internal const int MENU_ITEM_HEIGHT = 26;
internal const int DELIMITER_HEIGHT = 1;
internal const int PROGRESS_BAR_HEIGHT = 3;
internal static bool DrawMenuItem(
string text,
Texture icon,
string shortcut,
out Rect menuItemRect)
{
GUIStyle menuItemStyle = UnityStyles.EditorToolbar.Popup.Hover;
menuItemRect = GUILayoutUtility.GetRect(
new GUIContent(text),
menuItemStyle,
GUILayout.Height(MENU_ITEM_HEIGHT));
bool isClicked = GUI.Button(menuItemRect, GUIContent.none, menuItemStyle);
bool isHovered = menuItemRect.Contains(Event.current.mousePosition);
GUIStyle labelStyle = isHovered ?
UnityStyles.EditorToolbar.Popup.LabelHover :
UnityStyles.EditorToolbar.Popup.Label;
GUIStyle shortcutStyle = isHovered
? UnityStyles.EditorToolbar.Popup.ShortcutHover
: UnityStyles.EditorToolbar.Popup.Shortcut;
float padding = labelStyle.padding.left;
if (icon != null)
{
Rect iconRect = new Rect(
menuItemRect.x + padding,
menuItemRect.y + (MENU_ITEM_HEIGHT - ICON_SIZE) / 2,
ICON_SIZE,
ICON_SIZE);
float textOffset = icon != null ? ICON_SIZE + labelStyle.margin.left : 0f;
Rect textRect = new Rect(
menuItemRect.x + textOffset,
menuItemRect.y,
menuItemRect.width - textOffset,
menuItemRect.height);
GUI.DrawTexture(iconRect, icon);
GUI.Label(textRect, text, labelStyle);
}
else
{
GUI.Label(menuItemRect, text, labelStyle);
}
if (!string.IsNullOrEmpty(shortcut))
GUI.Label(menuItemRect, shortcut, shortcutStyle);
return isClicked;
}
internal static void DrawDelimiterRect(Rect rect, Color color)
{
if (Event.current.type != EventType.Repaint)
return;
Color color1 = GUI.color;
GUI.color *= color;
GUI.DrawTexture(rect, EditorGUIUtility.whiteTexture);
GUI.color = color1;
}
internal static int RepaintWhenHoveredMenuItemChanged(
Action repaint,
int lastHoveredIndex,
params Rect[] rects)
{
Vector2 mousePos = Event.current.mousePosition;
int hoveredIndex = -1;
for (int i = 0; i < rects.Length; i++)
{
if (rects[i].Contains(mousePos))
{
hoveredIndex = i;
break;
}
}
if (hoveredIndex != lastHoveredIndex)
{
repaint();
}
return hoveredIndex;
}
internal static void DrawPopupBorder(Rect rect)
{
GUI.Label(rect, GUIContent.none, "grey_border");
}
const int ICON_SIZE = 16;
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 064a7a3d9b9b458f87abe1ec38227570
timeCreated: 1745998364
@@ -0,0 +1,21 @@
using UnityEngine;
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow
{
// Workaround for Unity 6.0-6.2 on Windows where clicking the window title or menus
// while a popup is open causes a GUI rendering error.
// Closes the popup when mouse goes above it (toward the risky window menu area).
internal static class ToolbarMouseBoundary
{
internal static bool IsAboveToolbar(Rect popupRect, Vector2 mousePosition)
{
float topBoundary = popupRect.y - TOOLBAR_TOP_OFFSET;
return mousePosition.y < topBoundary;
}
// Height of the toolbar button (20), his top margin (1) and the toolbar top padding (7),
// also equivalent to button height (20) + ((toolbar height (36) - button height (20)) / 2).
const float TOOLBAR_TOP_OFFSET = 28f;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e542f43e3279a52408997f8ab7dca7c0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,164 @@
using System;
using UnityEditor;
using UnityEngine;
using PlasticGui;
using Unity.PlasticSCM.Editor.Toolbar.PopupWindow.Operations;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.Toolbar.PopupWindow
{
internal class UncontrolledPopupWindow : PopupWindowContent
{
internal UncontrolledPopupWindow(
UncontrolledPopupOperations operations,
Action repaintToolbar,
Vector2 size)
{
mOperations = operations;
mRepaintToolbar = repaintToolbar;
mSize = size;
}
public override Vector2 GetWindowSize()
{
return mSize;
}
public override void OnClose()
{
RepaintToolbar();
}
void RepaintToolbar()
{
if (mRepaintToolbar == null)
return;
mRepaintToolbar();
}
public override void OnGUI(Rect rect)
{
if (Keyboard.IsKeyPressed(Event.current, KeyCode.Escape))
{
editorWindow.Close();
return;
}
#if UNITY_EDITOR_WIN && !UNITY_6000_3_OR_NEWER
// Workaround for Unity 6.0-6.2 on Windows: close popup if mouse goes above toolbar
if (ToolbarMouseBoundary.IsAboveToolbar(rect, Event.current.mousePosition))
{
editorWindow.Close();
return;
}
#endif
GUILayout.Space(1);
Rect useVersionControlRect;
if (PopupWindowDrawing.DrawMenuItem(
PlasticLocalization.Name.UseUnityVersionControl.GetString(),
null,
null,
out useVersionControlRect))
{
ExecuteAndClosePopup(mOperations.ShowUVCSWindow);
return;
}
Rect hideVersionControlRect;
if (PopupWindowDrawing.DrawMenuItem(
PlasticLocalization.Name.HideVersionControlToolbar.GetString(),
Images.GetHideVersionControlIcon(),
null,
out hideVersionControlRect))
{
ExecuteAndClosePopup(mOperations.HideUVCSToolbarButton);
return;
}
Rect delimiterRect = new Rect(
hideVersionControlRect.x,
hideVersionControlRect.y + hideVersionControlRect.height,
hideVersionControlRect.width,
PopupWindowDrawing.DELIMITER_HEIGHT);
PopupWindowDrawing.DrawDelimiterRect(
delimiterRect,
UnityStyles.Colors.SplitLineColor);
Rect settingsRect;
if (PopupWindowDrawing.DrawMenuItem(
PlasticLocalization.Name.Settings.GetString(),
Images.GetSettingsIcon(),
null,
out settingsRect))
{
ExecuteAndClosePopup(mOperations.ShowUVCSSettings);
return;
}
Rect settingsDelimiteRect = new Rect(
settingsRect.x,
settingsRect.y + settingsRect.height,
settingsRect.width,
PopupWindowDrawing.DELIMITER_HEIGHT);
PopupWindowDrawing.DrawDelimiterRect(
settingsDelimiteRect,
UnityStyles.Colors.SplitLineColor);
Rect learnMoreRect;
if (PopupWindowDrawing.DrawMenuItem(
PlasticLocalization.Name.LearnMoreAboutUnityVersionControl.GetString(),
null,
null,
out learnMoreRect))
{
ExecuteAndClosePopup(mOperations.OpenUVCSLandingPageInBrowser);
return;
}
mLastHoveredIndex = PopupWindowDrawing.RepaintWhenHoveredMenuItemChanged(
Repaint,
mLastHoveredIndex,
useVersionControlRect,
hideVersionControlRect,
settingsRect,
learnMoreRect);
#if UNITY_EDITOR_WIN && !UNITY_6000_3_OR_NEWER
// Request continuous repaint to track mouse position even outside popup rect
if (editorWindow != null)
editorWindow.Repaint();
#endif
}
void ExecuteAndClosePopup(Action action)
{
editorWindow.Close();
EditorDispatcher.Dispatch(action);
}
void Repaint()
{
if (editorWindow == null)
return;
editorWindow.Repaint();
}
readonly Action mRepaintToolbar;
readonly UncontrolledPopupOperations mOperations;
readonly Vector2 mSize;
int mLastHoveredIndex = -1;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1ba537cc779f0474bb8c90d5315bbc74
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,463 @@
using System;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Codice.Client.Common;
using Codice.Client.Common.Threading;
using Codice.CM.Common;
using Codice.LogWrapper;
using PlasticGui;
using PlasticGui.WorkspaceWindow;
using PlasticGui.WorkspaceWindow.Topbar;
using PlasticGui.WorkspaceWindow.Topbar.WorkingObjectInfo.BranchesList;
using Unity.PlasticSCM.Editor.Toolbar.PopupWindow;
using Unity.PlasticSCM.Editor.Toolbar.PopupWindow.Operations;
using Unity.PlasticSCM.Editor.Toolbar.PopupWindow.BranchesList;
namespace Unity.PlasticSCM.Editor.Toolbar
{
internal interface IUpdateToolbarButtonVisibility
{
void Show();
void Hide();
}
internal class ToolbarController :
UpdateWorkspaceInfoBar.IWorkingObjectInfoPanel,
IRefreshableView,
IUpdateToolbarButtonVisibility
{
public const string ToolbarButtonPath = "Services/Unity Version Control"; // used by Unity 6.3+
public event Action OnToolbarButtonInvalidated = delegate { };
public event Action OnToolbarInvalidated = delegate { };
internal ToolbarController(UVCSPlugin uvcsPlugin)
{
mUVCSPlugin = uvcsPlugin;
}
internal bool IsControlledProject()
{
return mWkInfo != null;
}
internal void PopupClicked(Rect rect)
{
Vector2 buttonBottom = new Vector2(rect.x, rect.y + rect.height);
if (IsControlledProject())
{
ShowControlledPopup(buttonBottom);
return;
}
ShowUncontrolledPopup(buttonBottom);
}
internal void SetWorkspace(
WorkspaceInfo wkInfo,
bool isGluonMode)
{
mWkInfo = wkInfo;
mIsGluonMode = isGluonMode;
mModel = null;
mWorkingBranch = null;
if (mWkInfo != null)
{
// Workspace is controlled - refresh workspace info and load branches
RefreshWorkspaceWorkingInfo();
LoadBranches();
}
else
{
// Workspace is uncontrolled - reset to defaults and refresh the button
ResetToolbarButtonData();
FireOnToolbarButtonInvalidated();
}
}
internal void ExecuteSwitchToBranchUI(BranchInfo branchInfo, RepositorySpec repSpec)
{
CreateControlledPopupOperations().SwitchToBranch(branchInfo, repSpec);
}
internal void LoadBranches()
{
if (mWkInfo == null)
return;
PlasticThreadPool.Run(delegate { SetCalculatedModel(CalculateBranchesListModel(mWkInfo)); });
}
internal void RefreshWorkspaceWorkingInfo()
{
if (mWkInfo == null)
return;
UpdateWorkspaceInfoBar.UpdateWorkspaceInfo(
mWkInfo,
null,
this);
}
internal void UpdateIcon(Texture icon)
{
mDropDownButtonData.Icon = icon;
FireOnToolbarButtonInvalidated();
}
internal void UpdatePendingChangesInfoTooltipText(string pendingChangesInfoTooltipText)
{
mButtonTooltipData.PendingChangesInfo = pendingChangesInfoTooltipText;
UpdateButtonTooltip(mButtonTooltipData);
}
internal void UpdateIncomingChangesInfoTooltipText(string incomingChangesInfoTooltipText)
{
mButtonTooltipData.IncomingChangesInfo = incomingChangesInfoTooltipText;
UpdateButtonTooltip(mButtonTooltipData);
}
internal UVCSToolbarButtonData GetButtonData()
{
if (mDropDownButtonData.Icon == null)
mDropDownButtonData.Icon = UVCSPlugin.Instance.GetPluginStatusIcon();
return mDropDownButtonData;
}
internal void Enable()
{
mDropDownButtonData.IsVisible = UVCSToolbarButtonIsShownPreference.IsEnabled();
FireOnToolbarButtonInvalidated();
}
void IUpdateToolbarButtonVisibility.Show()
{
UVCSToolbarButtonIsShownPreference.Enable();
mDropDownButtonData.IsVisible = true;
FireOnToolbarButtonInvalidated();
}
void IUpdateToolbarButtonVisibility.Hide()
{
#if UNITY_6000_3_OR_NEWER
UnityEditor.Toolbars.MainToolbar.HideAll(ToolbarButtonPath);
#else
UVCSToolbarButtonIsShownPreference.Disable();
mDropDownButtonData.IsVisible = false;
FireOnToolbarButtonInvalidated();
#endif
}
void IRefreshableView.Refresh()
{
LoadBranches();
}
void UpdateWorkspaceInfoBar.IWorkingObjectInfoPanel.UpdateInfo(
string objectType,
string objectName,
string repositoryName,
string serverName)
{
if (mWkInfo == null)
return;
mDropDownButtonData.Text = GetShorten.ObjectName(
objectName,
objectType);
FireOnToolbarButtonInvalidated();
string serverForDisplay = ResolveServer.ToDisplayString(serverName);
mButtonTooltipData.WorkingObjectType = objectType;
mButtonTooltipData.WorkingObjectName = objectName;
mButtonTooltipData.RepositoryName = repositoryName;
mButtonTooltipData.ServerName = serverForDisplay;
UpdateButtonTooltip(mButtonTooltipData);
UpdateWorkingBranch(
objectType,
objectName,
repositoryName,
serverName);
}
void UpdateWorkspaceInfoBar.IWorkingObjectInfoPanel.UpdateComment(
string comment,
bool bFailed)
{
if (mWkInfo == null)
return;
string commentText = string.IsNullOrEmpty(comment) ?
PlasticLocalization.Name.NoCommentSet.GetString() :
comment;
mButtonTooltipData.Comment = commentText;
UpdateButtonTooltip(mButtonTooltipData);
}
void UpdateButtonTooltip(ButtonTooltipData buttonTooltipData)
{
if (mWkInfo == null)
return;
StringBuilder sb = new StringBuilder();
sb.Append(string.Format(
"{0}: {1}@{2}@{3}",
buttonTooltipData.WorkingObjectType,
buttonTooltipData.WorkingObjectName,
buttonTooltipData.RepositoryName,
buttonTooltipData.ServerName));
if (!string.IsNullOrEmpty(buttonTooltipData.Comment))
{
sb.AppendLine();
sb.Append(buttonTooltipData.Comment);
}
if (!string.IsNullOrEmpty(buttonTooltipData.IncomingChangesInfo))
{
sb.AppendLine();
sb.Append(buttonTooltipData.IncomingChangesInfo);
}
if (!string.IsNullOrEmpty(buttonTooltipData.PendingChangesInfo))
{
sb.AppendLine();
sb.Append(buttonTooltipData.PendingChangesInfo);
}
mDropDownButtonData.Tooltip = sb.ToString();
FireOnToolbarButtonInvalidated();
}
void FireOnToolbarInvalidated()
{
if (OnToolbarInvalidated != null)
OnToolbarInvalidated();
}
void FireOnToolbarButtonInvalidated()
{
if (OnToolbarButtonInvalidated != null)
OnToolbarButtonInvalidated();
}
void SetWorkingBranch(WorkingObjectInfo workingObjectInfo)
{
mWorkingBranch = workingObjectInfo.BranchInfo;
}
void UpdateWorkingBranch(
string objectType,
string objectName,
string repository,
string server)
{
RepositorySpec repSpec = RepositorySpec.BuildFromNameAndResolvedServer(repository, server);
if (objectType != PlasticLocalization.Name.Branch.GetString())
{
mWorkingBranch = null;
return;
}
PlasticThreadPool.Run(delegate
{
try
{
mWorkingBranch = PlasticGui.Plastic.API.GetBranchInfo(repSpec, objectName);
}
catch (Exception ex)
{
mLog.ErrorFormat("Error loading the working branch: {0}", ex.Message);
mLog.DebugFormat("Stack trace: {0}", ex.StackTrace);
}
});
}
void ShowUncontrolledPopup(Vector2 popupPosition)
{
int popupHeight = PopupWindowDrawing.MENU_ITEM_HEIGHT * 4 +
PopupWindowDrawing.DELIMITER_HEIGHT * 2;
UncontrolledPopupWindow window = new UncontrolledPopupWindow(
new UncontrolledPopupOperations(mUVCSPlugin, this),
FireOnToolbarInvalidated,
new Vector2(285, popupHeight));
UnityEditor.PopupWindow.Show(
new Rect(popupPosition, Vector2.zero), window);
}
BranchesListModel GetCalculatedModel()
{
lock (mModelLock)
{
return mModel;
}
}
void SetCalculatedModel(BranchesListModel branches)
{
lock (mModelLock)
{
mModel = branches;
mMainBranch = (mModel.Branches == null) ?
null : mModel.Branches.MainBranch;
}
}
void ShowControlledPopup(Vector2 popupPosition)
{
ControlledPopupOperations operations = CreateControlledPopupOperations();
ControlledPopupWindow window = new ControlledPopupWindow(
operations,
RefreshBranches,
() => mWorkingBranch,
FireOnToolbarInvalidated,
new Vector2(375, 425));
BranchesListModel model = GetCalculatedModel();
if (model != null)
model.ResetFilter();
window.SetModel(model);
RefreshBranches(window);
UnityEditor.PopupWindow.Show(
new Rect(popupPosition, Vector2.zero), window);
}
void RefreshBranches(ControlledPopupWindow window)
{
bool isOperationFinished = false;
Task.Delay(TimeSpan.FromMilliseconds(1500)).ContinueWith((task, state) =>
{
if (window != null && !isOperationFinished)
{
window.ShowProgressBar();
}
}, null);
BranchesListModel model = null;
IThreadWaiter waiter = ThreadWaiter.GetWaiter(50);
waiter.Execute(
threadOperationDelegate: delegate
{
model = CalculateBranchesListModel(mWkInfo);
SetCalculatedModel(model);
},
afterOperationDelegate: delegate
{
isOperationFinished = true;
if (window == null)
return;
window.HideProgressBar();
window.SetModel(model);
});
}
void ResetToolbarButtonData()
{
mButtonTooltipData = new ButtonTooltipData();
mDropDownButtonData = UVCSToolbarButtonData.BuildDefault();
}
static BranchesListModel CalculateBranchesListModel(WorkspaceInfo wkInfo)
{
try
{
RepositorySpec repSpec = PlasticGui.Plastic.API.GetRepositorySpec(wkInfo);
QueryResult queryResult = PlasticGui.Plastic.API.FindQuery(wkInfo, "find branches");
if (repSpec == null || queryResult == null)
return BranchesListModel.BuildEmpty();
ClassifiedBranchesList result = new ClassifiedBranchesList(
queryResult.Result[0].Cast<BranchInfo>().ToList(),
RecentBranchesSettings.GetRecentBranches(PlasticGuiConfig.GetConfigFile(), wkInfo.Id),
WellKnownGuids.MainBranch);
return BranchesListModel.FromBranches(result, repSpec);
}
catch (Exception ex)
{
mLog.ErrorFormat("Error loading the branches: {0}", ex.Message);
mLog.DebugFormat("Stack trace: {0}", ex.StackTrace);
return BranchesListModel.FromException(ex);
}
}
BranchInfo GetMainBranch(WorkspaceInfo wkInfo)
{
if (mMainBranch != null)
return mMainBranch;
return PlasticGui.Plastic.API.GetMainBranch(wkInfo);
}
ControlledPopupOperations CreateControlledPopupOperations()
{
return new ControlledPopupOperations(
mWkInfo,
mUVCSPlugin,
mIsGluonMode,
RefreshWorkspaceWorkingInfo,
this,
SetWorkingBranch,
() => mModel == null ? null : mModel.RepSpec,
() => GetMainBranch(mWkInfo),
() => mWorkingBranch);
}
WorkspaceInfo mWkInfo;
BranchInfo mMainBranch;
BranchInfo mWorkingBranch;
bool mIsGluonMode;
BranchesListModel mModel = BranchesListModel.BuildEmpty();
ButtonTooltipData mButtonTooltipData = new ButtonTooltipData();
UVCSToolbarButtonData mDropDownButtonData = UVCSToolbarButtonData.BuildDefault();
readonly object mModelLock = new object();
readonly UVCSPlugin mUVCSPlugin;
static readonly ILog mLog = PlasticApp.GetLogger("PlasticWindow");
class ButtonTooltipData
{
public string WorkingObjectType { get; set; }
public string WorkingObjectName { get; set; }
public string RepositoryName { get; set; }
public string ServerName { get; set; }
public string Comment { get; set; }
public string PendingChangesInfo { get; set; }
public string IncomingChangesInfo { get; set; }
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 792f2bf6e6d57db4f93253a322673bc7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,17 @@
namespace Unity.PlasticSCM.Editor.Toolbar
{
internal static class UVCSToolbar
{
internal static ToolbarController Controller
{
get { return mController; }
}
static UVCSToolbar()
{
mController = new ToolbarController(UVCSPlugin.Instance);
}
static readonly ToolbarController mController;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5717b3e29bf6a2b48be2cf9d0707c505
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,26 @@
using UnityEngine;
using PlasticGui;
using Unity.PlasticSCM.Editor.UI;
namespace Unity.PlasticSCM.Editor.Toolbar
{
internal class UVCSToolbarButtonData
{
internal bool IsVisible { get; set; }
internal string Text { get; set; }
internal string Tooltip { get; set; }
internal Texture Icon { get; set; }
internal static UVCSToolbarButtonData BuildDefault()
{
return new UVCSToolbarButtonData
{
Text = PlasticLocalization.Name.UnityVCS.GetString(),
Tooltip = PlasticLocalization.Name.UseUnityVersionControlToManageYourProject.GetString(),
Icon = Images.GetPlasticViewIcon(),
IsVisible = UVCSToolbarButtonIsShownPreference.IsEnabled()
};
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5bbb26813ae33c64d8937661111fb3c6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: