浏览代码
"Replace" context-menu with a searchable popup (#223)
"Replace" context-menu with a searchable popup (#223)
* "Replace" context-menu with a popup window * [Bot] Automated dotnet-format update * Selection interactive preview * Whoops, wrong merge resolve * [Bot] Automated dotnet-format update * Show popup at screen mouse position * Mini-previews on renderable objects + minor GUI improvements * [Bot] Automated dotnet-format update * Editors cache fix, remove dummy editor * Destroy only cached editor * Rename "ReplacePrefabTreeView" to "PrefabSelectionTreeView" * catch ClearPreviewCache error * fix null texture warning * Fix popup fit on smaller screens * Fix black frame when closing popup during repaint * Expand folder on single-click * Remove editor Destroy, as error is still showing inside try catch * Revert delayed close, as it made popup not-closable in some cases/main
GitHub
4 年前
当前提交
851182b5
共有 9 个文件被更改,包括 662 次插入 和 3 次删除
-
6UOP1_Project/Assets/Scripts/Editor/ReplaceTool.cs
-
113UOP1_Project/Assets/Scripts/Editor/GameObjectPreview.cs
-
3UOP1_Project/Assets/Scripts/Editor/GameObjectPreview.cs.meta
-
267UOP1_Project/Assets/Scripts/Editor/PrefabSelectionTreeView.cs
-
11UOP1_Project/Assets/Scripts/Editor/PrefabSelectionTreeView.cs.meta
-
69UOP1_Project/Assets/Scripts/Editor/ReplaceContextMenu.cs
-
3UOP1_Project/Assets/Scripts/Editor/ReplaceContextMenu.cs.meta
-
190UOP1_Project/Assets/Scripts/Editor/ReplacePrefabSearchPopup.cs
-
3UOP1_Project/Assets/Scripts/Editor/ReplacePrefabSearchPopup.cs.meta
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Reflection; |
|||
using UnityEditor; |
|||
using UnityEngine; |
|||
using Object = UnityEngine.Object; |
|||
|
|||
namespace UOP1.EditorTools |
|||
{ |
|||
internal class GameObjectPreview |
|||
{ |
|||
private static Type gameObjectInspectorType; |
|||
private static MethodInfo getPreviewDataMethod; |
|||
private static FieldInfo renderUtilityField; |
|||
|
|||
private Rect renderRect; |
|||
private Color light0Color; |
|||
private Color light1Color; |
|||
private PreviewRenderUtility renderUtility; |
|||
|
|||
private Editor cachedEditor; |
|||
|
|||
public RenderTexture outputTexture; |
|||
|
|||
[InitializeOnLoadMethod] |
|||
private static void OnInitialize() |
|||
{ |
|||
gameObjectInspectorType = typeof(Editor).Assembly.GetType("UnityEditor.GameObjectInspector"); |
|||
var previewDataType = gameObjectInspectorType.GetNestedType("PreviewData", BindingFlags.NonPublic); |
|||
|
|||
getPreviewDataMethod = gameObjectInspectorType.GetMethod("GetPreviewData", BindingFlags.NonPublic | BindingFlags.Instance); |
|||
renderUtilityField = previewDataType.GetField("renderUtility", BindingFlags.Public | BindingFlags.Instance); |
|||
} |
|||
|
|||
public void CreatePreviewForTarget(GameObject target) |
|||
{ |
|||
if (!cachedEditor || cachedEditor.target != target) |
|||
{ |
|||
renderUtility = null; |
|||
// There is a bug that breaks previews and Prefab mode after creating too many editors.
|
|||
// Simply using CreateCachedEditor is fixing that problem.
|
|||
Editor.CreateCachedEditor(target, gameObjectInspectorType, ref cachedEditor); |
|||
} |
|||
} |
|||
|
|||
public void RenderInteractivePreview(Rect rect) |
|||
{ |
|||
if (!cachedEditor) |
|||
return; |
|||
|
|||
if (renderUtility == null || renderUtility.lights[0] == null) |
|||
{ |
|||
var previewData = getPreviewDataMethod.Invoke(cachedEditor, null); |
|||
renderUtility = renderUtilityField.GetValue(previewData) as PreviewRenderUtility; |
|||
|
|||
light0Color = renderUtility.lights[0].color; |
|||
light1Color = renderUtility.lights[1].color; |
|||
} |
|||
|
|||
renderUtility.lights[0].color = light0Color * 1.6f; |
|||
renderUtility.lights[1].color = light1Color * 6f; |
|||
var backColor = renderUtility.camera.backgroundColor; |
|||
renderUtility.camera.backgroundColor = new Color(backColor.r, backColor.g, backColor.b, 0); |
|||
renderUtility.camera.clearFlags = CameraClearFlags.Depth; |
|||
|
|||
var color = GUI.color; |
|||
|
|||
// Hide default preview texture, since it has no alpha blending
|
|||
GUI.color = new Color(1, 1, 1, 0); |
|||
|
|||
cachedEditor.OnPreviewGUI(rect, null); |
|||
|
|||
GUI.color = color; |
|||
|
|||
outputTexture = renderUtility.camera.targetTexture; |
|||
} |
|||
|
|||
public void DrawPreviewTexture(Rect rect) |
|||
{ |
|||
GUI.DrawTexture(rect, outputTexture, ScaleMode.ScaleToFit, true, 0); |
|||
} |
|||
|
|||
public static bool HasRenderableParts(GameObject go) |
|||
{ |
|||
var renderers = go.GetComponentsInChildren<Renderer>(); |
|||
foreach (var renderer in renderers) |
|||
{ |
|||
switch (renderer) |
|||
{ |
|||
case MeshRenderer _: |
|||
var filter = renderer.gameObject.GetComponent<MeshFilter>(); |
|||
if (filter && filter.sharedMesh) |
|||
return true; |
|||
break; |
|||
case SkinnedMeshRenderer skinnedMesh: |
|||
if (skinnedMesh.sharedMesh) |
|||
return true; |
|||
break; |
|||
case SpriteRenderer sprite: |
|||
if (sprite.sprite) |
|||
return true; |
|||
break; |
|||
case BillboardRenderer billboard: |
|||
if (billboard.billboard && billboard.sharedMaterial) |
|||
return true; |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: bb1d562e678248bbb3b897536cf62c50 |
|||
timeCreated: 1606495882 |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UnityEditor; |
|||
using UnityEditor.IMGUI.Controls; |
|||
using UnityEngine; |
|||
using Object = UnityEngine.Object; |
|||
|
|||
namespace UOP1.EditorTools.Replacer |
|||
{ |
|||
internal class PrefabSelectionTreeView : TreeView |
|||
{ |
|||
private static Texture2D prefabOnIcon = EditorGUIUtility.IconContent("Prefab On Icon").image as Texture2D; |
|||
private static Texture2D prefabVariantOnIcon = EditorGUIUtility.IconContent("PrefabVariant On Icon").image as Texture2D; |
|||
private static Texture2D folderIcon = EditorGUIUtility.IconContent("Folder Icon").image as Texture2D; |
|||
private static Texture2D folderOnIcon = EditorGUIUtility.IconContent("Folder On Icon").image as Texture2D; |
|||
|
|||
private static GUIStyle whiteLabel; |
|||
private static GUIStyle foldout; |
|||
|
|||
public int RowsCount => rows.Count; |
|||
private Event evt => Event.current; |
|||
|
|||
public Action<GameObject> onSelectEntry; |
|||
|
|||
private List<TreeViewItem> rows = new List<TreeViewItem>(); |
|||
private HashSet<string> paths = new HashSet<string>(); |
|||
|
|||
private Dictionary<int, RenderTexture> previewCache = new Dictionary<int, RenderTexture>(); |
|||
private HashSet<int> renderableItems = new HashSet<int>(); |
|||
|
|||
private GameObjectPreview itemPreview = new GameObjectPreview(); |
|||
private GUIContent itemContent = new GUIContent(); |
|||
|
|||
private int selectedId; |
|||
|
|||
public PrefabSelectionTreeView(TreeViewState state) : base(state) |
|||
{ |
|||
foldoutOverride = FoldoutOverride; |
|||
Reload(); |
|||
} |
|||
|
|||
private bool FoldoutOverride(Rect position, bool expandedState, GUIStyle style) |
|||
{ |
|||
position.width = Screen.width; |
|||
position.height = 20; |
|||
position.y -= 2; |
|||
|
|||
expandedState = GUI.Toggle(position, expandedState, GUIContent.none, style); |
|||
|
|||
return expandedState; |
|||
} |
|||
|
|||
public void Cleanup() |
|||
{ |
|||
foreach (var texture in previewCache.Values) |
|||
Object.DestroyImmediate(texture); |
|||
} |
|||
|
|||
public bool IsRenderable(int id) |
|||
{ |
|||
return renderableItems.Contains(id); |
|||
} |
|||
|
|||
private void CachePreview(int itemId) |
|||
{ |
|||
var copy = new RenderTexture(itemPreview.outputTexture); |
|||
var previous = RenderTexture.active; |
|||
Graphics.Blit(itemPreview.outputTexture, copy); |
|||
RenderTexture.active = previous; |
|||
previewCache.Add(itemId, copy); |
|||
} |
|||
|
|||
protected override bool CanMultiSelect(TreeViewItem item) |
|||
{ |
|||
return false; |
|||
} |
|||
|
|||
private bool IsPrefabAsset(int id, out GameObject prefab) |
|||
{ |
|||
var obj = EditorUtility.InstanceIDToObject(id); |
|||
|
|||
if (obj is GameObject go) |
|||
{ |
|||
prefab = go; |
|||
return true; |
|||
} |
|||
|
|||
prefab = null; |
|||
return false; |
|||
} |
|||
|
|||
protected override void DoubleClickedItem(int id) |
|||
{ |
|||
if (IsPrefabAsset(id, out var prefab)) |
|||
onSelectEntry(prefab); |
|||
else |
|||
SetExpanded(id, !IsExpanded(id)); |
|||
} |
|||
|
|||
protected override void KeyEvent() |
|||
{ |
|||
var key = evt.keyCode; |
|||
if (key == KeyCode.KeypadEnter || key == KeyCode.Return) |
|||
DoubleClickedItem(selectedId); |
|||
} |
|||
|
|||
protected override void SelectionChanged(IList<int> selectedIds) |
|||
{ |
|||
if (selectedIds.Count > 0) |
|||
selectedId = selectedIds[0]; |
|||
} |
|||
|
|||
protected override TreeViewItem BuildRoot() |
|||
{ |
|||
var root = new TreeViewItem(0, -1); |
|||
rows.Clear(); |
|||
paths.Clear(); |
|||
|
|||
foreach (var guid in AssetDatabase.FindAssets("t:Prefab")) |
|||
{ |
|||
var path = AssetDatabase.GUIDToAssetPath(guid); |
|||
var splits = path.Split('/'); |
|||
var depth = splits.Length - 2; |
|||
|
|||
if (splits[0] != "Assets") |
|||
break; |
|||
|
|||
var asset = AssetDatabase.LoadAssetAtPath<GameObject>(path); |
|||
|
|||
AddFoldersItems(splits); |
|||
AddPrefabItem(asset, depth); |
|||
} |
|||
|
|||
SetupParentsAndChildrenFromDepths(root, rows); |
|||
|
|||
return root; |
|||
} |
|||
|
|||
protected override float GetCustomRowHeight(int row, TreeViewItem item) |
|||
{ |
|||
// Hide folders during search
|
|||
if (!IsPrefabAsset(item.id, out _) && hasSearch) |
|||
return 0; |
|||
|
|||
return 20; |
|||
} |
|||
|
|||
public override void OnGUI(Rect rect) |
|||
{ |
|||
if (whiteLabel == null) |
|||
whiteLabel = new GUIStyle(EditorStyles.label) { normal = { textColor = EditorStyles.whiteLabel.normal.textColor } }; |
|||
|
|||
base.OnGUI(rect); |
|||
} |
|||
|
|||
protected override void RowGUI(RowGUIArgs args) |
|||
{ |
|||
var rect = args.rowRect; |
|||
var item = args.item; |
|||
|
|||
var isRenderable = IsRenderable(item.id); |
|||
var isSelected = IsSelected(item.id); |
|||
var isFocused = HasFocus() && isSelected; |
|||
var isPrefab = IsPrefabAsset(item.id, out var prefab); |
|||
var isFolder = !isPrefab; |
|||
|
|||
if (isFolder && hasSearch) |
|||
return; |
|||
|
|||
if (isFolder) |
|||
{ |
|||
if (rect.Contains(evt.mousePosition) && evt.type == EventType.MouseUp) |
|||
{ |
|||
SetSelection(new List<int> { item.id }); |
|||
SetFocus(); |
|||
} |
|||
} |
|||
|
|||
var labelStyle = isFocused ? whiteLabel : EditorStyles.label; |
|||
var contentIndent = GetContentIndent(item); |
|||
|
|||
customFoldoutYOffset = 2; |
|||
itemContent.text = item.displayName; |
|||
|
|||
rect.x += contentIndent; |
|||
rect.width -= contentIndent; |
|||
|
|||
var iconRect = new Rect(rect) { width = 20 }; |
|||
|
|||
if (isPrefab) |
|||
{ |
|||
var type = PrefabUtility.GetPrefabAssetType(prefab); |
|||
var onIcon = type == PrefabAssetType.Regular ? prefabOnIcon : prefabVariantOnIcon; |
|||
|
|||
var labelRect = new Rect(rect); |
|||
|
|||
if (isRenderable) |
|||
{ |
|||
var previewRect = new Rect(rect) { width = 32, height = 32 }; |
|||
|
|||
if (!previewCache.TryGetValue(item.id, out var previewTexture)) |
|||
{ |
|||
itemPreview.CreatePreviewForTarget(prefab); |
|||
itemPreview.RenderInteractivePreview(previewRect); |
|||
|
|||
if (itemPreview.outputTexture) |
|||
CachePreview(item.id); |
|||
} |
|||
|
|||
if (!previewTexture) |
|||
Repaint(); |
|||
else |
|||
GUI.DrawTexture(iconRect, previewTexture, ScaleMode.ScaleAndCrop); |
|||
|
|||
labelRect.x += iconRect.width; |
|||
labelRect.width -= iconRect.width + 24; |
|||
|
|||
GUI.Label(labelRect, args.label, labelStyle); |
|||
|
|||
if (isSelected) |
|||
{ |
|||
var prefabIconRect = new Rect(iconRect) { x = rect.xMax - 24 }; |
|||
GUI.Label(prefabIconRect, isFocused ? onIcon : item.icon); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
itemContent.image = isSelected ? onIcon : item.icon; |
|||
GUI.Label(rect, itemContent, labelStyle); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
itemContent.image = isFocused ? folderOnIcon : folderIcon; |
|||
GUI.Label(rect, itemContent, labelStyle); |
|||
} |
|||
} |
|||
|
|||
private void AddFoldersItems(string[] splits) |
|||
{ |
|||
for (int i = 1; i < splits.Length - 1; i++) |
|||
{ |
|||
var split = splits[i]; |
|||
|
|||
if (!paths.Contains(split)) |
|||
{ |
|||
rows.Add(new TreeViewItem(split.GetHashCode(), i - 1, " " + split) { icon = folderIcon }); |
|||
paths.Add(split); |
|||
} |
|||
} |
|||
} |
|||
|
|||
private void AddPrefabItem(GameObject asset, int depth) |
|||
{ |
|||
var id = asset.GetInstanceID(); |
|||
var content = new GUIContent(EditorGUIUtility.ObjectContent(asset, asset.GetType())); |
|||
|
|||
if (GameObjectPreview.HasRenderableParts(asset)) |
|||
renderableItems.Add(id); |
|||
|
|||
rows.Add(new TreeViewItem(id, depth, content.text) |
|||
{ |
|||
icon = content.image as Texture2D |
|||
}); |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 241edd7da6766964687c5bf319a6163f |
|||
MonoImporter: |
|||
externalObjects: {} |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using UnityEditor; |
|||
using UnityEngine; |
|||
using UnityEngine.UIElements; |
|||
|
|||
namespace UOP1.EditorTools.Replacer |
|||
{ |
|||
internal class ReplaceContextMenu |
|||
{ |
|||
private static Type hierarchyType; |
|||
|
|||
private static EditorWindow focusedWindow; |
|||
private static IMGUIContainer hierarchyGUI; |
|||
|
|||
private static Vector2 mousePosition; |
|||
private static bool hasExecuted; |
|||
|
|||
[InitializeOnLoadMethod] |
|||
private static void OnInitialize() |
|||
{ |
|||
hierarchyType = typeof(Editor).Assembly.GetType("UnityEditor.SceneHierarchyWindow"); |
|||
|
|||
EditorApplication.update += TrackFocusedHierarchy; |
|||
} |
|||
|
|||
private static void TrackFocusedHierarchy() |
|||
{ |
|||
if (focusedWindow != EditorWindow.focusedWindow) |
|||
{ |
|||
focusedWindow = EditorWindow.focusedWindow; |
|||
|
|||
if (focusedWindow?.GetType() == hierarchyType) |
|||
{ |
|||
if (hierarchyGUI != null) |
|||
hierarchyGUI.onGUIHandler -= OnFocusedHierarchyGUI; |
|||
|
|||
hierarchyGUI = focusedWindow.rootVisualElement.parent.Query<IMGUIContainer>(); |
|||
hierarchyGUI.onGUIHandler += OnFocusedHierarchyGUI; |
|||
} |
|||
} |
|||
} |
|||
|
|||
private static void OnFocusedHierarchyGUI() |
|||
{ |
|||
// As Event.current is null during context-menu callback, we need to track mouse position on hierarchy GUI
|
|||
mousePosition = GUIUtility.GUIToScreenPoint(Event.current.mousePosition); |
|||
} |
|||
|
|||
[MenuItem("GameObject/Replace", true, priority = 0)] |
|||
private static bool ReplaceSelectionValidate() |
|||
{ |
|||
return Selection.gameObjects.Length > 0; |
|||
} |
|||
|
|||
[MenuItem("GameObject/Replace", priority = 0)] |
|||
private static void ReplaceSelection() |
|||
{ |
|||
if (hasExecuted) |
|||
return; |
|||
|
|||
var rect = new Rect(mousePosition, new Vector2(240, 360)); |
|||
|
|||
ReplacePrefabSearchPopup.Show(rect); |
|||
|
|||
EditorApplication.delayCall += () => hasExecuted = false; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: a36e948ccc254a1cbffab62792cda09d |
|||
timeCreated: 1606469766 |
|
|||
using System; |
|||
using System.IO; |
|||
using UnityEditor; |
|||
using UnityEditor.Callbacks; |
|||
using UnityEditor.IMGUI.Controls; |
|||
using UnityEngine; |
|||
using static UnityEditor.EditorGUIUtility; |
|||
using static UnityEditor.EditorJsonUtility; |
|||
using static UnityEngine.Application; |
|||
|
|||
namespace UOP1.EditorTools.Replacer |
|||
{ |
|||
internal class ReplacePrefabSearchPopup : EditorWindow |
|||
{ |
|||
private const float previewHeight = 128; |
|||
|
|||
private class ViewState : ScriptableObject |
|||
{ |
|||
public TreeViewState treeViewState = new TreeViewState(); |
|||
} |
|||
|
|||
private static ReplacePrefabSearchPopup window; |
|||
private static Styles styles; |
|||
|
|||
private static Event evt => Event.current; |
|||
private static string assetPath => Path.Combine(dataPath.Remove(dataPath.Length - 7, 7), "Library", "ReplacePrefabTreeState.asset"); |
|||
|
|||
private bool hasSelection => tree.state.selectedIDs.Count > 0; |
|||
private int selectedId => tree.state.selectedIDs[0]; |
|||
private GameObject instance => EditorUtility.InstanceIDToObject(selectedId) as GameObject; |
|||
|
|||
private SearchField searchField; |
|||
private PrefabSelectionTreeView tree; |
|||
private ViewState viewState; |
|||
|
|||
private Vector2 startPos; |
|||
private Vector2 startSize; |
|||
private Vector2 lastSize; |
|||
|
|||
private GameObjectPreview selectionPreview = new GameObjectPreview(); |
|||
|
|||
public static void Show(Rect rect) |
|||
{ |
|||
var windows = Resources.FindObjectsOfTypeAll<ReplacePrefabSearchPopup>(); |
|||
window = windows.Length != 0 ? windows[0] : CreateInstance<ReplacePrefabSearchPopup>(); |
|||
|
|||
window.Init(); |
|||
|
|||
window.startPos = rect.position; |
|||
window.startSize = rect.size; |
|||
|
|||
window.position = new Rect(rect.position, rect.size); |
|||
// Need to predict start window size to avoid trash frame
|
|||
window.SetInitialSize(); |
|||
|
|||
// This type of window supports resizing, but is also persistent, so we need to close it manually
|
|||
window.ShowPopup(); |
|||
|
|||
//onSelectEntry += _ => window.Close();
|
|||
} |
|||
|
|||
private void Init() |
|||
{ |
|||
viewState = CreateInstance<ViewState>(); |
|||
|
|||
if (File.Exists(assetPath)) |
|||
FromJsonOverwrite(File.ReadAllText(assetPath), viewState); |
|||
|
|||
tree = new PrefabSelectionTreeView(viewState.treeViewState); |
|||
tree.onSelectEntry += OnSelectEntry; |
|||
|
|||
AssetPreview.SetPreviewTextureCacheSize(tree.RowsCount); |
|||
|
|||
searchField = new SearchField(); |
|||
searchField.downOrUpArrowKeyPressed += tree.SetFocusAndEnsureSelectedItem; |
|||
searchField.SetFocus(); |
|||
} |
|||
|
|||
private void OnSelectEntry(GameObject prefab) |
|||
{ |
|||
ReplaceTool.ReplaceSelectedObjects(Selection.gameObjects, prefab); |
|||
} |
|||
|
|||
private void OnEnable() |
|||
{ |
|||
Init(); |
|||
} |
|||
|
|||
private void OnDisable() |
|||
{ |
|||
tree.Cleanup(); |
|||
} |
|||
|
|||
public new void Close() |
|||
{ |
|||
SaveState(); |
|||
base.Close(); |
|||
} |
|||
|
|||
private void SaveState() |
|||
{ |
|||
File.WriteAllText(assetPath, ToJson(viewState)); |
|||
} |
|||
|
|||
private void OnGUI() |
|||
{ |
|||
if (evt.type == EventType.KeyDown && evt.keyCode == KeyCode.Escape) |
|||
{ |
|||
if (tree.hasSearch) |
|||
tree.searchString = ""; |
|||
else |
|||
Close(); |
|||
} |
|||
|
|||
if (focusedWindow != this) |
|||
Close(); |
|||
|
|||
if (styles == null) |
|||
styles = new Styles(); |
|||
|
|||
DoToolbar(); |
|||
DoTreeView(); |
|||
DoSelectionPreview(); |
|||
} |
|||
|
|||
void DoToolbar() |
|||
{ |
|||
tree.searchString = searchField.OnToolbarGUI(tree.searchString); |
|||
|
|||
GUILayout.Label("Replace With...", styles.headerLabel); |
|||
} |
|||
|
|||
void DoTreeView() |
|||
{ |
|||
var rect = GUILayoutUtility.GetRect(0, 10000, 0, 10000); |
|||
rect.x += 2; |
|||
rect.width -= 4; |
|||
|
|||
rect.y += 2; |
|||
rect.height -= 4; |
|||
|
|||
tree.OnGUI(rect); |
|||
} |
|||
|
|||
void DoSelectionPreview() |
|||
{ |
|||
if (hasSelection && tree.IsRenderable(selectedId)) |
|||
{ |
|||
SetSize(startSize.x, startSize.y + previewHeight); |
|||
var previewRect = GUILayoutUtility.GetRect(position.width, previewHeight); |
|||
|
|||
selectionPreview.CreatePreviewForTarget(instance); |
|||
selectionPreview.RenderInteractivePreview(previewRect); |
|||
|
|||
selectionPreview.DrawPreviewTexture(previewRect); |
|||
} |
|||
else |
|||
{ |
|||
SetSize(startSize.x, startSize.y); |
|||
} |
|||
} |
|||
|
|||
private void SetInitialSize() |
|||
{ |
|||
if (hasSelection && tree.IsRenderable(selectedId)) |
|||
SetSize(startSize.x, startSize.y + previewHeight); |
|||
else |
|||
SetSize(startSize.x, startSize.y); |
|||
} |
|||
|
|||
private void SetSize(float width, float height) |
|||
{ |
|||
var newSize = new Vector2(width, height); |
|||
if (newSize != lastSize) |
|||
{ |
|||
lastSize = newSize; |
|||
position = new Rect(position.x, position.y, width, height); |
|||
} |
|||
} |
|||
|
|||
private class Styles |
|||
{ |
|||
public GUIStyle headerLabel = new GUIStyle(EditorStyles.centeredGreyMiniLabel) |
|||
{ |
|||
fontSize = 11, |
|||
fontStyle = FontStyle.Bold |
|||
}; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 566745c65b224919bb9886aba499be67 |
|||
timeCreated: 1606459889 |
撰写
预览
正在加载...
取消
保存
Reference in new issue