You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
315 lines
14 KiB
315 lines
14 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using UnityEditor.Experimental.GraphView;
|
|
using UnityEditor.Graphing;
|
|
using UnityEditor.ShaderGraph.Internal;
|
|
using UnityEngine;
|
|
using UnityEngine.Assertions;
|
|
using UnityEngine.UIElements;
|
|
using GraphDataStore = UnityEditor.ShaderGraph.DataStore<UnityEditor.ShaderGraph.GraphData>;
|
|
using BlackboardItem = UnityEditor.ShaderGraph.Internal.ShaderInput;
|
|
using BlackboardItemController = UnityEditor.ShaderGraph.Drawing.ShaderInputViewController;
|
|
|
|
namespace UnityEditor.ShaderGraph.Drawing
|
|
{
|
|
class MoveShaderInputAction : IGraphDataAction
|
|
{
|
|
void MoveShaderInput(GraphData graphData)
|
|
{
|
|
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out MoveShaderInputAction");
|
|
AssertHelpers.IsNotNull(shaderInputReference, "ShaderInputReference is null while carrying out MoveShaderInputAction");
|
|
graphData.owner.RegisterCompleteObjectUndo("Move Graph Input");
|
|
graphData.MoveItemInCategory(shaderInputReference, newIndexValue, associatedCategoryGuid);
|
|
}
|
|
|
|
public Action<GraphData> modifyGraphDataAction => MoveShaderInput;
|
|
|
|
internal string associatedCategoryGuid { get; set; }
|
|
|
|
// Reference to the shader input being modified
|
|
internal ShaderInput shaderInputReference { get; set; }
|
|
|
|
internal int newIndexValue { get; set; }
|
|
}
|
|
|
|
class DeleteCategoryAction : IGraphDataAction
|
|
{
|
|
void RemoveCategory(GraphData graphData)
|
|
{
|
|
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out DeleteCategoryAction");
|
|
AssertHelpers.IsNotNull(categoriesToRemoveGuids, "CategoryToRemove is null while carrying out DeleteCategoryAction");
|
|
|
|
// This is called by MaterialGraphView currently, no need to repeat it here, though ideally it would live here
|
|
//graphData.owner.RegisterCompleteObjectUndo("Delete Category");
|
|
|
|
foreach (var categoryGUID in categoriesToRemoveGuids)
|
|
{
|
|
graphData.RemoveCategory(categoryGUID);
|
|
}
|
|
}
|
|
|
|
public Action<GraphData> modifyGraphDataAction => RemoveCategory;
|
|
|
|
// Reference to the guid(s) of categories being deleted
|
|
public HashSet<string> categoriesToRemoveGuids { get; set; } = new HashSet<string>();
|
|
}
|
|
|
|
class ChangeCategoryIsExpandedAction : IGraphDataAction
|
|
{
|
|
internal const string kEditorPrefKey = ".isCategoryExpanded";
|
|
|
|
void ChangeIsExpanded(GraphData graphData)
|
|
{
|
|
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeIsExpanded on Category");
|
|
foreach (var catid in categoryGuids)
|
|
{
|
|
var key = $"{editorPrefsBaseKey}.{catid}.{kEditorPrefKey}";
|
|
var currentValue = EditorPrefs.GetBool(key, true);
|
|
|
|
if (currentValue != isExpanded)
|
|
{
|
|
EditorPrefs.SetBool(key, isExpanded);
|
|
}
|
|
}
|
|
}
|
|
|
|
public string editorPrefsBaseKey;
|
|
public List<string> categoryGuids { get; set; }
|
|
public bool isExpanded { get; set; }
|
|
|
|
public Action<GraphData> modifyGraphDataAction => ChangeIsExpanded;
|
|
}
|
|
|
|
class ChangeCategoryNameAction : IGraphDataAction
|
|
{
|
|
void ChangeCategoryName(GraphData graphData)
|
|
{
|
|
AssertHelpers.IsNotNull(graphData, "GraphData is null while carrying out ChangeCategoryNameAction");
|
|
graphData.owner.RegisterCompleteObjectUndo("Change Category Name");
|
|
graphData.ChangeCategoryName(categoryGuid, newCategoryNameValue);
|
|
}
|
|
|
|
public Action<GraphData> modifyGraphDataAction => ChangeCategoryName;
|
|
|
|
// Guid of the category being modified
|
|
public string categoryGuid { get; set; }
|
|
|
|
internal string newCategoryNameValue { get; set; }
|
|
}
|
|
|
|
class BlackboardCategoryController : SGViewController<CategoryData, BlackboardCategoryViewModel>, IDisposable
|
|
{
|
|
internal SGBlackboardCategory blackboardCategoryView => m_BlackboardCategoryView;
|
|
SGBlackboardCategory m_BlackboardCategoryView;
|
|
Dictionary<string, BlackboardItemController> m_BlackboardItemControllers = new Dictionary<string, ShaderInputViewController>();
|
|
SGBlackboard blackboard { get; set; }
|
|
|
|
Action m_UnregisterAll;
|
|
|
|
internal BlackboardCategoryController(CategoryData categoryData, BlackboardCategoryViewModel categoryViewModel, GraphDataStore dataStore)
|
|
: base(categoryData, categoryViewModel, dataStore)
|
|
{
|
|
m_BlackboardCategoryView = new SGBlackboardCategory(categoryViewModel, this);
|
|
blackboard = categoryViewModel.parentView as SGBlackboard;
|
|
if (blackboard == null)
|
|
return;
|
|
|
|
blackboard.Add(m_BlackboardCategoryView);
|
|
|
|
var dragActionCancelCallback = new EventCallback<MouseUpEvent>((evt) =>
|
|
{
|
|
m_BlackboardCategoryView.OnDragActionCanceled();
|
|
});
|
|
|
|
m_UnregisterAll += () => blackboard.UnregisterCallback(dragActionCancelCallback);
|
|
|
|
// These make sure that the drag indicators are disabled whenever a drag action is cancelled without completing a drop
|
|
blackboard.RegisterCallback(dragActionCancelCallback);
|
|
blackboard.hideDragIndicatorAction += m_BlackboardCategoryView.OnDragActionCanceled;
|
|
|
|
foreach (var categoryItem in categoryData.Children)
|
|
{
|
|
if (categoryItem == null)
|
|
{
|
|
AssertHelpers.Fail("Failed to insert blackboard row into category due to shader input being null.");
|
|
continue;
|
|
}
|
|
InsertBlackboardRow(categoryItem);
|
|
}
|
|
}
|
|
|
|
protected override void RequestModelChange(IGraphDataAction changeAction)
|
|
{
|
|
DataStore.Dispatch(changeAction);
|
|
}
|
|
|
|
// Called by GraphDataStore.Subscribe after the model has been changed
|
|
protected override void ModelChanged(GraphData graphData, IGraphDataAction changeAction)
|
|
{
|
|
// If categoryData associated with this controller is removed by an operation, destroy controller and views associated
|
|
if (graphData.ContainsCategory(Model) == false)
|
|
{
|
|
Dispose();
|
|
return;
|
|
}
|
|
|
|
switch (changeAction)
|
|
{
|
|
case AddShaderInputAction addBlackboardItemAction:
|
|
if (addBlackboardItemAction.shaderInputReference != null && IsInputInCategory(addBlackboardItemAction.shaderInputReference))
|
|
{
|
|
var blackboardRow = FindBlackboardRow(addBlackboardItemAction.shaderInputReference);
|
|
if (blackboardRow == null)
|
|
blackboardRow = InsertBlackboardRow(addBlackboardItemAction.shaderInputReference);
|
|
// Rows should auto-expand when an input is first added
|
|
// blackboardRow.expanded = true;
|
|
var propertyView = blackboardRow.Q<SGBlackboardField>();
|
|
if (addBlackboardItemAction.addInputActionType == AddShaderInputAction.AddActionSource.AddMenu)
|
|
propertyView.OpenTextEditor();
|
|
}
|
|
break;
|
|
|
|
case CopyShaderInputAction copyShaderInputAction:
|
|
// In the specific case of only-one keywords like Material Quality and Raytracing, they can get copied, but because only one can exist, the output copied value is null
|
|
if (copyShaderInputAction.copiedShaderInput != null && IsInputInCategory(copyShaderInputAction.copiedShaderInput))
|
|
{
|
|
var blackboardRow = InsertBlackboardRow(copyShaderInputAction.copiedShaderInput, copyShaderInputAction.insertIndex);
|
|
if (blackboardRow != null)
|
|
{
|
|
var graphView = ViewModel.parentView.GetFirstAncestorOfType<MaterialGraphView>();
|
|
var propertyView = blackboardRow.Q<SGBlackboardField>();
|
|
graphView?.AddToSelectionNoUndoRecord(propertyView);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case AddItemToCategoryAction addItemToCategoryAction:
|
|
// If item was added to category that this controller manages, then add blackboard row to represent that item
|
|
if (addItemToCategoryAction.itemToAdd != null && addItemToCategoryAction.categoryGuid == ViewModel.associatedCategoryGuid)
|
|
{
|
|
InsertBlackboardRow(addItemToCategoryAction.itemToAdd, addItemToCategoryAction.indexToAddItemAt);
|
|
}
|
|
else
|
|
{
|
|
// If the added input has been added to a category other than this one, and it used to belong to this category,
|
|
// Then cleanup the controller and view that used to represent that input
|
|
foreach (var key in m_BlackboardItemControllers.Keys)
|
|
{
|
|
var blackboardItemController = m_BlackboardItemControllers[key];
|
|
if (blackboardItemController.Model == addItemToCategoryAction.itemToAdd)
|
|
{
|
|
RemoveBlackboardRow(addItemToCategoryAction.itemToAdd);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case DeleteCategoryAction deleteCategoryAction:
|
|
if (deleteCategoryAction.categoriesToRemoveGuids.Contains(ViewModel.associatedCategoryGuid))
|
|
{
|
|
this.Dispose();
|
|
return;
|
|
}
|
|
|
|
break;
|
|
|
|
case ChangeCategoryIsExpandedAction changeIsExpandedAction:
|
|
if (changeIsExpandedAction.categoryGuids.Contains(ViewModel.associatedCategoryGuid))
|
|
{
|
|
ViewModel.isExpanded = changeIsExpandedAction.isExpanded;
|
|
m_BlackboardCategoryView.TryDoFoldout(changeIsExpandedAction.isExpanded);
|
|
}
|
|
break;
|
|
|
|
case ChangeCategoryNameAction changeCategoryNameAction:
|
|
if (changeCategoryNameAction.categoryGuid == ViewModel.associatedCategoryGuid)
|
|
{
|
|
ViewModel.name = Model.name;
|
|
m_BlackboardCategoryView.title = ViewModel.name;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
internal bool IsInputInCategory(ShaderInput shaderInput)
|
|
{
|
|
return Model != null && Model.IsItemInCategory(shaderInput);
|
|
}
|
|
|
|
internal SGBlackboardRow FindBlackboardRow(ShaderInput shaderInput)
|
|
{
|
|
m_BlackboardItemControllers.TryGetValue(shaderInput.objectId, out var associatedController);
|
|
return associatedController?.BlackboardItemView;
|
|
}
|
|
|
|
// Creates controller, view and view model for a blackboard item and adds the view to the specified index in the category
|
|
// By default adds it to the end of the list if no insertionIndex specified
|
|
internal SGBlackboardRow InsertBlackboardRow(BlackboardItem shaderInput, int insertionIndex = -1)
|
|
{
|
|
var shaderInputViewModel = new ShaderInputViewModel()
|
|
{
|
|
model = shaderInput,
|
|
parentView = blackboardCategoryView,
|
|
};
|
|
var blackboardItemController = new BlackboardItemController(shaderInput, shaderInputViewModel, DataStore);
|
|
|
|
m_BlackboardItemControllers.TryGetValue(shaderInput.objectId, out var existingItemController);
|
|
if (existingItemController == null)
|
|
{
|
|
m_BlackboardItemControllers.Add(shaderInput.objectId, blackboardItemController);
|
|
// If no index specified, or if trying to insert at last index, add to end of category
|
|
if (insertionIndex == -1 || insertionIndex == m_BlackboardItemControllers.Count() - 1)
|
|
blackboardCategoryView.Add(blackboardItemController.BlackboardItemView);
|
|
else
|
|
blackboardCategoryView.Insert(insertionIndex, blackboardItemController.BlackboardItemView);
|
|
|
|
blackboardCategoryView.MarkDirtyRepaint();
|
|
|
|
return blackboardItemController.BlackboardItemView;
|
|
}
|
|
else
|
|
{
|
|
AssertHelpers.Fail("Tried to add blackboard item that already exists to category.");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
internal void RemoveBlackboardRow(BlackboardItem shaderInput)
|
|
{
|
|
m_BlackboardItemControllers.TryGetValue(shaderInput.objectId, out var associatedBlackboardItemController);
|
|
if (associatedBlackboardItemController != null)
|
|
{
|
|
associatedBlackboardItemController.Dispose();
|
|
m_BlackboardItemControllers.Remove(shaderInput.objectId);
|
|
}
|
|
else
|
|
AssertHelpers.Fail("Failed to find associated blackboard item controller for shader input that was just deleted. Cannot clean up view associated with input.");
|
|
}
|
|
|
|
void ClearBlackboardRows()
|
|
{
|
|
foreach (var shaderInputViewController in m_BlackboardItemControllers.Values)
|
|
shaderInputViewController.Dispose();
|
|
|
|
m_BlackboardItemControllers.Clear();
|
|
}
|
|
|
|
public override void Dispose()
|
|
{
|
|
if(blackboard == null)
|
|
return;
|
|
|
|
base.Dispose();
|
|
Cleanup();
|
|
ClearBlackboardRows();
|
|
m_UnregisterAll?.Invoke();
|
|
|
|
blackboard = null;
|
|
m_BlackboardCategoryView?.Dispose();
|
|
m_BlackboardCategoryView?.Clear();
|
|
m_BlackboardCategoryView = null;
|
|
}
|
|
}
|
|
}
|