// Copyright (c) Microsoft Corporation. // Licensed under the MIT License using Microsoft.MixedReality.Toolkit.Utilities; using System; using System.Linq; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.Experimental.InteractiveElement { /// /// The container that represents a single Interaction State. This class is utilized by the BaseInteractiveElement MonoBehaviour. /// [System.Serializable] public class InteractionState { /// /// Constructor for an Interaction State. /// /// The name of the state public InteractionState(string stateName) { Name = stateName; SetEventConfiguration(Name); SetInteractionType(Name); } [SerializeField] [Tooltip("The name of the state")] private string stateName; /// /// The name of the state. /// public string Name { get => stateName; internal set => stateName = value; } [SerializeField] [Tooltip("The value of the state. The value will be 0 if the state is off, 1 if the state is on.")] private int stateValue = 0; /// /// The value of the state. The value will be 0 if the state is off, 1 if the state is on. /// public int Value { get => stateValue; internal set => stateValue = value; } [SerializeField] [Tooltip("Whether or not the state is currently active.")] private bool active = false; /// /// Whether or not the state is currently active. /// public bool Active { get => active; internal set => active = value; } [SerializeField] [Tooltip("The type of interaction (Near, Far, Both, Other) this state is associated with.")] private InteractionType interactionType = InteractionType.Other; /// /// The type of interaction (Near, Far, Both, None) this state is associated with. /// public InteractionType InteractionType { get => interactionType; internal set => interactionType = value; } [SerializeReference] [Tooltip("The event configuration for this state. ")] private IStateEventConfig eventConfiguration = null; /// /// The event configuration for this state. /// public IStateEventConfig EventConfiguration { get => eventConfiguration; internal set => eventConfiguration = value; } private const string Near = "Near"; private const string Far = "Far"; // List of all core state names private string[] coreStates = Enum.GetNames(typeof(CoreInteractionState)).ToArray(); // Set the event configuration for a new state internal void SetEventConfiguration(string stateName) { if (EventConfiguration == null) { BaseInteractionEventConfiguration eventConfiguration; string subStateName = GetSubStateName(); // Find matching event configuration by state name var eventConfigTypes = TypeCacheUtility.GetSubClasses(); Type eventConfigType; try { eventConfigType = eventConfigTypes?.Find((type) => type.Name.StartsWith(subStateName)); } catch { eventConfigType = null; } if (eventConfigType != null) { // If a state has an associated event configuration class, then create an instance with the matching type eventConfiguration = Activator.CreateInstance(eventConfigType) as BaseInteractionEventConfiguration; } else { // If the state does not have a specific event configuration class type, create the an instance of StateEvents. // StateEvents is the default type for a state's event configuration when a matching event configuration type does not exist. eventConfiguration = Activator.CreateInstance(typeof(StateEvents)) as BaseInteractionEventConfiguration; } eventConfiguration.StateName = stateName; EventConfiguration = eventConfiguration; } } // Set the InteractionType for a state based on the state name internal void SetInteractionType(string stateName) { string touchStateName = CoreInteractionState.Touch.ToString(); string focusStateName = CoreInteractionState.Focus.ToString(); if (stateName.Contains(Far)) { InteractionType = InteractionType.Far; } // The Touch state is a special case because it does not contain "Near" in the state name but // the InteractionType is Near else if (stateName.Contains(Near) || stateName == touchStateName) { InteractionType = InteractionType.Near; } // Special case for Focus as that state supports near and far interaction without "Near" or "Far" in the name else if (stateName == focusStateName) { InteractionType = InteractionType.NearAndFar; } else { InteractionType = InteractionType.Other; } } // Trim the name of a state if it contains "Near" or "Far" if the current state contains "Focus" in the name internal string GetSubStateName() { string focusStateName = CoreInteractionState.Focus.ToString(); string subStateName = Name; if (subStateName.Contains(focusStateName)) { // If the state name contains Near, then remove "Near" and return the remaining sub-string if (subStateName.Contains(Near)) { subStateName = stateName.Replace(Near, ""); } else if (stateName.Contains(Far)) { subStateName = stateName.Replace(Far, ""); } } return subStateName; } } }