This commit is contained in:
Takashi Yoshinaga
2019-08-20 19:20:22 +09:00
parent 354a84e7d8
commit 7aa14adaf7
2259 changed files with 0 additions and 0 deletions
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 42064bc130be4c44b288d249a44b356f
timeCreated: 1504191962
@@ -0,0 +1,74 @@
using System;
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
#if !UNITY_2018_3_OR_NEWER
internal class AlertFactory : UxmlFactory<Alert>
{
protected override Alert DoCreate(IUxmlAttributes bag, CreationContext cc)
{
return new Alert();
}
}
#endif
internal class Alert : VisualElement
{
#if UNITY_2018_3_OR_NEWER
internal new class UxmlFactory : UxmlFactory<Alert> { }
#endif
private const string TemplatePath = PackageManagerWindow.ResourcesPath + "Templates/Alert.uxml";
private readonly VisualElement root;
private const float originalPositionRight = 5.0f;
private const float positionRightWithScroll = 12.0f;
public Action OnCloseError;
public Alert()
{
UIUtils.SetElementDisplay(this, false);
root = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(TemplatePath).CloneTree(null);
Add(root);
root.StretchToParentSize();
CloseButton.clickable.clicked += () =>
{
if (null != OnCloseError)
OnCloseError();
ClearError();
};
}
public void SetError(Error error)
{
var message = "An error occured.";
if (error != null)
message = error.message ?? string.Format("An error occurred ({0})", error.errorCode.ToString());
AlertMessage.text = message;
UIUtils.SetElementDisplay(this, true);
}
public void ClearError()
{
UIUtils.SetElementDisplay(this, false);
AdjustSize(false);
AlertMessage.text = "";
OnCloseError = null;
}
public void AdjustSize(bool verticalScrollerVisible)
{
if (verticalScrollerVisible)
style.positionRight = originalPositionRight + positionRightWithScroll;
else
style.positionRight = originalPositionRight;
}
private Label AlertMessage { get { return root.Q<Label>("alertMessage"); } }
private Button CloseButton { get { return root.Q<Button>("close"); } }
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b274f3d1ea05d4bd8a13f4556f7797d2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,87 @@
using UnityEngine;
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
#if !UNITY_2018_3_OR_NEWER
internal class LoadingSpinnerFactory : UxmlFactory<LoadingSpinner>
{
protected override LoadingSpinner DoCreate(IUxmlAttributes bag, CreationContext cc)
{
return new LoadingSpinner();
}
}
#endif
internal class LoadingSpinner : VisualElement
{
#if UNITY_2018_3_OR_NEWER
internal new class UxmlFactory : UxmlFactory<LoadingSpinner, UxmlTraits>
{
}
// This works around an issue with UXML instantiation
// See https://fogbugz.unity3d.com/f/cases/1046459/
internal new class UxmlTraits : VisualElement.UxmlTraits
{
public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
{
base.Init(ve, bag, cc);
UIUtils.SetElementDisplay(ve, false);
}
}
#endif
public bool InvertColor { get; set; }
public bool Started { get; private set; }
private int rotation;
public LoadingSpinner()
{
InvertColor = false;
Started = false;
UIUtils.SetElementDisplay(this, false);
}
private void UpdateProgress()
{
if (parent == null)
return;
parent.transform.rotation = Quaternion.Euler(0, 0, rotation);
rotation += 3;
if (rotation > 360)
rotation -= 360;
}
public void Start()
{
if (Started)
return;
// Weird hack to make sure loading spinner doesn't generate an error every frame.
// Cannot put in constructor as it give really strange result.
if (parent != null && parent.parent != null)
parent.parent.clippingOptions = ClippingOptions.ClipAndCacheContents;
rotation = 0;
EditorApplication.update += UpdateProgress;
Started = true;
UIUtils.SetElementDisplay(this, true);
}
public void Stop()
{
if (!Started)
return;
EditorApplication.update -= UpdateProgress;
Started = false;
UIUtils.SetElementDisplay(this, false);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 06f8e3404d534cab82fe852ff33dad77
timeCreated: 1504191988
@@ -0,0 +1,186 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
#if UNITY_2018_3_OR_NEWER
internal class PopupField<T> : Experimental.UIElements.PopupField<T>
{
private Func<T, string> m_Callback;
public override T value
{
get { return base.value; }
set
{
base.value = value;
if (m_Callback != null)
m_TextElement.text = m_Callback(m_Value);
else
m_TextElement.text = m_Value.ToString();
}
}
/// <summary>
/// Callback that will return the string to be set in the field's label.
/// </summary>
/// <param name="callback"></param>
public void SetLabelCallback(Func<T, string> callback)
{
m_Callback = callback;
}
public PopupField(List<T> choices, T defaultValue) :
base(choices, defaultValue)
{
}
public PopupField(List<T> choices, int defaultIndex) :
base(choices, defaultIndex)
{
}
}
#else
internal class PopupField<T> : BaseTextElement, INotifyValueChanged<T>
{
private readonly List<T> m_PossibleValues;
private Func<T, string> m_Callback;
private EventCallback<ChangeEvent<T>> m_valueCallback;
private T m_Value;
public T value
{
get { return m_Value; }
set
{
if (EqualityComparer<T>.Default.Equals(m_Value, value))
return;
if (!m_PossibleValues.Contains(value))
throw new ArgumentException(string.Format("Value {0} is not present in the list of possible values", value));
m_Value = value;
m_Index = m_PossibleValues.IndexOf(m_Value);
if (m_Callback != null)
text = m_Callback(m_Value);
else
text = m_Value.ToString();
#if UNITY_2018_3_OR_NEWER
MarkDirtyRepaint();
#else
Dirty(ChangeType.Repaint);
#endif
}
}
private int m_Index = -1;
public int index
{
get { return m_Index; }
set
{
if (value != m_Index)
{
if (value >= m_PossibleValues.Count || value < 0)
throw new ArgumentException(string.Format("Index {0} is beyond the scope of possible value", value));
m_Index = value;
this.value = m_PossibleValues[m_Index];
}
}
}
/// <summary>
/// Callback that will return the string to be set in the field's label.
/// </summary>
/// <param name="callback"></param>
public void SetLabelCallback(Func<T, string> callback)
{
m_Callback = callback;
}
private PopupField(List<T> possibleValues)
{
if (possibleValues == null)
throw new ArgumentNullException("possibleValues can't be null");
m_PossibleValues = possibleValues;
AddToClassList("popupField");
}
public PopupField(List<T> possibleValues, T defaultValue) :
this(possibleValues)
{
if (defaultValue == null)
throw new ArgumentNullException("defaultValue can't be null");
if (!m_PossibleValues.Contains(defaultValue))
throw new ArgumentException(string.Format("Default value {0} is not present in the list of possible values", defaultValue));
// note: idx will be set when setting value
value = defaultValue;
}
public PopupField(List<T> possibleValues, int defaultIndex) :
this(possibleValues)
{
if (defaultIndex >= m_PossibleValues.Count || defaultIndex < 0)
throw new ArgumentException(string.Format("Default Index {0} is beyond the scope of possible value", value));
// note: value will be set when setting idx
index = defaultIndex;
}
public void SetValueAndNotify(T newValue)
{
if (!EqualityComparer<T>.Default.Equals(newValue, value))
{
using (ChangeEvent<T> evt = ChangeEvent<T>.GetPooled(value, newValue))
{
value = newValue;
if (m_valueCallback != null)
m_valueCallback(evt);
}
}
}
public void OnValueChanged(EventCallback<ChangeEvent<T>> callback)
{
m_valueCallback = callback;
RegisterCallback(callback);
}
protected override void ExecuteDefaultAction(EventBase evt)
{
base.ExecuteDefaultAction(evt);
if (evt.GetEventTypeId() == MouseDownEvent.TypeId())
OnMouseDown();
}
private void OnMouseDown()
{
var menu = new GenericMenu();
foreach (T item in m_PossibleValues)
{
bool isSelected = EqualityComparer<T>.Default.Equals(item, value);
menu.AddItem(new GUIContent(item.ToString()), isSelected,
() => ChangeValueFromMenu(item));
}
var menuPosition = new Vector2(0.0f, layout.height);
menuPosition = this.LocalToWorld(menuPosition);
var menuRect = new Rect(menuPosition, Vector2.zero);
menu.DropDown(menuRect);
}
private void ChangeValueFromMenu(T menuItem)
{
SetValueAndNotify(menuItem);
}
}
#endif
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9e69df8ff024a4dc1a9e5c22725e4863
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,55 @@
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
internal static class UIUtils
{
private const string DisplayNone = "display-none";
public static void SetElementDisplay(VisualElement element, bool value)
{
if (element == null)
return;
if (value)
element.RemoveFromClassList(DisplayNone);
else
element.AddToClassList(DisplayNone);
element.visible = value;
}
public static void SetElementDisplayNonEmpty(Label element)
{
if (element == null)
return;
var empty = string.IsNullOrEmpty(element.text);
if (empty)
element.AddToClassList(DisplayNone);
else
element.RemoveFromClassList(DisplayNone);
element.visible = !empty;
}
public static void SetElementDisplayNonEmpty(Button element)
{
if (element == null)
return;
var empty = string.IsNullOrEmpty(element.text);
if (empty)
element.AddToClassList(DisplayNone);
else
element.RemoveFromClassList(DisplayNone);
element.visible = !empty;
}
public static bool IsElementVisible(VisualElement element)
{
return element.visible && !element.ClassListContains(DisplayNone);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0edd86f97b0648f685604a5582cff608
timeCreated: 1508956933
@@ -0,0 +1,66 @@
namespace UnityEditor.PackageManager.UI
{
internal class VersionItem
{
internal PackageInfo Version;
public string MenuName { get; set; }
// Base label
public string Label
{
get
{
if (Version == null)
return MenuName;
var label = Version.VersionWithoutTag;
return label;
}
}
public string DropdownLabel
{
get
{
if (Version == null)
return MenuName;
var label = MenuName + Label;
if (Version.IsLocal)
label += " - local";
if (Version.IsCurrent)
label += " - current";
if (Version.IsVerified)
label += " - verified";
else if (!string.IsNullOrEmpty(Version.Version.Prerelease))
label += string.Format(" - {0}", Version.Version.Prerelease);
else if (Version.IsPreview)
label += " - preview";
return label;
}
}
public override string ToString()
{
return DropdownLabel;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(obj, null)) return false;
if (ReferenceEquals(this, obj)) return true;
var other = (VersionItem)obj;
return Version == other.Version;
}
public override int GetHashCode()
{
return Version.GetHashCode();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3877b2be7ee07495d8918dc8937e6de2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bfd715cd54ab84c22b128149c12b516c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,34 @@
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
/// <summary>
/// Interface for Package Manager UI Extension
/// </summary>
public interface IPackageManagerExtension
{
/// <summary>
/// Creates the extension UI visual element.
/// </summary>
/// <returns>A visual element that represents the UI or null if none</returns>
VisualElement CreateExtensionUI();
/// <summary>
/// Called by the Package Manager UI when the package selection changed.
/// </summary>
/// <param name="packageInfo">The newly selected package information (can be null)</param>
void OnPackageSelectionChange(PackageManager.PackageInfo packageInfo);
/// <summary>
/// Called by the Package Manager UI when a package is added or updated.
/// </summary>
/// <param name="packageInfo">The package information</param>
void OnPackageAddedOrUpdated(PackageManager.PackageInfo packageInfo);
/// <summary>
/// Called by the Package Manager UI when a package is removed.
/// </summary>
/// <param name="packageInfo">The package information</param>
void OnPackageRemoved(PackageManager.PackageInfo packageInfo);
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 66083b7f6dc2e433eae33f3244b2ce88
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,134 @@
using UnityEngine;
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
#if !UNITY_2018_3_OR_NEWER
internal class PackageAddFromUrlFieldFactory : UxmlFactory<PackageAddFromUrlField>
{
protected override PackageAddFromUrlField DoCreate(IUxmlAttributes bag, CreationContext cc)
{
return new PackageAddFromUrlField();
}
}
#endif
internal class PackageAddFromUrlField : VisualElement
{
#if UNITY_2018_3_OR_NEWER
internal new class UxmlFactory : UxmlFactory<PackageAddFromUrlField> { }
#endif
private string urlText;
private readonly VisualElement root;
public PackageAddFromUrlField()
{
root = Resources.GetTemplate("PackageAddFromUrlField.uxml");
Add(root);
UrlTextField.value = urlText;
AddButton.SetEnabled(!string.IsNullOrEmpty(urlText));
AddButton.clickable.clicked += OnAddButtonClick;
RegisterCallback<AttachToPanelEvent>(OnEnterPanel);
RegisterCallback<DetachFromPanelEvent>(OnLeavePanel);
}
private void OnUrlTextFieldChange(ChangeEvent<string> evt)
{
urlText = evt.newValue;
AddButton.SetEnabled(!string.IsNullOrEmpty(urlText));
}
private void OnUrlTextFieldFocus(FocusEvent evt)
{
Show();
}
private void OnUrlTextFieldFocusOut(FocusOutEvent evt)
{
Hide();
}
private void OnContainerFocus(FocusEvent evt)
{
UrlTextField.Focus();
}
private void OnContainerFocusOut(FocusOutEvent evt)
{
Hide();
}
private void OnEnterPanel(AttachToPanelEvent evt)
{
AddFromUrlFieldContainer.RegisterCallback<FocusEvent>(OnContainerFocus);
AddFromUrlFieldContainer.RegisterCallback<FocusOutEvent>(OnContainerFocusOut);
UrlTextField.RegisterCallback<FocusEvent>(OnUrlTextFieldFocus);
UrlTextField.RegisterCallback<FocusOutEvent>(OnUrlTextFieldFocusOut);
UrlTextField.RegisterCallback<ChangeEvent<string>>(OnUrlTextFieldChange);
UrlTextField.RegisterCallback<KeyDownEvent>(OnKeyDownShortcut);
Hide();
}
private void OnLeavePanel(DetachFromPanelEvent evt)
{
AddFromUrlFieldContainer.UnregisterCallback<FocusEvent>(OnContainerFocus);
AddFromUrlFieldContainer.UnregisterCallback<FocusOutEvent>(OnContainerFocusOut);
UrlTextField.UnregisterCallback<FocusEvent>(OnUrlTextFieldFocus);
UrlTextField.UnregisterCallback<FocusOutEvent>(OnUrlTextFieldFocusOut);
UrlTextField.UnregisterCallback<ChangeEvent<string>>(OnUrlTextFieldChange);
UrlTextField.UnregisterCallback<KeyDownEvent>(OnKeyDownShortcut);
}
private void OnKeyDownShortcut(KeyDownEvent evt)
{
switch (evt.keyCode)
{
case KeyCode.Escape:
Hide();
break;
case KeyCode.Return:
case KeyCode.KeypadEnter:
OnAddButtonClick();
break;
}
}
private void OnAddButtonClick()
{
var path = urlText;
if (!string.IsNullOrEmpty(path) && !Package.AddRemoveOperationInProgress)
{
Package.AddFromLocalDisk(path);
Hide();
}
}
internal void Hide()
{
UIUtils.SetElementDisplay(this, false);
}
internal void Show(bool reset = false)
{
if (reset)
Reset();
UIUtils.SetElementDisplay(this, true);
}
private void Reset()
{
UrlTextField.value = string.Empty;
urlText = string.Empty;
AddButton.SetEnabled(false);
UrlTextField.Focus();
}
private VisualElement AddFromUrlFieldContainer { get { return root.Q<VisualElement>("addFromUrlFieldContainer"); }}
private TextField UrlTextField { get { return root.Q<TextField>("urlTextField"); } }
private Button AddButton{ get { return root.Q<Button>("addFromUrlButton"); }}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 40f980217d9196e4baa9ebd2ac1328af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,626 @@
using System.Collections.Generic;
using System.Linq;
using Semver;
using UnityEngine;
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
#if !UNITY_2018_3_OR_NEWER
internal class PackageDetailsFactory : UxmlFactory<PackageDetails>
{
protected override PackageDetails DoCreate(IUxmlAttributes bag, CreationContext cc)
{
return new PackageDetails();
}
}
#endif
internal class PackageDetails : VisualElement
{
#if UNITY_2018_3_OR_NEWER
internal new class UxmlFactory : UxmlFactory<PackageDetails> { }
#endif
private readonly VisualElement root;
private Package package;
private const string emptyDescriptionClass = "empty";
private List<VersionItem> VersionItems;
internal PopupField<VersionItem> VersionPopup;
private PackageInfo DisplayPackage;
private PackageInfo SelectedPackage
{
get { return VersionPopup.value.Version != null ? VersionPopup.value.Version : null; }
}
internal enum PackageAction
{
Add,
Remove,
Update,
Downgrade,
Enable,
Disable,
UpToDate,
Current,
Local,
Git,
Embedded
}
private static readonly VersionItem EmptyVersion = new VersionItem {Version = null};
internal static readonly string[] PackageActionVerbs = { "Install", "Remove", "Update to", "Update to", "Enable", "Disable", "Up to date", "Current", "Local", "Git", "Embedded" };
internal static readonly string[] PackageActionInProgressVerbs = { "Installing", "Removing", "Updating to", "Updating to", "Enabling", "Disabling", "Up to date", "Current", "Local", "Git", "Embedded" };
public PackageDetails()
{
UIUtils.SetElementDisplay(this, false);
root = Resources.GetTemplate("PackageDetails.uxml");
Add(root);
foreach (var extension in PackageManagerExtensions.Extensions)
CustomContainer.Add(extension.CreateExtensionUI());
root.StretchToParentSize();
SetUpdateVisibility(false);
RemoveButton.visible = false;
UpdateBuiltIn.visible = false;
UpdateButton.clickable.clicked += UpdateClick;
UpdateBuiltIn.clickable.clicked += UpdateClick;
RemoveButton.clickable.clicked += RemoveClick;
ViewDocButton.clickable.clicked += ViewDocClick;
ViewChangelogButton.clickable.clicked += ViewChangelogClick;
ViewLicenses.clickable.clicked += ViewLicensesClick;
VersionItems = new List<VersionItem> {EmptyVersion};
VersionPopup = new PopupField<VersionItem>(VersionItems, 0);
VersionPopup.SetLabelCallback(VersionSelectionSetLabel);
VersionPopup.AddToClassList("popup");
VersionPopup.OnValueChanged(VersionSelectionChanged);
if (VersionItems.Count == 1)
VersionPopup.SetEnabled(false);
UpdateDropdownContainer.Add(VersionPopup);
VersionPopup.StretchToParentSize();
// Fix button on dark skin but overlapping edge pixel perfectly
if (EditorGUIUtility.isProSkin)
{
VersionPopup.style.positionLeft = -1;
UpdateDropdownContainer.style.sliceLeft = 4;
}
}
private string VersionSelectionSetLabel(VersionItem item)
{
return item.Label;
}
private void VersionSelectionChanged(ChangeEvent<VersionItem> e)
{
RefreshAddButton();
}
private void SetUpdateVisibility(bool value)
{
if (UpdateContainer != null)
UIUtils.SetElementDisplay(UpdateContainer, value);
}
internal void SetDisplayPackage(PackageInfo packageInfo)
{
DisplayPackage = packageInfo;
var detailVisible = true;
Error error = null;
if (package == null || DisplayPackage == null)
{
detailVisible = false;
UIUtils.SetElementDisplay(DocumentationContainer, false);
UIUtils.SetElementDisplay(CustomContainer, false);
UIUtils.SetElementDisplay(UpdateBuiltIn, false);
foreach (var extension in PackageManagerExtensions.Extensions)
extension.OnPackageSelectionChange(null);
}
else
{
SetUpdateVisibility(true);
UIUtils.SetElementDisplay(ViewDocButton, true);
RemoveButton.visible = true;
if (string.IsNullOrEmpty(DisplayPackage.Description))
{
DetailDesc.text = "There is no description for this package.";
DetailDesc.AddToClassList(emptyDescriptionClass);
}
else
{
DetailDesc.text = DisplayPackage.Description;
DetailDesc.RemoveFromClassList(emptyDescriptionClass);
}
root.Q<Label>("detailTitle").text = DisplayPackage.DisplayName;
DetailVersion.text = "Version " + DisplayPackage.VersionWithoutTag;
if (DisplayPackage.IsInDevelopment || DisplayPackage.HasVersionTag(PackageTag.preview))
UIUtils.SetElementDisplay(GetTag(PackageTag.verified), false);
else
{
var unityVersionParts = Application.unityVersion.Split('.');
var unityVersion = string.Format("{0}.{1}", unityVersionParts[0], unityVersionParts[1]);
VerifyLabel.text = unityVersion + " verified";
UIUtils.SetElementDisplay(GetTag(PackageTag.verified), DisplayPackage.IsVerified);
}
UIUtils.SetElementDisplay(GetTag(PackageTag.inDevelopment), DisplayPackage.IsInDevelopment);
UIUtils.SetElementDisplay(GetTag(PackageTag.local), DisplayPackage.IsLocal);
UIUtils.SetElementDisplay(GetTag(PackageTag.preview), DisplayPackage.IsPreview);
UIUtils.SetElementDisplay(DocumentationContainer, DisplayPackage.Origin != PackageSource.BuiltIn);
UIUtils.SetElementDisplay(ChangelogContainer, DisplayPackage.HasChangelog(DisplayPackage));
root.Q<Label>("detailName").text = DisplayPackage.Name;
root.Q<ScrollView>("detailView").scrollOffset = new Vector2(0, 0);
DetailModuleReference.text = "";
var isBuiltIn = DisplayPackage.IsBuiltIn;
if (isBuiltIn)
DetailModuleReference.text = DisplayPackage.BuiltInDescription;
DetailAuthor.text = "";
if (!string.IsNullOrEmpty(DisplayPackage.Author))
DetailAuthor.text = string.Format("Author: {0}", DisplayPackage.Author);
UIUtils.SetElementDisplay(DetailDesc, !isBuiltIn);
UIUtils.SetElementDisplay(DetailVersion, !isBuiltIn);
UIUtils.SetElementDisplayNonEmpty(DetailModuleReference);
UIUtils.SetElementDisplayNonEmpty(DetailAuthor);
if (DisplayPackage.Errors.Count > 0)
error = DisplayPackage.Errors.First();
RefreshAddButton();
RefreshRemoveButton();
UIUtils.SetElementDisplay(CustomContainer, true);
package.AddSignal.OnOperation += OnAddOperation;
package.RemoveSignal.OnOperation += OnRemoveOperation;
foreach (var extension in PackageManagerExtensions.Extensions)
extension.OnPackageSelectionChange(DisplayPackage.Info);
}
// Set visibility
root.Q<VisualElement>("detail").visible = detailVisible;
if (null == error)
error = PackageCollection.Instance.GetPackageError(package);
if (error != null)
SetError(error);
else
DetailError.ClearError();
}
private void ResetVersionItems(PackageInfo displayPackage)
{
VersionItems.Clear();
VersionPopup.SetEnabled(true);
if (displayPackage == null)
return;
//
// Get key versions -- Latest, Verified, LatestPatch, Current.
var keyVersions = new List<PackageInfo>();
if (package.LatestRelease != null) keyVersions.Add(package.LatestRelease);
if (package.Current != null) keyVersions.Add(package.Current);
if (package.Verified != null && package.Verified != package.Current) keyVersions.Add(package.Verified);
if (package.LatestPatch != null && package.IsAfterCurrentVersion(package.LatestPatch)) keyVersions.Add(package.LatestPatch);
if (package.Current == null && package.LatestRelease == null && package.Latest != null) keyVersions.Add(package.Latest);
if (Package.ShouldProposeLatestVersions && package.Latest != package.LatestRelease && package.Latest != null) keyVersions.Add(package.Latest);
keyVersions.Add(package.LatestUpdate); // Make sure LatestUpdate is always in the list.
foreach (var version in keyVersions.OrderBy(package => package.Version).Reverse())
{
var item = new VersionItem {Version = version};
VersionItems.Add(item);
if (version == package.LatestUpdate)
VersionPopup.value = item;
}
//
// Add all versions
foreach (var version in package.Versions.Reverse())
{
var item = new VersionItem {Version = version};
item.MenuName = "All Versions/";
VersionItems.Add(item);
}
if (VersionItems.Count == 0)
{
VersionItems.Add(EmptyVersion);
VersionPopup.value = EmptyVersion;
VersionPopup.SetEnabled(false);
}
}
public void SetPackage(Package package)
{
if (this.package != null)
{
if (this.package.AddSignal.Operation != null)
{
this.package.AddSignal.Operation.OnOperationError -= OnAddOperationError;
this.package.AddSignal.Operation.OnOperationSuccess -= OnAddOperationSuccess;
}
this.package.AddSignal.ResetEvents();
if (this.package.RemoveSignal.Operation != null)
{
this.package.RemoveSignal.Operation.OnOperationSuccess -= OnRemoveOperationSuccess;
this.package.RemoveSignal.Operation.OnOperationError -= OnRemoveOperationError;
}
this.package.RemoveSignal.ResetEvents();
}
UIUtils.SetElementDisplay(this, true);
this.package = package;
var displayPackage = package != null ? package.VersionToDisplay : null;
ResetVersionItems(displayPackage);
SetDisplayPackage(displayPackage);
}
private void SetError(Error error)
{
DetailError.AdjustSize(DetailView.verticalScroller.visible);
DetailError.SetError(error);
DetailError.OnCloseError = () =>
{
PackageCollection.Instance.RemovePackageErrors(package);
PackageCollection.Instance.UpdatePackageCollection();
};
}
private void OnAddOperation(IAddOperation operation)
{
operation.OnOperationError += OnAddOperationError;
operation.OnOperationSuccess += OnAddOperationSuccess;
}
private void OnAddOperationError(Error error)
{
if (package != null && package.AddSignal.Operation != null)
{
package.AddSignal.Operation.OnOperationSuccess -= OnAddOperationSuccess;
package.AddSignal.Operation.OnOperationError -= OnAddOperationError;
package.AddSignal.Operation = null;
}
PackageCollection.Instance.AddPackageError(package, error);
SetError(error);
if (package != null)
ResetVersionItems(package.VersionToDisplay);
PackageCollection.Instance.UpdatePackageCollection();
}
private void OnAddOperationSuccess(PackageInfo packageInfo)
{
if (package != null && package.AddSignal.Operation != null)
{
package.AddSignal.Operation.OnOperationSuccess -= OnAddOperationSuccess;
package.AddSignal.Operation.OnOperationError -= OnAddOperationError;
package.AddSignal.Operation = null;
}
foreach (var extension in PackageManagerExtensions.Extensions)
extension.OnPackageAddedOrUpdated(packageInfo.Info);
}
private void OnRemoveOperation(IRemoveOperation operation)
{
// Make sure we are not already registered
operation.OnOperationError -= OnRemoveOperationError;
operation.OnOperationSuccess -= OnRemoveOperationSuccess;
operation.OnOperationError += OnRemoveOperationError;
operation.OnOperationSuccess += OnRemoveOperationSuccess;
}
private void OnRemoveOperationError(Error error)
{
if (package != null && package.RemoveSignal.Operation != null)
{
package.RemoveSignal.Operation.OnOperationSuccess -= OnRemoveOperationSuccess;
package.RemoveSignal.Operation.OnOperationError -= OnRemoveOperationError;
package.RemoveSignal.Operation = null;
}
PackageCollection.Instance.AddPackageError(package, error);
SetError(error);
PackageCollection.Instance.UpdatePackageCollection();
}
private void OnRemoveOperationSuccess(PackageInfo packageInfo)
{
if (package != null && package.RemoveSignal.Operation != null)
{
package.RemoveSignal.Operation.OnOperationSuccess -= OnRemoveOperationSuccess;
package.RemoveSignal.Operation.OnOperationError -= OnRemoveOperationError;
package.RemoveSignal.Operation = null;
}
foreach (var extension in PackageManagerExtensions.Extensions)
extension.OnPackageRemoved(packageInfo.Info);
}
private void RefreshAddButton()
{
if (package.Current != null && package.Current.IsInDevelopment)
{
UIUtils.SetElementDisplay(UpdateBuiltIn, false);
UIUtils.SetElementDisplay(UpdateCombo, false);
UIUtils.SetElementDisplay(UpdateButton, false);
return;
}
var targetVersion = SelectedPackage;
if (targetVersion == null)
return;
var enableButton = !Package.AddRemoveOperationInProgress;
var enableVersionButton = true;
var action = PackageAction.Update;
var inprogress = false;
var isBuiltIn = package.IsBuiltIn;
SemVersion version = null;
if (package.AddSignal.Operation != null)
{
if (isBuiltIn)
{
action = PackageAction.Enable;
inprogress = true;
enableButton = false;
}
else
{
var addOperationVersion = package.AddSignal.Operation.PackageInfo.Version;
if (package.Current == null)
{
action = PackageAction.Add;
inprogress = true;
}
else
{
action = addOperationVersion.CompareByPrecedence(package.Current.Version) >= 0
? PackageAction.Update : PackageAction.Downgrade;
inprogress = true;
}
enableButton = false;
enableVersionButton = false;
}
}
else
{
if (package.Current != null)
{
// Installed
if (package.Current.IsVersionLocked)
{
if (package.Current.Origin == PackageSource.Embedded)
action = PackageAction.Embedded;
else if (package.Current.Origin == PackageSource.Git)
action = PackageAction.Git;
enableButton = false;
enableVersionButton = false;
}
else
{
if (targetVersion.IsCurrent)
{
if (targetVersion == package.LatestUpdate)
action = PackageAction.UpToDate;
else
action = PackageAction.Current;
enableButton = false;
}
else
{
action = targetVersion.Version.CompareByPrecedence(package.Current.Version) >= 0
? PackageAction.Update : PackageAction.Downgrade;
}
}
}
else
{
// Not Installed
if (package.Versions.Any())
{
if (isBuiltIn)
action = PackageAction.Enable;
else
action = PackageAction.Add;
}
}
}
if (package.RemoveSignal.Operation != null)
enableButton = false;
if (EditorApplication.isCompiling)
{
enableButton = false;
enableVersionButton = false;
EditorApplication.update -= CheckCompilationStatus;
EditorApplication.update += CheckCompilationStatus;
}
var button = isBuiltIn ? UpdateBuiltIn : UpdateButton;
button.SetEnabled(enableButton);
VersionPopup.SetEnabled(enableVersionButton);
button.text = GetButtonText(action, inprogress, version);
var visibleFlag = !(package.Current != null && package.Current.IsVersionLocked);
UIUtils.SetElementDisplay(UpdateBuiltIn, isBuiltIn && visibleFlag);
UIUtils.SetElementDisplay(UpdateCombo, !isBuiltIn && visibleFlag);
UIUtils.SetElementDisplay(UpdateButton, !isBuiltIn && visibleFlag);
}
private void RefreshRemoveButton()
{
var visibleFlag = false;
var current = package.Current;
// Show only if there is a current package installed
if (current != null)
{
visibleFlag = current.CanBeRemoved && !package.IsPackageManagerUI;
var action = current.IsBuiltIn ? PackageAction.Disable : PackageAction.Remove;
var inprogress = package.RemoveSignal.Operation != null;
var enableButton = visibleFlag && !EditorApplication.isCompiling && !inprogress && !Package.AddRemoveOperationInProgress;
if (EditorApplication.isCompiling)
{
EditorApplication.update -= CheckCompilationStatus;
EditorApplication.update += CheckCompilationStatus;
}
RemoveButton.SetEnabled(enableButton);
RemoveButton.text = GetButtonText(action, inprogress);
}
UIUtils.SetElementDisplay(RemoveButton, visibleFlag);
}
private void CheckCompilationStatus()
{
if (EditorApplication.isCompiling)
return;
RefreshAddButton();
RefreshRemoveButton();
EditorApplication.update -= CheckCompilationStatus;
}
private static string GetButtonText(PackageAction action, bool inProgress = false, SemVersion version = null)
{
return version == null ?
string.Format("{0}", inProgress ? PackageActionInProgressVerbs[(int) action] : PackageActionVerbs[(int) action]) :
string.Format("{0} {1}", inProgress ? PackageActionInProgressVerbs[(int) action] : PackageActionVerbs[(int) action], version);
}
private void UpdateClick()
{
if (package.IsPackageManagerUI)
{
// Let's not allow updating of the UI if there are build errrors, as for now, that will prevent the UI from reloading properly.
if (EditorUtility.scriptCompilationFailed)
{
EditorUtility.DisplayDialog("Unity Package Manager", "The Package Manager UI cannot be updated while there are script compilation errors in your project. Please fix the errors and try again.", "Ok");
return;
}
if (!EditorUtility.DisplayDialog("Unity Package Manager", "Updating this package will close the Package Manager window. You will have to re-open it after the update is done. Do you want to continue?", "Yes", "No"))
return;
if (package.AddSignal.Operation != null)
{
package.AddSignal.Operation.OnOperationSuccess -= OnAddOperationSuccess;
package.AddSignal.Operation.OnOperationError -= OnAddOperationError;
package.AddSignal.ResetEvents();
package.AddSignal.Operation = null;
}
DetailError.ClearError();
EditorApplication.update += CloseAndUpdate;
return;
}
DetailError.ClearError();
package.Add(SelectedPackage);
RefreshAddButton();
RefreshRemoveButton();
}
private void CloseAndUpdate()
{
EditorApplication.update -= CloseAndUpdate;
package.Add(SelectedPackage);
var windows = UnityEngine.Resources.FindObjectsOfTypeAll<PackageManagerWindow>();
if (windows.Length > 0)
{
windows[0].Close();
}
}
private void RemoveClick()
{
DetailError.ClearError();
package.Remove();
RefreshRemoveButton();
RefreshAddButton();
}
private void ViewDocClick()
{
Application.OpenURL(DisplayPackage.GetDocumentationUrl());
}
private void ViewChangelogClick()
{
Application.OpenURL(DisplayPackage.GetChangelogUrl());
}
private void ViewLicensesClick()
{
Application.OpenURL(DisplayPackage.GetLicensesUrl());
}
private Label DetailDesc { get { return root.Q<Label>("detailDesc"); } }
internal Button UpdateButton { get { return root.Q<Button>("update"); } }
private Button RemoveButton { get { return root.Q<Button>("remove"); } }
private Button ViewDocButton { get { return root.Q<Button>("viewDocumentation"); } }
private VisualElement DocumentationContainer { get { return root.Q<VisualElement>("documentationContainer"); } }
private Button ViewChangelogButton { get { return root.Q<Button>("viewChangelog"); } }
private VisualElement ChangelogContainer { get { return root.Q<VisualElement>("changeLogContainer"); } }
private VisualElement ViewLicensesContainer { get { return root.Q<VisualElement>("viewLicensesContainer"); } }
private Button ViewLicenses { get { return root.Q<Button>("viewLicenses"); } }
private VisualElement UpdateContainer { get { return root.Q<VisualElement>("updateContainer"); } }
private Alert DetailError { get { return root.Q<Alert>("detailError"); } }
private ScrollView DetailView { get { return root.Q<ScrollView>("detailView"); } }
private Label DetailModuleReference { get { return root.Q<Label>("detailModuleReference"); } }
private Label DetailVersion { get { return root.Q<Label>("detailVersion"); }}
private Label DetailAuthor { get { return root.Q<Label>("detailAuthor"); }}
private Label VerifyLabel { get { return root.Q<Label>("tagVerify"); } }
private VisualElement CustomContainer { get { return root.Q<VisualElement>("detailCustomContainer"); } }
internal VisualElement GetTag(PackageTag tag) {return root.Q<VisualElement>("tag-" + tag); }
private VisualElement UpdateDropdownContainer { get { return root.Q<VisualElement>("updateDropdownContainer"); } }
internal VisualElement UpdateCombo { get { return root.Q<VisualElement>("updateCombo"); } }
internal Button UpdateBuiltIn { get { return root.Q<Button>("updateBuiltIn"); } }
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 3f3e22b18940a4e828a5170574a3617e
timeCreated: 1502224642
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,96 @@
using System;
using System.Text.RegularExpressions;
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
internal static class PackageFiltering
{
private static bool FilterByText(PackageInfo info, string text)
{
if (info == null)
return false;
if (info.Name.IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0)
return true;
if (!string.IsNullOrEmpty(info.DisplayName) && info.DisplayName.IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0)
return true;
if (!info.IsBuiltIn)
{
var prerelease = text.StartsWith("-") ? text.Substring(1) : text;
if (info.Version != null && info.Version.Prerelease.IndexOf(prerelease, StringComparison.CurrentCultureIgnoreCase) >= 0)
return true;
if (info.VersionWithoutTag.StartsWith(text, StringComparison.CurrentCultureIgnoreCase))
return true;
if (info.IsPreview)
{
if (PackageTag.preview.ToString().IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0)
return true;
}
if (info.IsVerified)
{
if (PackageTag.verified.ToString().IndexOf(text, StringComparison.CurrentCultureIgnoreCase) >= 0)
return true;
}
}
return false;
}
internal static bool FilterByText(Package package, string text)
{
if (string.IsNullOrEmpty(text))
return true;
var trimText = text.Trim(' ', '\t');
trimText = Regex.Replace(trimText, @"[ ]{2,}", " ");
return string.IsNullOrEmpty(trimText) || FilterByText(package.Current ?? package.Latest, trimText);
}
private static bool FilterByText(PackageItem item, string text)
{
return item.package != null && FilterByText(item.package, text);
}
public static void FilterPackageList(PackageList packageList)
{
PackageItem firstItem = null;
PackageItem lastItem = null;
var selectedItemInFilter = false;
var selectedItem = packageList.selectedItem;
var packageItems = packageList.Query<PackageItem>().ToList();
foreach (var item in packageItems)
{
if (FilterByText(item, PackageSearchFilter.Instance.SearchText))
{
if (firstItem == null)
firstItem = item;
if (item == selectedItem)
selectedItemInFilter = true;
UIUtils.SetElementDisplay(item, true);
if (lastItem != null)
lastItem.nextItem = item;
item.previousItem = lastItem;
item.nextItem = null;
lastItem = item;
}
else
UIUtils.SetElementDisplay(item, false);
}
if (firstItem == null)
packageList.ShowNoResults();
else
packageList.ShowResults(selectedItemInFilter ? selectedItem : firstItem);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5ffd2adf615994485991e37bacbf735c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,75 @@
using System.Linq;
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
#if !UNITY_2018_3_OR_NEWER
internal class PackageGroupFactory : UxmlFactory<PackageGroup>
{
protected override PackageGroup DoCreate(IUxmlAttributes bag, CreationContext cc)
{
return new PackageGroup(bag.GetPropertyString("name"));
}
}
#endif
internal class PackageGroup : VisualElement
{
#if UNITY_2018_3_OR_NEWER
internal new class UxmlFactory : UxmlFactory<PackageGroup> { }
#endif
private readonly VisualElement root;
internal readonly PackageGroupOrigins Origin;
public PackageGroup previousGroup;
public PackageGroup nextGroup;
public PackageItem firstPackage;
public PackageItem lastPackage;
public PackageGroup() : this(string.Empty)
{
}
public PackageGroup(string groupName)
{
name = groupName;
root = Resources.GetTemplate("PackageGroup.uxml");
Add(root);
if (string.IsNullOrEmpty(groupName) || groupName != PackageGroupOrigins.BuiltInPackages.ToString())
{
HeaderTitle.text = "Packages";
Origin = PackageGroupOrigins.Packages;
}
else
{
HeaderTitle.text = "Built In Packages";
Origin = PackageGroupOrigins.BuiltInPackages;
}
}
internal PackageItem AddPackage(Package package)
{
var packageItem = new PackageItem(package) {packageGroup = this};
var lastItem = List.Children().LastOrDefault() as PackageItem;
if (lastItem != null)
{
lastItem.nextItem = packageItem;
packageItem.previousItem = lastItem;
packageItem.nextItem = null;
}
List.Add(packageItem);
if (firstPackage == null) firstPackage = packageItem;
lastPackage = packageItem;
return packageItem;
}
private VisualElement List { get { return root.Q<VisualElement>("groupContainer"); } }
private Label HeaderTitle { get { return root.Q<Label>("headerTitle"); } }
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 760934a36e5f490db3c9fcaf497625a4
timeCreated: 1508509771
@@ -0,0 +1,150 @@
using UnityEngine.Experimental.UIElements;
using System;
namespace UnityEditor.PackageManager.UI
{
#if !UNITY_2018_3_OR_NEWER
internal class PackageItemFactory : UxmlFactory<PackageItem>
{
protected override PackageItem DoCreate(IUxmlAttributes bag, CreationContext cc)
{
return new PackageItem();
}
}
#endif
internal class PackageItem : VisualElement
{
#if UNITY_2018_3_OR_NEWER
internal new class UxmlFactory : UxmlFactory<PackageItem> { }
#endif
public static string SelectedClassName = "selected";
public event Action<PackageItem> OnSelected = delegate { };
private readonly VisualElement root;
private string currentStateClass;
public Package package { get; private set; }
public PackageItem previousItem;
public PackageItem nextItem;
public PackageGroup packageGroup;
public PackageItem() : this(null)
{
}
public PackageItem(Package package)
{
root = Resources.GetTemplate("PackageItem.uxml");
Add(root);
root.AddManipulator(new Clickable(Select));
SetItem(package);
}
private void Select()
{
OnSelected(this);
}
public void SetSelected(bool value)
{
if (value)
PackageContainer.AddToClassList(SelectedClassName);
else
PackageContainer.RemoveFromClassList(SelectedClassName);
Spinner.InvertColor = value;
}
private void SetItem(Package package)
{
var displayPackage = package != null ? package.VersionToDisplay : null;
if (displayPackage == null)
return;
this.package = package;
OnPackageChanged();
this.package.AddSignal.WhenOperation(OnPackageAdd);
this.package.RemoveSignal.WhenOperation(OnPackageRemove);
}
private void OnPackageRemove(IRemoveOperation operation)
{
operation.OnOperationError += error => StopSpinner();
OnPackageUpdate();
}
private void OnPackageAdd(IAddOperation operation)
{
operation.OnOperationError += error => StopSpinner();
OnPackageUpdate();
}
private void OnPackageChanged()
{
var displayPackage = package != null ? package.VersionToDisplay : null;
if (displayPackage == null)
return;
NameLabel.text = displayPackage.DisplayName;
VersionLabel.text = displayPackage.Version.ToString();
var stateClass = GetIconStateId(displayPackage);
if (displayPackage.State == PackageState.Outdated && package.LatestUpdate == package.Current)
stateClass = GetIconStateId(PackageState.UpToDate);
if (PackageCollection.Instance.GetPackageError(package) != null)
stateClass = GetIconStateId(PackageState.Error);
if (stateClass == GetIconStateId(PackageState.UpToDate) && package.Current != null)
stateClass = "installed";
StateLabel.RemoveFromClassList(currentStateClass);
StateLabel.AddToClassList(stateClass);
UIUtils.SetElementDisplay(VersionLabel, !displayPackage.IsBuiltIn);
currentStateClass = stateClass;
if (displayPackage.State != PackageState.InProgress && Spinner.Started)
StopSpinner();
}
private void OnPackageUpdate()
{
StartSpinner();
}
private void StartSpinner()
{
Spinner.Start();
StateLabel.AddToClassList("no-icon");
}
private void StopSpinner()
{
Spinner.Stop();
StateLabel.RemoveFromClassList("no-icon");
}
private Label NameLabel { get { return root.Q<Label>("packageName"); } }
private Label StateLabel { get { return root.Q<Label>("packageState"); } }
private Label VersionLabel { get { return root.Q<Label>("packageVersion"); } }
private VisualElement PackageContainer { get { return root.Q<VisualElement>("packageContainer"); } }
private LoadingSpinner Spinner { get { return root.Q<LoadingSpinner>("packageSpinner"); } }
public static string GetIconStateId(PackageInfo packageInfo)
{
if (packageInfo == null)
return "";
return GetIconStateId(packageInfo.State);
}
public static string GetIconStateId(PackageState state)
{
return state.ToString().ToLower();
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: c68ba5b432ef64e67ae0bf74960908a8
timeCreated: 1502224642
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,408 @@
using UnityEngine.Experimental.UIElements;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace UnityEditor.PackageManager.UI
{
#if !UNITY_2018_3_OR_NEWER
internal class PackageListFactory : UxmlFactory<PackageList>
{
protected override PackageList DoCreate(IUxmlAttributes bag, CreationContext cc)
{
return new PackageList();
}
}
#endif
internal class PackageList : VisualElement
{
#if UNITY_2018_3_OR_NEWER
internal new class UxmlFactory : UxmlFactory<PackageList> { }
#endif
public event Action<Package> OnSelected = delegate { };
public event Action OnLoaded = delegate { };
public event Action OnFocusChange = delegate { };
private readonly VisualElement root;
internal PackageItem selectedItem;
private List<PackageGroup> Groups;
public PackageList()
{
Groups = new List<PackageGroup>();
root = Resources.GetTemplate("PackageList.uxml");
Add(root);
root.StretchToParentSize();
UIUtils.SetElementDisplay(Empty, false);
UIUtils.SetElementDisplay(NoResult, false);
PackageCollection.Instance.OnPackagesChanged += SetPackages;
RegisterCallback<AttachToPanelEvent>(OnEnterPanel);
RegisterCallback<DetachFromPanelEvent>(OnLeavePanel);
Reload();
}
public void GrabFocus()
{
if (selectedItem == null)
return;
selectedItem.Focus();
}
public void ShowResults(PackageItem item)
{
NoResultText.text = string.Empty;
UIUtils.SetElementDisplay(NoResult, false);
Select(item);
EditorApplication.delayCall += ScrollIfNeeded;
UpdateGroups();
}
public void ShowNoResults()
{
NoResultText.text = string.Format("No results for \"{0}\"", PackageSearchFilter.Instance.SearchText);
UIUtils.SetElementDisplay(NoResult, true);
foreach (var group in Groups)
{
UIUtils.SetElementDisplay(group, false);
}
Select(null);
OnSelected(null);
}
private void UpdateGroups()
{
foreach (var group in Groups)
{
PackageItem firstPackage = null;
PackageItem lastPackage = null;
var listGroup = group.Query<PackageItem>().ToList();
foreach (var item in listGroup)
{
if (!item.visible)
continue;
if (firstPackage == null) firstPackage = item;
lastPackage = item;
}
if (firstPackage == null && lastPackage == null)
{
UIUtils.SetElementDisplay(group, false);
}
else
{
UIUtils.SetElementDisplay(group, true);
group.firstPackage = firstPackage;
group.lastPackage = lastPackage;
}
}
}
private void OnEnterPanel(AttachToPanelEvent e)
{
panel.visualTree.RegisterCallback<KeyDownEvent>(OnKeyDownShortcut);
}
private void OnLeavePanel(DetachFromPanelEvent e)
{
panel.visualTree.UnregisterCallback<KeyDownEvent>(OnKeyDownShortcut);
}
private void ScrollIfNeeded()
{
EditorApplication.delayCall -= ScrollIfNeeded;
if (selectedItem == null)
return;
var minY = List.worldBound.yMin;
var maxY = List.worldBound.yMax;
var itemMinY = selectedItem.worldBound.yMin;
var itemMaxY = selectedItem.worldBound.yMax;
var scroll = List.scrollOffset;
if (itemMinY < minY)
{
scroll.y -= minY - itemMinY;
if (scroll.y <= minY)
scroll.y = 0;
List.scrollOffset = scroll;
}
else if (itemMaxY > maxY)
{
scroll.y += itemMaxY - maxY;
List.scrollOffset = scroll;
}
}
private void OnKeyDownShortcut(KeyDownEvent evt)
{
if (selectedItem == null)
return;
if (evt.keyCode == KeyCode.Tab)
{
OnFocusChange();
evt.StopPropagation();
return;
}
if (evt.keyCode == KeyCode.UpArrow)
{
if (selectedItem.previousItem != null)
{
Select(selectedItem.previousItem);
ScrollIfNeeded();
}
else if (selectedItem.packageGroup.previousGroup != null && selectedItem.packageGroup.previousGroup.visible)
{
Select(selectedItem.packageGroup.previousGroup.lastPackage);
ScrollIfNeeded();
}
evt.StopPropagation();
return;
}
if (evt.keyCode == KeyCode.DownArrow)
{
if (selectedItem.nextItem != null)
{
Select(selectedItem.nextItem);
ScrollIfNeeded();
}
else if (selectedItem.packageGroup.nextGroup != null && selectedItem.packageGroup.nextGroup.visible)
{
Select(selectedItem.packageGroup.nextGroup.firstPackage);
ScrollIfNeeded();
}
evt.StopPropagation();
return;
}
if (evt.keyCode == KeyCode.PageUp)
{
if (selectedItem.packageGroup != null)
{
if (selectedItem == selectedItem.packageGroup.lastPackage && selectedItem != selectedItem.packageGroup.firstPackage)
{
Select(selectedItem.packageGroup.firstPackage);
ScrollIfNeeded();
}
else if (selectedItem == selectedItem.packageGroup.firstPackage && selectedItem.packageGroup.previousGroup != null && selectedItem.packageGroup.previousGroup.visible)
{
Select(selectedItem.packageGroup.previousGroup.lastPackage);
ScrollIfNeeded();
}
else if (selectedItem != selectedItem.packageGroup.lastPackage && selectedItem != selectedItem.packageGroup.firstPackage)
{
Select(selectedItem.packageGroup.firstPackage);
ScrollIfNeeded();
}
}
evt.StopPropagation();
return;
}
if (evt.keyCode == KeyCode.PageDown)
{
if (selectedItem.packageGroup != null)
{
if (selectedItem == selectedItem.packageGroup.firstPackage && selectedItem != selectedItem.packageGroup.lastPackage)
{
Select(selectedItem.packageGroup.lastPackage);
ScrollIfNeeded();
}
else if (selectedItem == selectedItem.packageGroup.lastPackage && selectedItem.packageGroup.nextGroup != null && selectedItem.packageGroup.nextGroup.visible)
{
Select(selectedItem.packageGroup.nextGroup.firstPackage);
ScrollIfNeeded();
}
else if (selectedItem != selectedItem.packageGroup.firstPackage && selectedItem != selectedItem.packageGroup.lastPackage)
{
Select(selectedItem.packageGroup.lastPackage);
ScrollIfNeeded();
}
}
evt.StopPropagation();
}
}
private void Reload()
{
// Force a re-init to initial condition
PackageCollection.Instance.UpdatePackageCollection();
SelectLastSelection();
}
private void ClearAll()
{
List.Clear();
Groups.Clear();
UIUtils.SetElementDisplay(Empty, false);
UIUtils.SetElementDisplay(NoResult, false);
}
private void SetPackages(IEnumerable<Package> packages)
{
if (PackageCollection.Instance.Filter == PackageFilter.Modules)
{
packages = packages.Where(pkg => pkg.IsBuiltIn);
}
else if (PackageCollection.Instance.Filter== PackageFilter.All)
{
packages = packages.Where(pkg => !pkg.IsBuiltIn);
}
else
{
packages = packages.Where(pkg => !pkg.IsBuiltIn);
packages = packages.Where(pkg => pkg.Current != null);
}
OnLoaded();
ClearAll();
var packagesGroup = new PackageGroup(PackageGroupOrigins.Packages.ToString());
Groups.Add(packagesGroup);
List.Add(packagesGroup);
packagesGroup.previousGroup = null;
var builtInGroup = new PackageGroup(PackageGroupOrigins.BuiltInPackages.ToString());
Groups.Add(builtInGroup);
List.Add(builtInGroup);
if ((PackageCollection.Instance.Filter & PackageFilter.Modules) == PackageFilter.Modules)
{
packagesGroup.nextGroup = builtInGroup;
builtInGroup.previousGroup = packagesGroup;
builtInGroup.nextGroup = null;
}
else
{
packagesGroup.nextGroup = null;
UIUtils.SetElementDisplay(builtInGroup, false);
}
var lastSelection = PackageCollection.Instance.SelectedPackage;
Select(null);
PackageItem defaultSelection = null;
foreach (var package in packages.OrderBy(pkg => pkg.Versions.FirstOrDefault() == null ? pkg.Name : pkg.Versions.FirstOrDefault().DisplayName))
{
var item = AddPackage(package);
if (null == selectedItem && defaultSelection == null)
defaultSelection = item;
if (null == selectedItem && !string.IsNullOrEmpty(lastSelection) && package.Name.Equals(lastSelection))
Select(item);
}
if (selectedItem == null)
Select(defaultSelection);
PackageFiltering.FilterPackageList(this);
}
public void SelectLastSelection()
{
var lastSelection = PackageCollection.Instance.SelectedPackage;
if (lastSelection == null)
return;
var list = List.Query<PackageItem>().ToList();
PackageItem defaultSelection = null;
foreach (var item in list)
{
if (defaultSelection == null)
defaultSelection = item;
if (!string.IsNullOrEmpty(lastSelection) && item.package.Name.Equals(lastSelection))
{
defaultSelection = item;
break;
}
}
selectedItem = null;
Select(defaultSelection);
}
private PackageItem AddPackage(Package package)
{
var groupName = package.Latest != null ? package.Latest.Group : package.Current.Group;
var group = GetOrCreateGroup(groupName);
var packageItem = group.AddPackage(package);
packageItem.OnSelected += Select;
return packageItem;
}
private PackageGroup GetOrCreateGroup(string groupName)
{
foreach (var g in Groups)
{
if (g.name == groupName)
return g;
}
var group = new PackageGroup(groupName);
var latestGroup = Groups.LastOrDefault();
Groups.Add(group);
List.Add(group);
group.previousGroup = null;
if (latestGroup != null)
{
latestGroup.nextGroup = group;
group.previousGroup = latestGroup;
group.nextGroup = null;
}
return group;
}
private void Select(PackageItem packageItem)
{
if (packageItem == selectedItem)
return;
var selectedPackageName = packageItem != null ? packageItem.package.Name : null;
PackageCollection.Instance.SelectedPackage = selectedPackageName;
if (selectedItem != null)
selectedItem.SetSelected(false); // Clear Previous selection
selectedItem = packageItem;
if (selectedItem == null)
{
OnSelected(null);
return;
}
selectedItem.SetSelected(true);
ScrollIfNeeded();
OnSelected(selectedItem.package);
}
private ScrollView List { get { return root.Q<ScrollView>("scrollView"); } }
private VisualElement Empty { get { return root.Q<VisualElement>("emptyArea"); } }
private VisualElement NoResult { get { return root.Q<VisualElement>("noResult"); } }
private Label NoResultText { get { return root.Q<Label>("noResultText"); } }
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 2d77b2d58287d46a6a61f12c861bfc2f
timeCreated: 1502224642
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,25 @@
using System.Collections.Generic;
namespace UnityEditor.PackageManager.UI
{
/// <summary>
/// Package Manager UI Extensions
/// </summary>
public static class PackageManagerExtensions
{
internal static List<IPackageManagerExtension> Extensions { get { return extensions ?? (extensions = new List<IPackageManagerExtension>()); } }
private static List<IPackageManagerExtension> extensions;
/// <summary>
/// Registers a new Package Manager UI extension
/// </summary>
/// <param name="extension">A Package Manager UI extension</param>
public static void RegisterExtension(IPackageManagerExtension extension)
{
if (extension == null)
return;
Extensions.Add(extension);
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 20a8ca0a6d82545f6bfd6f2d898d61f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,41 @@
using System.Linq;
namespace UnityEditor.PackageManager.UI
{
internal static class PackageManagerPrefs
{
private const string kShowPreviewPackagesPrefKeyPrefix = "PackageManager.ShowPreviewPackages_";
private const string kShowPreviewPackagesWarningPrefKey = "PackageManager.ShowPreviewPackagesWarning";
private static string GetProjectIdentifier()
{
// PlayerSettings.productGUID is already used as LocalProjectID by Analytics, so we use it too
return PlayerSettings.productGUID.ToString();
}
public static bool ShowPreviewPackages
{
get
{
var key = kShowPreviewPackagesPrefKeyPrefix + GetProjectIdentifier();
// If user manually choose to show or not preview packages, use this value
if (EditorPrefs.HasKey(key))
return EditorPrefs.GetBool(key);
// Returns true if at least one preview package is installed, false otherwise
return PackageCollection.Instance.LatestListPackages.Any(p => p.IsPreview && p.IsCurrent);
}
set
{
EditorPrefs.SetBool(kShowPreviewPackagesPrefKeyPrefix + GetProjectIdentifier(), value);
}
}
public static bool ShowPreviewPackagesWarning
{
get { return EditorPrefs.GetBool(kShowPreviewPackagesWarningPrefKey, true); }
set { EditorPrefs.SetBool(kShowPreviewPackagesWarningPrefKey, value); }
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 566f8bae715954c65a2a7a4b5818fc7a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,164 @@
using System.Linq;
using UnityEngine;
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
#if !UNITY_2018_3_OR_NEWER
internal class PackageManangerToolbarFactory : UxmlFactory<PackageManagerToolbar>
{
protected override PackageManagerToolbar DoCreate(IUxmlAttributes bag, CreationContext cc)
{
return new PackageManagerToolbar();
}
}
#endif
internal class PackageManagerToolbar : VisualElement
{
#if UNITY_2018_3_OR_NEWER
internal new class UxmlFactory : UxmlFactory<PackageManagerToolbar> { }
#endif
private readonly VisualElement root;
[SerializeField]
private PackageFilter selectedFilter = PackageFilter.All;
public PackageManagerToolbar()
{
root = Resources.GetTemplate("PackageManagerToolbar.uxml");
Add(root);
root.StretchToParentSize();
SetFilter(PackageCollection.Instance.Filter);
RegisterCallback<AttachToPanelEvent>(OnEnterPanel);
RegisterCallback<DetachFromPanelEvent>(OnLeavePanel);
}
public void GrabFocus()
{
SearchToolbar.GrabFocus();
}
public new void SetEnabled(bool enable)
{
base.SetEnabled(enable);
FilterButton.SetEnabled(enable);
AdvancedButton.SetEnabled(enable);
SearchToolbar.SetEnabled(enable);
}
private static string GetFilterDisplayName(PackageFilter filter)
{
switch (filter)
{
case PackageFilter.All:
return "All packages";
case PackageFilter.Local:
return "In Project";
case PackageFilter.Modules:
return "Built-in packages";
case PackageFilter.None:
return "None";
default:
return filter.ToString();
}
}
private void SetFilter(object obj)
{
var previouSelectedFilter = selectedFilter;
selectedFilter = (PackageFilter) obj;
FilterButton.text = string.Format("{0} ▾", GetFilterDisplayName(selectedFilter));
if (selectedFilter != previouSelectedFilter)
PackageCollection.Instance.SetFilter(selectedFilter);
}
private void OnFilterButtonMouseDown(MouseDownEvent evt)
{
if (evt.propagationPhase != PropagationPhase.AtTarget)
return;
var menu = new GenericMenu();
menu.AddItem(new GUIContent(GetFilterDisplayName(PackageFilter.All)),
selectedFilter == PackageFilter.All,
SetFilter, PackageFilter.All);
menu.AddItem(new GUIContent(GetFilterDisplayName(PackageFilter.Local)),
selectedFilter == PackageFilter.Local,
SetFilter, PackageFilter.Local);
menu.AddSeparator("");
menu.AddItem(new GUIContent(GetFilterDisplayName(PackageFilter.Modules)),
selectedFilter == PackageFilter.Modules,
SetFilter, PackageFilter.Modules);
var menuPosition = new Vector2(FilterButton.layout.xMin, FilterButton.layout.center.y);
menuPosition = this.LocalToWorld(menuPosition);
var menuRect = new Rect(menuPosition, Vector2.zero);
menu.DropDown(menuRect);
}
private void OnAdvancedButtonMouseDown(MouseDownEvent evt)
{
if (evt.propagationPhase != PropagationPhase.AtTarget)
return;
var menu = new GenericMenu();
menu.AddItem(new GUIContent("Show preview packages"), PackageManagerPrefs.ShowPreviewPackages, TogglePreviewPackages);
//menu.AddItem(new GUIContent("Reset to defaults"), false, ResetToDefaultsClick);
var menuPosition = new Vector2(AdvancedButton.layout.xMax + 30, AdvancedButton.layout.center.y);
menuPosition = this.LocalToWorld(menuPosition);
var menuRect = new Rect(menuPosition, Vector2.zero);
menu.DropDown(menuRect);
}
private static void TogglePreviewPackages()
{
var showPreviewPackages = PackageManagerPrefs.ShowPreviewPackages;
if (!showPreviewPackages && PackageManagerPrefs.ShowPreviewPackagesWarning)
{
const string message = "Preview packages are not verified with Unity, may be unstable, and are unsupported in production. Are you sure you want to show preview packages?";
if (!EditorUtility.DisplayDialog("Unity Package Manager", message, "Yes", "No"))
return;
PackageManagerPrefs.ShowPreviewPackagesWarning = false;
}
PackageManagerPrefs.ShowPreviewPackages = !showPreviewPackages;
PackageCollection.Instance.UpdatePackageCollection(true);
}
private void ResetToDefaultsClick()
{
if (!EditorUtility.DisplayDialog("Unity Package Manager", "Operation will reset all your packages to Editor defaults. Do you want to continue?", "Yes", "No"))
return;
// Registered on callback
AssemblyReloadEvents.beforeAssemblyReload += PackageManagerWindow.ShowPackageManagerWindow;
Client.ResetToEditorDefaults();
var windows = UnityEngine.Resources.FindObjectsOfTypeAll<PackageManagerWindow>();
if (windows.Length > 0)
{
windows[0].Close();
}
}
private void OnEnterPanel(AttachToPanelEvent evt)
{
FilterButton.RegisterCallback<MouseDownEvent>(OnFilterButtonMouseDown);
AdvancedButton.RegisterCallback<MouseDownEvent>(OnAdvancedButtonMouseDown);
}
private void OnLeavePanel(DetachFromPanelEvent evt)
{
FilterButton.UnregisterCallback<MouseDownEvent>(OnFilterButtonMouseDown);
AdvancedButton.UnregisterCallback<MouseDownEvent>(OnAdvancedButtonMouseDown);
}
private Label FilterButton { get { return root.Q<Label>("toolbarFilterButton"); } }
private Label AdvancedButton { get { return root.Q<Label>("toolbarAdvancedButton"); } }
internal PackageSearchToolbar SearchToolbar { get { return root.Q<PackageSearchToolbar>("toolbarSearch"); } }
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b6d1682724bab428496b2bd2d8c7b194
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,131 @@
using System.Linq;
using UnityEngine;
using UnityEngine.Experimental.UIElements;
using UnityEditor.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
internal class PackageManagerWindow : EditorWindow
{
public const string PackagePath = "Packages/com.unity.package-manager-ui/";
public const string ResourcesPath = PackagePath + "Editor/Resources/";
private const string TemplatePath = ResourcesPath + "Templates/PackageManagerWindow.uxml";
private const string DarkStylePath = ResourcesPath + "Styles/Main_Dark.uss";
private const string LightStylePath = ResourcesPath + "Styles/Main_Light.uss";
private const double targetVersionNumber = 2018.1;
public PackageCollection Collection;
public PackageSearchFilter SearchFilter;
#if UNITY_2018_1_OR_NEWER
public void OnEnable()
{
PackageCollection.InitInstance(ref Collection);
PackageSearchFilter.InitInstance(ref SearchFilter);
this.GetRootVisualContainer().AddStyleSheetPath(EditorGUIUtility.isProSkin ? DarkStylePath : LightStylePath);
var windowResource = AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(TemplatePath);
if (windowResource != null)
{
var template = windowResource.CloneTree(null);
this.GetRootVisualContainer().Add(template);
template.StretchToParentSize();
PackageList.OnSelected += OnPackageSelected;
PackageList.OnLoaded += OnPackagesLoaded;
PackageList.OnFocusChange += OnListFocusChange;
PackageManagerToolbar.SearchToolbar.OnSearchChange += OnSearchChange;
PackageManagerToolbar.SearchToolbar.OnFocusChange += OnToolbarFocusChange;
// Disable filter while fetching first results
if (!PackageCollection.Instance.LatestListPackages.Any())
PackageManagerToolbar.SetEnabled(false);
else
PackageList.SelectLastSelection();
}
}
private void OnListFocusChange()
{
PackageManagerToolbar.GrabFocus();
}
private void OnToolbarFocusChange()
{
PackageList.GrabFocus();
}
private void OnSearchChange(string searchText)
{
PackageSearchFilter.Instance.SearchText = searchText;
PackageFiltering.FilterPackageList(PackageList);
}
public void OnDisable()
{
// Package list item may not be valid here.
if (PackageList != null)
{
PackageList.OnSelected -= OnPackageSelected;
PackageList.OnLoaded -= OnPackagesLoaded;
}
if (PackageManagerToolbar != null)
{
PackageManagerToolbar.SearchToolbar.OnSearchChange -= OnSearchChange;
PackageManagerToolbar.SearchToolbar.OnFocusChange -= OnToolbarFocusChange;
}
}
public void OnDestroy()
{
PackageSearchFilter.Instance.ResetSearch();
PackageCollection.Instance.SetFilter(PackageFilter.All, false);
}
private void OnPackageSelected(Package package)
{
PackageDetails.SetPackage(package);
}
private void OnPackagesLoaded()
{
PackageManagerToolbar.SetEnabled(true);
}
private PackageList PackageList
{
get {return this.GetRootVisualContainer().Q<PackageList>("packageList");}
}
private PackageDetails PackageDetails
{
get {return this.GetRootVisualContainer().Q<PackageDetails>("detailsGroup");}
}
private PackageManagerToolbar PackageManagerToolbar
{
get {return this.GetRootVisualContainer().Q<PackageManagerToolbar>("toolbarContainer");}
}
internal Alert ErrorBanner { get { return this.GetRootVisualContainer().Q<Alert>("errorBanner"); } }
#endif
[MenuItem("Window/Package Manager", priority = 1500)]
internal static void ShowPackageManagerWindow()
{
#if UNITY_2018_1_OR_NEWER
var window = GetWindow<PackageManagerWindow>(false, "Packages", true);
window.minSize = new Vector2(700, 250);
window.Show();
#else
EditorUtility.DisplayDialog("Unsupported Unity Version", string.Format("The Package Manager requires Unity Version {0} or higher to operate.", targetVersionNumber), "Ok");
#endif
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 650ea1d167b834d0f86d94e1e8c3b80f
timeCreated: 1502224642
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,153 @@
using System;
using UnityEngine;
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
#if !UNITY_2018_3_OR_NEWER
internal class PackageSearchToolbarFactory : UxmlFactory<PackageSearchToolbar>
{
protected override PackageSearchToolbar DoCreate(IUxmlAttributes bag, CreationContext cc)
{
return new PackageSearchToolbar();
}
}
#endif
internal class PackageSearchToolbar : VisualElement
{
#if UNITY_2018_3_OR_NEWER
internal new class UxmlFactory : UxmlFactory<PackageSearchToolbar> { }
#endif
private const string kPlaceHolder = "Search by package name, verified, preview or version number...";
public event Action OnFocusChange = delegate { };
public event Action<string> OnSearchChange = delegate { };
private string searchText;
private bool showingPlaceHolder;
private readonly VisualElement root;
public PackageSearchToolbar()
{
root = Resources.GetTemplate("PackageSearchToolbar.uxml");
Add(root);
root.StretchToParentSize();
SearchTextField.value = searchText;
SearchTextField.maxLength = 54;
SearchCancelButton.clickable.clicked += SearchCancelButtonClick;
RegisterCallback<AttachToPanelEvent>(OnEnterPanel);
RegisterCallback<DetachFromPanelEvent>(OnLeavePanel);
searchText = PackageSearchFilter.Instance.SearchText;
if (string.IsNullOrEmpty(searchText))
{
showingPlaceHolder = true;
SearchTextField.value = kPlaceHolder;
SearchTextField.AddToClassList("placeholder");
}
else
{
showingPlaceHolder = false;
SearchTextField.value = searchText;
SearchTextField.RemoveFromClassList("placeholder");
}
}
public void GrabFocus()
{
SearchTextField.Focus();
}
public new void SetEnabled(bool enable)
{
base.SetEnabled(enable);
SearchTextField.SetEnabled(enable);
SearchCancelButton.SetEnabled(enable);
}
private void OnSearchTextFieldChange(ChangeEvent<string> evt)
{
if (showingPlaceHolder && evt.newValue == kPlaceHolder)
return;
if (!string.IsNullOrEmpty(evt.newValue))
SearchCancelButton.AddToClassList("on");
else
SearchCancelButton.RemoveFromClassList("on");
searchText = evt.newValue;
OnSearchChange(searchText);
}
private void OnSearchTextFieldFocus(FocusEvent evt)
{
if (showingPlaceHolder)
{
SearchTextField.value = string.Empty;
SearchTextField.RemoveFromClassList("placeholder");
showingPlaceHolder = false;
}
}
private void OnSearchTextFieldFocusOut(FocusOutEvent evt)
{
if (string.IsNullOrEmpty(searchText))
{
showingPlaceHolder = true;
SearchTextField.AddToClassList("placeholder");
SearchTextField.value = kPlaceHolder;
}
}
private void SearchCancelButtonClick()
{
if (!string.IsNullOrEmpty(SearchTextField.value))
{
SearchTextField.value = string.Empty;
}
showingPlaceHolder = true;
SearchTextField.AddToClassList("placeholder");
SearchTextField.value = kPlaceHolder;
}
private void OnEnterPanel(AttachToPanelEvent evt)
{
SearchTextField.RegisterCallback<FocusEvent>(OnSearchTextFieldFocus);
SearchTextField.RegisterCallback<FocusOutEvent>(OnSearchTextFieldFocusOut);
SearchTextField.RegisterCallback<ChangeEvent<string>>(OnSearchTextFieldChange);
SearchTextField.RegisterCallback<KeyDownEvent>(OnKeyDownShortcut);
}
private void OnLeavePanel(DetachFromPanelEvent evt)
{
SearchTextField.UnregisterCallback<FocusEvent>(OnSearchTextFieldFocus);
SearchTextField.UnregisterCallback<FocusOutEvent>(OnSearchTextFieldFocusOut);
SearchTextField.UnregisterCallback<ChangeEvent<string>>(OnSearchTextFieldChange);
SearchTextField.UnregisterCallback<KeyDownEvent>(OnKeyDownShortcut);
}
private void OnKeyDownShortcut(KeyDownEvent evt)
{
if (evt.keyCode == KeyCode.Escape)
{
SearchCancelButtonClick();
SearchCancelButton.Focus();
evt.StopImmediatePropagation();
return;
}
if (evt.keyCode == KeyCode.Tab)
{
OnFocusChange();
evt.StopImmediatePropagation();
}
}
private TextField SearchTextField { get { return root.Q<TextField>("searchTextField"); } }
private Button SearchCancelButton { get { return root.Q<Button>("searchCancelButton"); } }
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f74142ec8a4cd4fb1b0ff6cf5c3075af
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,150 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Experimental.UIElements;
namespace UnityEditor.PackageManager.UI
{
#if !UNITY_2018_3_OR_NEWER
internal class PackageStatusBarFactory : UxmlFactory<PackageStatusBar>
{
protected override PackageStatusBar DoCreate(IUxmlAttributes bag, CreationContext cc)
{
return new PackageStatusBar();
}
}
#endif
internal class PackageStatusBar : VisualElement
{
#if UNITY_2018_3_OR_NEWER
internal new class UxmlFactory : UxmlFactory<PackageStatusBar> { }
#endif
private readonly VisualElement root;
private string LastErrorMessage;
private List<IBaseOperation> operationsInProgress;
private enum StatusType {Normal, Loading, Error};
public PackageStatusBar()
{
root = Resources.GetTemplate("PackageStatusBar.uxml");
Add(root);
MoreAddOptionsButton.clickable.clicked += OnMoreAddOptionsButtonClick;
LastErrorMessage = string.Empty;
operationsInProgress = new List<IBaseOperation>();
SetDefaultMessage();
PackageCollection.Instance.ListSignal.WhenOperation(OnListOrSearchOperation);
PackageCollection.Instance.SearchSignal.WhenOperation(OnListOrSearchOperation);
}
private void SetDefaultMessage()
{
if(!string.IsNullOrEmpty(PackageCollection.Instance.lastUpdateTime))
SetStatusMessage(StatusType.Normal, "Last update " + PackageCollection.Instance.lastUpdateTime);
else
SetStatusMessage(StatusType.Normal, string.Empty);
}
private void OnListOrSearchOperation(IBaseOperation operation)
{
if (operation == null || operation.IsCompleted)
return;
operationsInProgress.Add(operation);
operation.OnOperationFinalized += () => { OnOperationFinalized(operation); };
operation.OnOperationError += OnOperationError;
SetStatusMessage(StatusType.Loading, "Loading packages...");
}
private void OnOperationFinalized(IBaseOperation operation)
{
operationsInProgress.Remove(operation);
if (operationsInProgress.Any()) return;
var errorMessage = LastErrorMessage;
if (Application.internetReachability == NetworkReachability.NotReachable)
{
EditorApplication.update -= CheckInternetReachability;
EditorApplication.update += CheckInternetReachability;
errorMessage = "You seem to be offline.";
}
if (!string.IsNullOrEmpty(errorMessage))
SetStatusMessage(StatusType.Error, errorMessage);
else
SetDefaultMessage();
}
private void OnOperationError(Error error)
{
LastErrorMessage = "Cannot load packages, see console.";
}
private void CheckInternetReachability()
{
if (Application.internetReachability == NetworkReachability.NotReachable) return;
PackageCollection.Instance.FetchListCache(true);
PackageCollection.Instance.FetchSearchCache(true);
EditorApplication.update -= CheckInternetReachability;
}
private void SetStatusMessage(StatusType status, string message)
{
if (status == StatusType.Loading)
LoadingSpinner.Start();
else
LoadingSpinner.Stop();
UIUtils.SetElementDisplay(LoadingIcon, status == StatusType.Error);
if (status == StatusType.Error)
LoadingText.AddToClassList("icon");
else
LoadingText.RemoveFromClassList("icon");
LoadingText.text = message;
}
private void OnMoreAddOptionsButtonClick()
{
var menu = new GenericMenu();
var addPackageFromDiskItem = new GUIContent("Add package from disk...");
/* // Disable adding from url field before the feature is ready
var addPackageFromUrlItem = new GUIContent("Add package from URL...");
menu.AddItem(addPackageFromUrlItem, false, delegate
{
AddFromUrlField.Show(true);
});
*/
menu.AddItem(addPackageFromDiskItem, false, delegate
{
var path = EditorUtility.OpenFilePanelWithFilters("Select package on disk", "", new[] { "package.json file", "json" });
if (!string.IsNullOrEmpty(path) && !Package.AddRemoveOperationInProgress)
Package.AddFromLocalDisk(path);
});
var menuPosition = MoreAddOptionsButton.LocalToWorld(new Vector2(MoreAddOptionsButton.layout.width, 0));
var menuRect = new Rect(menuPosition, Vector2.zero);
menu.DropDown(menuRect);
}
private PackageAddFromUrlField AddFromUrlField { get { return root.Q<PackageAddFromUrlField>("packageAddFromUrlField"); }}
private VisualElement LoadingSpinnerContainer { get { return root.Q<VisualElement>("loadingSpinnerContainer"); }}
private LoadingSpinner LoadingSpinner { get { return root.Q<LoadingSpinner>("packageSpinner"); }}
private Label LoadingIcon { get { return root.Q<Label>("loadingIcon"); }}
private Label LoadingText { get { return root.Q<Label>("loadingText"); }}
private Button MoreAddOptionsButton{ get { return root.Q<Button>("moreAddOptionsButton"); }}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f34f5fa2437664b2a81b4a7f34df87ad
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: