study/first_study/Library/PackageCache/com.unity.render-pipelines.universal@d10049dfa479/Editor/Converter/RenderPipelineConverterVisualElement.cs
jh04010421 739d49f1a0 Unity | 2026.01.20
수업 실습 파일
2026-01-20 11:01:57 +09:00

350 lines
14 KiB
C#

using System;
using System.Collections.Generic;
using System.Text;
using UnityEngine;
using UnityEngine.UIElements;
namespace UnityEditor.Rendering.Universal
{
internal class RenderPipelineConverterVisualElement : VisualElement
{
const string k_Uxml = "Packages/com.unity.render-pipelines.universal/Editor/Converter/converter_widget_main.uxml";
const string k_Uss = "Packages/com.unity.render-pipelines.universal/Editor/Converter/converter_widget_main.uss";
static Lazy<VisualTreeAsset> s_VisualTreeAsset = new Lazy<VisualTreeAsset>(() => AssetDatabase.LoadAssetAtPath<VisualTreeAsset>(k_Uxml));
static Lazy<StyleSheet> s_StyleSheet = new Lazy<StyleSheet>(() => AssetDatabase.LoadAssetAtPath<StyleSheet>(k_Uss));
ConverterInfo m_ConverterInfo;
// TODO: Once attributes land on all the converters use m_ConverterInfo;
public string displayName => converter.name;
public string description => converter.info;
public ConverterState state => m_ConverterInfo.state;
public RenderPipelineConverter converter => m_ConverterInfo.converter as RenderPipelineConverter;
public bool isActiveAndEnabled => converter.isEnabled && state.isActive;
public bool requiresInitialization => !state.isInitialized && isActiveAndEnabled;
VisualElement m_RootVisualElement;
Label m_PendingLabel;
Label m_WarningLabel;
Label m_ErrorLabel;
Label m_SuccessLabel;
public Action showMoreInfo; // TODO Remove with the UX rework
public Action converterSelected;
public RenderPipelineConverterVisualElement(ConverterInfo converterInfo)
{
m_ConverterInfo = converterInfo;
m_RootVisualElement = new VisualElement();
s_VisualTreeAsset.Value.CloneTree(m_RootVisualElement);
m_RootVisualElement.styleSheets.Add(s_StyleSheet.Value);
var converterEnabledToggle = m_RootVisualElement.Q<Toggle>("converterEnabled");
converterEnabledToggle.SetValueWithoutNotify(state.isActive);
converterEnabledToggle.RegisterCallback<ClickEvent>((evt) =>
{
state.isActive = !state.isActive;
converterSelected?.Invoke();
UpdateConversionInfo();
evt.StopPropagation(); // This toggle needs to stop propagation since it is inside another clickable element
});
var topElement = m_RootVisualElement.Q<VisualElement>("converterTopVisualElement");
topElement.RegisterCallback<ClickEvent>((evt) =>
{
showMoreInfo?.Invoke();
});
topElement.RegisterCallback<TooltipEvent>(evt =>
{
// Show the tooltip around the toggle only
var rect = converterEnabledToggle.worldBound;
rect.position += new Vector2(150, -30); // offset it a bit to not be ove the toggle
evt.rect = rect; // position area that triggers it
evt.StopPropagation();
});
var allLabel = m_RootVisualElement.Q<Label>("all");
allLabel.RegisterCallback<ClickEvent>((evt) =>
{
SetItemsActive(true);
Refresh();
});
var noneLabel = m_RootVisualElement.Q<Label>("none");
noneLabel.RegisterCallback<ClickEvent>((evt) =>
{
SetItemsActive(false);
Refresh();
});
ListView listView = m_RootVisualElement.Q<ListView>("converterItems");
listView.showBoundCollectionSize = false;
listView.makeItem = () =>
{
var item = new RenderPipelineConverterItemVisualElement();
item.itemSelectionChanged += UpdateInfo;
return item;
};
listView.bindItem = (element, index) =>
{
var item = element as RenderPipelineConverterItemVisualElement;
item.Bind(state.items[index]);
};
listView.selectionChanged += obj => { converter.OnClicked(listView.selectedIndex); };
// setup the images
m_RootVisualElement.Q<Image>("pendingImage").image = CoreEditorStyles.iconPending;
m_RootVisualElement.Q<Image>("pendingImage").tooltip = "Pending";
m_RootVisualElement.Q<Image>("warningImage").image = CoreEditorStyles.iconWarn;
m_RootVisualElement.Q<Image>("warningImage").tooltip = "Warnings";
m_RootVisualElement.Q<Image>("errorImage").image = CoreEditorStyles.iconFail;
m_RootVisualElement.Q<Image>("errorImage").tooltip = "Failed";
m_RootVisualElement.Q<Image>("successImage").image = CoreEditorStyles.iconComplete;
m_RootVisualElement.Q<Image>("successImage").tooltip = "Success";
// Store labels to easy update afterwards
m_PendingLabel = m_RootVisualElement.Q<Label>("pendingLabel");
m_WarningLabel = m_RootVisualElement.Q<Label>("warningLabel");
m_ErrorLabel = m_RootVisualElement.Q<Label>("errorLabel");
m_SuccessLabel = m_RootVisualElement.Q<Label>("successLabel");
Add(m_RootVisualElement);
Refresh();
}
private void SetItemsActive(bool value)
{
foreach (var itemState in state.items)
itemState.isActive = value;
}
public void UpdateInfo()
{
UpdateConversionInfo();
UpdateSelectedConverterItemsLabel();
UpdateAllNoneLabels();
}
void UpdateSelectedConverterItemsLabel()
{
var text = $"{state.selectedItemsCount}/{state.items.Count} selected";
m_RootVisualElement.Q<Label>("converterStats").text = text;
}
void UpdateAllNoneLabels()
{
var allLabel = m_RootVisualElement.Q<Label>("all");
var noneLabel = m_RootVisualElement.Q<Label>("none");
var count = state.items.Count;
int selectedCount = state.selectedItemsCount;
bool noneSelected = selectedCount == 0;
bool allSelected = selectedCount == count;
SetSelected(allLabel, allSelected);
SetSelected(noneLabel, noneSelected);
}
void SetSelected(Label label, bool selected)
{
if (selected)
{
label.RemoveFromClassList("not_selected");
label.AddToClassList("selected");
}
else
{
label.RemoveFromClassList("selected");
label.AddToClassList("not_selected");
}
}
void UpdateConversionInfo()
{
// Make sure info is up to date
state.pending = 0;
state.errors = 0;
state.success = 0;
state.warnings = 0;
foreach (var converterItemState in state.items)
{
switch (converterItemState.status)
{
case Status.Pending: state.pending++; break;
case Status.Warning: state.warnings++; break;
case Status.Error: state.errors++; break;
case Status.Success: state.success++; break;
}
}
var info = GetConversionInfo();
m_RootVisualElement.Q<Label>("converterStateInfoL").text = info.message;
m_RootVisualElement.Q<Label>("converterStateInfoL").style.unityFontStyleAndWeight = FontStyle.Bold;
m_RootVisualElement.Q<Image>("converterStateInfoIcon").image = info.icon;
m_PendingLabel.text = $"{state.pending}";
m_WarningLabel.text = $"{state.warnings}";
m_ErrorLabel.text = $"{state.errors}";
m_SuccessLabel.text = $"{state.success}";
}
private (string message, Texture2D icon) GetConversionInfo()
{
if (!state.isActive)
return ("Converter Not Selected", null);
if (!state.isInitialized)
return ("Initialization Pending", CoreEditorStyles.iconPending);
if (state.errors > 0)
return ("Conversion Complete with Errors", CoreEditorStyles.iconFail);
if (state.warnings > 0)
return ("Conversion Pending with Warnings", CoreEditorStyles.iconWarn);
if (state.pending > 0)
return ("Conversion Pending", CoreEditorStyles.iconPending);
if (state.success > 0)
return ("Conversion Complete", CoreEditorStyles.iconComplete);
return ("No items found to convert", CoreEditorStyles.iconInfo);
}
public void ShowConverterLayout()
{
m_RootVisualElement.Q<VisualElement>("informationVE").style.display = DisplayStyle.Flex;
m_RootVisualElement.Q<VisualElement>("converterItems").style.display = DisplayStyle.Flex;
m_RootVisualElement.Q<ListView>("converterItems").itemsSource = state.items;
}
public void HideConverterLayout()
{
m_RootVisualElement.Q<VisualElement>("converterItems").style.display = DisplayStyle.None;
m_RootVisualElement.Q<VisualElement>("informationVE").style.display = DisplayStyle.None;
}
public void Refresh()
{
m_RootVisualElement.Q<ListView>("converterItems").Rebuild();
UpdateInfo();
m_RootVisualElement.SetEnabled(converter.isEnabled);
m_RootVisualElement.Q<Label>("converterName").text = displayName;
m_RootVisualElement.Q<VisualElement>("converterTopVisualElement").tooltip = (converter.isEnabled) ? description : converter.isDisabledWarningMessage;
}
public void Scan(Action onScanFinish)
{
// Create the context to call the converter init method
List<ConverterItemDescriptor> converterItemInfos = new List<ConverterItemDescriptor>();
var initCtx = new InitializeConverterContext { items = converterItemInfos };
state.isLoading = true;
converter.OnInitialize(initCtx, OnConverterCompleteDataCollection);
void OnConverterCompleteDataCollection()
{
// Set the item infos list to to the right index
state.items = new List<ConverterItemState>(converterItemInfos.Count);
for (var j = 0; j < converterItemInfos.Count; j++)
{
var converterItemState = new ConverterItemState()
{
descriptor = initCtx.items[j],
hasConverted = false,
isActive = true, // Default all the entries to true
status = Status.Pending
};
// The scan has already found some items that might not be convertible
if (!string.IsNullOrEmpty(converterItemInfos[j].warningMessage))
{
converterItemState.status = Status.Warning;
converterItemState.message = converterItemInfos[j].warningMessage;
converterItemState.isActive = false;
}
state.items.Add(converterItemState);
}
state.isLoading = false;
state.isInitialized = true;
Refresh();
onScanFinish?.Invoke();
}
}
public void Convert(string progressTitle)
{
if (state.pending == 0)
{
Debug.Log($"Skipping conversion, {converter.name} has no pending items to convert.");
return;
}
var sb = new StringBuilder($"Conversion results for item: {displayName}:{Environment.NewLine}");
converter.OnPreRun();
int itemIndex = 0;
int itemToConvertIndex = 0;
foreach (var item in state.items)
{
if (EditorUtility.DisplayCancelableProgressBar(progressTitle,
$"({itemToConvertIndex} of {state.pending}) {item.descriptor.name}",
itemToConvertIndex / (float)state.pending))
break;
if (!item.hasConverted && item.isActive)
{
try
{
var itemToConvertInfo = new ConverterItemInfo()
{
index = itemIndex,
descriptor = item.descriptor,
};
var ctx = new RunItemContext(itemToConvertInfo);
converter.OnRun(ref ctx);
item.hasConverted = true;
if (ctx.didFail)
{
item.status = Status.Error;
item.message = ctx.info;
sb.AppendLine($"- {item.descriptor.name} ({item.status}) ({ctx.info})");
}
else
{
item.status = Status.Success;
item.message = string.Empty;
sb.AppendLine($"- {item.descriptor.name} ({item.status})");
}
}
catch(Exception ex)
{
Debug.LogError($"Exception {ex.Message} while converting {item.descriptor} from {displayName}");
}
itemToConvertIndex++;
}
itemIndex++;
}
converter.OnPostRun();
Refresh();
sb.AppendLine(state.ToString());
Debug.Log(sb);
}
}
}