|
| 1 | +using UnityEngine; |
| 2 | +using UnityEditor; |
| 3 | +using UnityEditor.SceneManagement; |
| 4 | + |
| 5 | +[CustomEditor(typeof(TTSSetup))] |
| 6 | +public class TTSSetupEditor : Editor |
| 7 | +{ |
| 8 | + SerializedProperty openAIKey; |
| 9 | + SerializedProperty customText; |
| 10 | + Texture2D bannerTexture; |
| 11 | + |
| 12 | + readonly float uiElementHeight = 40f; |
| 13 | + private GUIStyle buttonStyle1, buttonStyle2, buttonStyle3, buttonStyle4; |
| 14 | + |
| 15 | + private void OnEnable() |
| 16 | + { |
| 17 | + openAIKey = serializedObject.FindProperty("openAIKey"); |
| 18 | + customText = serializedObject.FindProperty("customText"); |
| 19 | + bannerTexture = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Editor/banner.png"); |
| 20 | + } |
| 21 | + |
| 22 | + private Texture2D ColorTex(int width, int height, Color col) |
| 23 | + { |
| 24 | + Texture2D result = new Texture2D(width, height); |
| 25 | + Color[] pix = new Color[width * height]; |
| 26 | + for (int i = 0; i < pix.Length; i++) pix[i] = col; |
| 27 | + result.SetPixels(pix); |
| 28 | + result.Apply(); |
| 29 | + return result; |
| 30 | + } |
| 31 | + |
| 32 | + private GUIStyle CreateButtonStyle(Color baseColor) |
| 33 | + { |
| 34 | + GUIStyle style = new GUIStyle() |
| 35 | + { |
| 36 | + normal = |
| 37 | + { |
| 38 | + background = ColorTex(2, 2, baseColor), |
| 39 | + textColor = Color.white |
| 40 | + |
| 41 | + }, |
| 42 | + hover = { |
| 43 | + background = ColorTex(2, 2, baseColor*1.2f), |
| 44 | + textColor = Color.white |
| 45 | + }, |
| 46 | + |
| 47 | + active = |
| 48 | + { |
| 49 | + background = ColorTex(2, 2, baseColor*0.8f), |
| 50 | + textColor = Color.white |
| 51 | + }, |
| 52 | + margin = new RectOffset(10, 10, 4, 4), |
| 53 | + padding = new RectOffset(10, 10, 10, 10) |
| 54 | + }; |
| 55 | + |
| 56 | + return style; |
| 57 | + } |
| 58 | + |
| 59 | + |
| 60 | + public override void OnInspectorGUI() |
| 61 | + { |
| 62 | + serializedObject.Update(); |
| 63 | + // -- setup button styles |
| 64 | + GUILayoutOption[] buttonOptions = { GUILayout.Height(uiElementHeight) }; |
| 65 | + EnsureButtonStyles(); |
| 66 | + |
| 67 | + // -- banner gfx |
| 68 | + if (bannerTexture != null) |
| 69 | + { |
| 70 | + GUILayout.Space(5); |
| 71 | + |
| 72 | + float aspectRatio = (float)bannerTexture.height / bannerTexture.width; |
| 73 | + float width = EditorGUIUtility.currentViewWidth; |
| 74 | + float height = width * aspectRatio; |
| 75 | + |
| 76 | + Rect rect = GUILayoutUtility.GetRect(width, height); |
| 77 | + |
| 78 | + GUI.DrawTexture(rect, bannerTexture, ScaleMode.ScaleToFit); |
| 79 | + |
| 80 | + GUILayout.Space(5); |
| 81 | + GUILayout.Box("", new GUILayoutOption[] { GUILayout.ExpandWidth(true), GUILayout.Height(5) }); |
| 82 | + GUILayout.Space(5); |
| 83 | + } |
| 84 | + |
| 85 | + // -- section for the main setup of the TTS prefabs etc. |
| 86 | + EditorGUILayout.LabelField("Setup", EditorStyles.boldLabel); |
| 87 | + GUIStyle textFieldStyle = new GUIStyle(EditorStyles.textField) |
| 88 | + { |
| 89 | + alignment = TextAnchor.MiddleLeft, |
| 90 | + normal = { textColor = Color.white }, |
| 91 | + margin = new RectOffset(10, 10, 4, 4), |
| 92 | + padding = new RectOffset(10, 10, 10, 10) |
| 93 | + }; |
| 94 | + |
| 95 | + string placeholderKeyText = "0. Enter your OpenAI API key"; |
| 96 | + string apiKeyField = string.IsNullOrEmpty(openAIKey.stringValue) ? placeholderKeyText : openAIKey.stringValue; |
| 97 | + apiKeyField = EditorGUILayout.TextField(apiKeyField, textFieldStyle, GUILayout.Height(uiElementHeight)); |
| 98 | + |
| 99 | + if (apiKeyField != placeholderKeyText && !string.IsNullOrEmpty(apiKeyField))openAIKey.stringValue = apiKeyField; |
| 100 | + else if (string.IsNullOrEmpty(apiKeyField))openAIKey.stringValue = ""; |
| 101 | + |
| 102 | + if (GUILayout.Button("1. Add OpenAI Prefab", buttonStyle1, buttonOptions)) AddOpenAIPrefab(); |
| 103 | + |
| 104 | + if (GUILayout.Button("2. Add Text-To-Speech Prefab", buttonStyle2, buttonOptions)) AddTextToSpeechPrefab(); |
| 105 | + |
| 106 | + if (GUILayout.Button("3. Say \"Hello World!\"", buttonStyle3, buttonOptions)) SayHelloWorld(); |
| 107 | + |
| 108 | + // -- spacer |
| 109 | + EditorGUILayout.Space(); |
| 110 | + GUILayout.Box("", new GUILayoutOption[] { GUILayout.ExpandWidth(true), GUILayout.Height(5) }); |
| 111 | + EditorGUILayout.Space(); |
| 112 | + |
| 113 | + // -- section to synthesize your own text (after completing the main setup) |
| 114 | + string placeholderTestText = "4. Synthesize your own text"; |
| 115 | + string customTextField = string.IsNullOrEmpty(customText.stringValue) ? placeholderTestText : customText.stringValue; |
| 116 | + customTextField = EditorGUILayout.TextField(customTextField, textFieldStyle, GUILayout.Height(uiElementHeight)); |
| 117 | + |
| 118 | + if (customTextField != placeholderTestText && !string.IsNullOrEmpty(customTextField)) customText.stringValue = customTextField; |
| 119 | + else if (string.IsNullOrEmpty(customTextField)) customText.stringValue = ""; |
| 120 | + |
| 121 | + if (GUILayout.Button("Synthesize", buttonStyle4, buttonOptions)) SynthesizeCustomText(); |
| 122 | + |
| 123 | + GUIStyle wrappedBoldLabel = new GUIStyle(EditorStyles.boldLabel) |
| 124 | + { |
| 125 | + wordWrap = true |
| 126 | + }; |
| 127 | + |
| 128 | + // -- spacer |
| 129 | + GUILayout.Space(5); |
| 130 | + GUILayout.Box("", new GUILayoutOption[] { GUILayout.ExpandWidth(true), GUILayout.Height(5) }); |
| 131 | + GUILayout.Space(5); |
| 132 | + |
| 133 | + // -- info texts |
| 134 | + EditorGUILayout.LabelField("Make sure to tinker around with the TTSManager settings to change the model, voice, and speed.", wrappedBoldLabel); |
| 135 | + EditorGUILayout.Space(); |
| 136 | + EditorGUILayout.LabelField("For synthesizing text via script, just reference the TTSManager and call TTSManager.SynthesizeAndPlay(\"your text\").", wrappedBoldLabel); |
| 137 | + |
| 138 | + serializedObject.ApplyModifiedProperties(); |
| 139 | + } |
| 140 | + |
| 141 | + private void EnsureButtonStyles() |
| 142 | + { |
| 143 | + if (buttonStyle1 == null) |
| 144 | + { |
| 145 | + buttonStyle1 = CreateButtonStyle(new Color(21f/255, 32f/255, 49f/255)); |
| 146 | + } |
| 147 | + if (buttonStyle2 == null) |
| 148 | + { |
| 149 | + buttonStyle2 = CreateButtonStyle(new Color(36f/255, 54f/255, 71f/255)); |
| 150 | + } |
| 151 | + if (buttonStyle3 == null) |
| 152 | + { |
| 153 | + buttonStyle3 = CreateButtonStyle(new Color(55f/255, 79f/255, 100f/255)); |
| 154 | + } |
| 155 | + if (buttonStyle4 == null) |
| 156 | + { |
| 157 | + buttonStyle4 = CreateButtonStyle(new Color(93f/255, 136f/255, 165f/255)); |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | + private void AddOpenAIPrefab() |
| 162 | + { |
| 163 | + if (string.IsNullOrEmpty(openAIKey.stringValue)) |
| 164 | + { |
| 165 | + Debug.LogError("Please enter your OpenAI API key."); |
| 166 | + return; |
| 167 | + } |
| 168 | + GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Prefabs/Core/OpenAI.prefab"); |
| 169 | + if (prefab) |
| 170 | + { |
| 171 | + GameObject openAI = (GameObject)PrefabUtility.InstantiatePrefab(prefab, EditorSceneManager.GetActiveScene()); |
| 172 | + OpenAIWrapper openAIWrapper = openAI.GetComponent<OpenAIWrapper>(); |
| 173 | + if (openAIWrapper) |
| 174 | + { |
| 175 | + openAIWrapper.SetAPIKey(openAIKey.stringValue); |
| 176 | + EditorUtility.SetDirty(openAIWrapper); |
| 177 | + } |
| 178 | + } |
| 179 | + else Debug.LogError("Couldn't find OpenAI Prefab at the specified path."); |
| 180 | + } |
| 181 | + |
| 182 | + private void AddTextToSpeechPrefab() |
| 183 | + { |
| 184 | + GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Prefabs/Core/TTSManager.prefab"); |
| 185 | + if (prefab) PrefabUtility.InstantiatePrefab(prefab, EditorSceneManager.GetActiveScene()); |
| 186 | + else Debug.LogError("Couldn't find Text-To-Speech Prefab at the specified path."); |
| 187 | + } |
| 188 | + |
| 189 | + private void SayHelloWorld() |
| 190 | + { |
| 191 | + TTSManager ttsManager = GameObject.FindObjectOfType<TTSManager>(); |
| 192 | + if (ttsManager != null) |
| 193 | + { |
| 194 | + // note: editor doesn't await the async op |
| 195 | + ttsManager.SynthesizeAndPlay("Hello World"); |
| 196 | + } |
| 197 | + } |
| 198 | + |
| 199 | + private void SynthesizeCustomText() |
| 200 | + { |
| 201 | + TTSManager ttsManager = GameObject.FindObjectOfType<TTSManager>(); |
| 202 | + if (ttsManager != null && customText != null) ttsManager.SynthesizeAndPlay(customText.stringValue); |
| 203 | + } |
| 204 | +} |
0 commit comments