#if GRAPH_DESIGNER
/// ---------------------------------------------
/// Behavior Designer
/// Copyright (c) Opsive. All Rights Reserved.
/// https://www.opsive.com
/// ---------------------------------------------
namespace Opsive.BehaviorDesigner.Editor.Controls.NodeViews
{
using Opsive.GraphDesigner.Editor;
using Opsive.BehaviorDesigner.Runtime.Tasks;
using Opsive.Shared.Editor.UIElements.Controls;
using UnityEngine.UIElements;
using UnityEditor;
using UnityEngine;
///
/// Implements TypeControlBase for the StackedTask type.
///
[ControlType(typeof(StackedTask))]
public class StackedTaskNodeViewControl : TaskNodeViewControl
{
private const float c_ActiveIconRotationSpeed = 30;
///
/// Displays information about the nested task within the Stacked Task.
///
private class TaskView : VisualElement
{
private const string c_DarkActiveIconGUID = "1230b934cbd748345b13125468a34720";
private const string c_LightActiveIconGUID = "e57f179ee476f274dbe537179e67bf04";
private int m_Index;
private Image m_ActiveImage;
///
/// TaskView constructor.
///
/// The index of the task.
/// A reference to the task.
public TaskView(int index, Task task)
{
m_Index = index;
var horizontalLayout = new VisualElement();
horizontalLayout.AddToClassList("horizontal-layout");
horizontalLayout.style.height = 18;
var label = new Label(task.ToString());
label.style.flexGrow = 1;
horizontalLayout.Add(label);
m_ActiveImage = new Image();
m_ActiveImage.image = Shared.Editor.Utility.EditorUtility.LoadAsset(EditorGUIUtility.isProSkin ? c_DarkActiveIconGUID : c_LightActiveIconGUID);
m_ActiveImage.style.width = 16;
m_ActiveImage.style.height = 16;
m_ActiveImage.style.display = DisplayStyle.None;
horizontalLayout.Add(m_ActiveImage);
Add(horizontalLayout);
}
///
/// Updates the status of the task.
///
/// The index that is active.
public void UpdateStatus(int activeIndex)
{
m_ActiveImage.style.display = (m_Index == activeIndex ? DisplayStyle.Flex : DisplayStyle.None);
if (m_Index == activeIndex) {
if (Application.isPlaying) {
var eulerAngles = m_ActiveImage.transform.rotation.eulerAngles;
m_ActiveImage.transform.rotation = Quaternion.Euler(eulerAngles.x, eulerAngles.y, eulerAngles.z + c_ActiveIconRotationSpeed);
}
} else {
m_ActiveImage.transform.rotation = Quaternion.identity;
}
}
}
private StackedTask m_StackedTask;
private TaskView[] m_TaskViews;
///
/// Addes the UIElements for the specified runtime node to the editor Node within the graph.
///
/// A reference to the GraphWindow.
/// The parent UIElement that should contain the node UIElements.
/// The node that the control represents.
public override void AddNodeView(GraphWindow graphWindow, VisualElement parent, object node)
{
base.AddNodeView(graphWindow, parent, node);
m_StackedTask = node as StackedTask;
if (m_StackedTask.Tasks == null) {
return;
}
var tasks = m_StackedTask.Tasks;
m_TaskViews = new TaskView[tasks.Length];
for (int i = 0; i < tasks.Length; ++i) {
var task = m_StackedTask.Tasks[i];
// The task no longer exists. Replace it.
if (task == null) {
tasks[i] = new UnknownTask();
m_StackedTask.Tasks = tasks;
}
m_TaskViews[i] = new TaskView(i, m_StackedTask.Tasks[i]);
parent.Add(m_TaskViews[i]);
}
}
///
/// Internal method which updates the node with the current execution status.
///
/// The status of the task.
protected override TaskStatus UpdateNodeInternal()
{
var activeIndex = -1;
TaskStatus status;
if ((status = base.UpdateNodeInternal()) == TaskStatus.Running && m_StackedTask.Tasks.Length > 1) {
activeIndex = m_StackedTask.ActiveIndex;
for (int i = 0; i < m_TaskViews.Length; ++i) {
m_TaskViews[i].UpdateStatus(activeIndex);
}
} else {
for (int i = 0; i < m_TaskViews.Length; ++i) {
m_TaskViews[i].UpdateStatus(activeIndex);
}
}
return status;
}
}
}
#endif