// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See LICENSE in the project root for license information. using System; using System.Reflection; using UnityEngine; using HoloToolkit.Unity; namespace HoloToolkit.Unity.Buttons { /// <summary> /// Class that can be used to toggle between to button profiles for any target component inheriting from ProfileButtonBase /// </summary> [RequireComponent(typeof(CompoundButton))] public class CompoundButtonToggle : MonoBehaviour { [Tooltip("Toggle behavior")] public ToggleBehaviorEnum Behavior = ToggleBehaviorEnum.OnTapped; [Tooltip("Profile to use when State is TRUE")] [HideInMRTKInspector] public ButtonProfile OnProfile; [Tooltip("Profile to use when State is FALSE")] [HideInMRTKInspector] public ButtonProfile OffProfile; [DropDownComponent(true)] [Tooltip("Component to target - must inherit from ProfileButtonBase")] public Component Target; /// <summary> /// Private reference of the compound button component /// </summary> private CompoundButton m_compButton; public bool State { get { return state; } set { SetState(value); } } [SerializeField] private bool state; /// <summary> /// On enable subscribe to button state change on the compound button component /// </summary> private void OnEnable() { m_compButton = GetComponent<CompoundButton>(); // Force initial state setting SetState(state, true); if (m_compButton != null) m_compButton.StateChange += ButtonStateChange; } /// <summary> /// On disable unsubscribe to button state change on the compound button component /// </summary> private void OnDisable() { if (m_compButton != null) m_compButton.StateChange -= ButtonStateChange; } /// <summary> /// Handle button pressed callback from button /// </summary> /// <param name="buttonObj"></param> public void ButtonStateChange(ButtonStateEnum newState) { if(newState == ButtonStateEnum.Pressed) { switch (Behavior) { default: break; case ToggleBehaviorEnum.OnTapped: State = !State; break; } } else if(newState == ButtonStateEnum.ObservationTargeted || newState == ButtonStateEnum.Targeted) { switch (Behavior) { default: break; case ToggleBehaviorEnum.OnFocus: State = !State; break; } } } private void SetState (bool newState, bool force = false) { if ((!force || !Application.isPlaying) && state == newState) return; if (Target == null || OnProfile == null || OffProfile == null) return; state = newState; // Get the profile field of the target component and set it to the on profile // Store all icons in iconLookup via reflection #if USE_WINRT FieldInfo fieldInfo = Target.GetType().GetTypeInfo().GetField("Profile"); #else FieldInfo fieldInfo = Target.GetType().GetField("Profile"); #endif if (fieldInfo == null) { Debug.LogError("Target component had no field type profile in CompoundButtonToggle"); return; } fieldInfo.SetValue(Target, state ? OnProfile : OffProfile); if (Application.isPlaying) { // Disable, then re-enable the target // This will force the component to update itself ((MonoBehaviour)Target).enabled = false; ((MonoBehaviour)Target).enabled = true; } } #if UNITY_EDITOR [UnityEditor.CustomEditor(typeof(CompoundButtonToggle))] public class CustomEditor : MRTKEditor { protected override void DrawCustomFooter() { CompoundButtonToggle toggle = (CompoundButtonToggle)target; FieldInfo fieldInfo = null; Type profileType = null; if (toggle.Target == null) { DrawError("Target must be set."); return; } else { fieldInfo = toggle.Target.GetType().GetField("Profile"); if (fieldInfo == null) { DrawError("Target component has no 'Profile' field - are you use this class inherits from ProfileButtonBase?"); return; } GUIStyle labelStyle = new GUIStyle(UnityEditor.EditorStyles.label); labelStyle.fontSize = 18; labelStyle.fontStyle = FontStyle.Bold; profileType = fieldInfo.FieldType; UnityEditor.EditorGUILayout.LabelField("Type: " + toggle.Target.GetType().Name + " / " + fieldInfo.FieldType.Name, labelStyle, GUILayout.MinHeight(24)); } UnityEditor.EditorGUILayout.LabelField("Select on/off profiles of the type " + profileType.Name); if (toggle.OnProfile == null) { toggle.OnProfile = (ButtonProfile)fieldInfo.GetValue(toggle.Target); } if (toggle.OffProfile == null) { toggle.OffProfile = toggle.OnProfile; } ButtonProfile onProfile = (ButtonProfile)UnityEditor.EditorGUILayout.ObjectField("On Profile", toggle.OnProfile, typeof(ButtonProfile), false); ButtonProfile offProfile = (ButtonProfile)UnityEditor.EditorGUILayout.ObjectField("Off Profile", toggle.OffProfile, typeof(ButtonProfile), false); if (onProfile.GetType() == profileType) { toggle.OnProfile = onProfile; } if (offProfile.GetType() == profileType) { toggle.OffProfile = offProfile; } if (toggle.OnProfile.GetType() != profileType) { DrawError("On profile object does not match type " + profileType.Name); } if (toggle.OffProfile.GetType() != profileType) { DrawError("Off profile object does not match type " + profileType.Name); } if (onProfile == offProfile) { DrawWarning("Profiles are the same - toggle will have no effect"); } toggle.Behavior = (ToggleBehaviorEnum)UnityEditor.EditorGUILayout.EnumPopup("Toggle behavior", toggle.Behavior); } } #endif } }