public override void OnActivate(string searchContext, VisualElement rootElement) { // Initialize project settings variables _projectSettings = new SerializedObject(ScriptableObject.CreateInstance <ProjectSettings>()); var textLanguages = _projectSettings.FindProperty("_textProjectLanguages"); var audioLanguages = _projectSettings.FindProperty("_audioProjectLanguages"); // Initialize user settings variables (preference variables) _preferences = new SerializedObject(ScriptableObject.CreateInstance <Preferences>()); _textLanguages = ProjectSettings.TextProjectLanguages; _audioLanguage = ProjectSettings.AudioProjectLanguages; _textLanguageLastFrame = Preferences.TextLanguage; _audioLanguageLastFrame = Preferences.AudioLanguage; // Initialize visual representation of the language lists _textLanguagesReorderableList = new ReorderableList(_projectSettings, textLanguages, true, true, false, true); // Add labels to the lists // Show available text languages to the left and available audio languages to the right _textLanguagesReorderableList.drawHeaderCallback = (Rect rect) => { EditorGUI.LabelField(new Rect(rect.x, rect.y, rect.width * 0.65f, EditorGUIUtility.singleLineHeight), "Languages"); EditorGUI.LabelField(new Rect(rect.width * 0.65f, rect.y, rect.width * 0.75f, EditorGUIUtility.singleLineHeight), "Has Audio"); }; // How an element of the lists should be drawn // Text languages will be drawn left as a label with their display name (-> "English") // Audio languages will be drawn right as a bool/toggle field indicating their use (-> true/false) // This communicates visually that for adding a voice over language a coresponding text language must exist already _textLanguagesReorderableList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => { var languageId = _textLanguagesReorderableList.serializedProperty.GetArrayElementAtIndex(index); var displayName = Cultures.GetCultures().FirstOrDefault(c => c.Name == languageId.stringValue).DisplayName ?? "<no display name>"; rect.y += 2; EditorGUI.LabelField(new Rect(rect.x, rect.y, rect.width * 0.7f, EditorGUIUtility.singleLineHeight), displayName); var textLanguageOnAudio = ProjectSettings.AudioProjectLanguages.Contains(languageId.stringValue); var audioBool = EditorGUI.Toggle(new Rect(rect.width * 0.7f, rect.y, rect.width * 0.3f, EditorGUIUtility.singleLineHeight), textLanguageOnAudio); if (audioBool != textLanguageOnAudio) { if (audioBool) { audioLanguages.InsertArrayElementAtIndex(audioLanguages.arraySize); audioLanguages.GetArrayElementAtIndex(audioLanguages.arraySize - 1).stringValue = languageId.stringValue; } else { var audiolanguageIndex = ProjectSettings.AudioProjectLanguages.IndexOf(languageId.stringValue); audioLanguages.DeleteArrayElementAtIndex(audiolanguageIndex); } } }; }
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { // If this property is not a string, fall back to default implementation. if (property.propertyType != SerializedPropertyType.String) { EditorGUI.PropertyField(position, property, label); return; } // Display this property as a dropdown that lets you select a language. var allCultures = Cultures.GetCultures().ToList(); var indices = Enumerable.Range(0, allCultures.Count()); var culturesToIndicies = allCultures.Zip(indices, (culture, index) => new { culture, index }).ToDictionary(pair => pair.culture.Name, pair => pair.index); var value = property.stringValue; int currentCultureIndex; if (culturesToIndicies.ContainsKey(value)) { // The property doesn't contain a valid culture name. // Default it to the current locale, and also update the property so that it // value = System.Globalization.CultureInfo.CurrentCulture.Name; // property.stringValue = value; currentCultureIndex = culturesToIndicies[value]; } else { currentCultureIndex = -1; } var allCultureDisplayNames = allCultures.Select(c => c.DisplayName).Select(n => new GUIContent(n)).ToArray(); using (var changeCheck = new EditorGUI.ChangeCheckScope()) { var selectedIndex = EditorGUI.Popup(position, label, currentCultureIndex, allCultureDisplayNames); if (changeCheck.changed) { property.stringValue = allCultures[selectedIndex].Name; } } }
/// <summary> /// Draws a language selection popup used for showing a user's language preference. /// Returns the corresponding SerializedProperty of the drawn language selection popup which be used after ApplyModifiedProperties() to detect changes to the settings. /// </summary> /// <param name="languagePreference">Determines wheter to draw the Text Language preference or the Audio Language preference.</param> private SerializedProperty DrawLanguagePreference(LanguagePreference languagePreference) { // Declare and set variables depending on the type of language preference to draw List <string> languages = default; SerializedProperty preferencesProperty = default; string defaultProjectLanguage = default; string infoMessageOnEmptyProjectLanguageList = default; string languagePopupLabel = default; switch (languagePreference) { case LanguagePreference.TextLanguage: languages = _textLanguages; preferencesProperty = _preferences.FindProperty("_textLanguage"); defaultProjectLanguage = ProjectSettings.TextProjectLanguageDefault; infoMessageOnEmptyProjectLanguageList = _emptyTextLanguageMessage; languagePopupLabel = "Text Language"; _textLanguageLastFrame = preferencesProperty.stringValue; break; case LanguagePreference.AudioLanguage: languages = _audioLanguage; preferencesProperty = _preferences.FindProperty("_audioLanguage"); defaultProjectLanguage = ProjectSettings.AudioProjectLanguageDefault; infoMessageOnEmptyProjectLanguageList = _emptyAudioLanguageMessage; languagePopupLabel = "Audio Language"; _audioLanguageLastFrame = preferencesProperty.stringValue; break; } // Get currently available languages and determine which the selected language should be int selectedLanguageIndex = -1; string[] languagesNamesAvailableForSelection = languages.Count > 0 ? languages.ToArray() : System.Array.Empty <string>(); var selectedLanguage = languagesNamesAvailableForSelection .Select((name, index) => new { name, index }) .FirstOrDefault(element => element.name == preferencesProperty.stringValue); if (selectedLanguage != null) { selectedLanguageIndex = selectedLanguage.index; } else if (!string.IsNullOrEmpty(defaultProjectLanguage)) { // Assign default language in case the currently selected language has become invalid selectedLanguageIndex = 0; } string[] languagesDisplayNamesAvailableForSelection = languagesNamesAvailableForSelection.Select(name => Cultures.GetCultures().FirstOrDefault(c => c.Name == name).DisplayName).ToArray(); // Disable popup and show message box in case the project languages have been defined yet if (languagesNamesAvailableForSelection.Length == 0) { GUI.enabled = false; EditorGUILayout.HelpBox(infoMessageOnEmptyProjectLanguageList, MessageType.Info); } // Draw the actual language popup selectedLanguageIndex = EditorGUILayout.Popup(languagePopupLabel, selectedLanguageIndex, languagesDisplayNamesAvailableForSelection); // Change/set the language ID if (selectedLanguageIndex != -1) { preferencesProperty.stringValue = languagesNamesAvailableForSelection[selectedLanguageIndex]; } else { // null the language ID since the index is invalid preferencesProperty.stringValue = string.Empty; } GUI.enabled = true; return(preferencesProperty); }
public override void OnGUI(string searchContext) { if (_projectSettings == null || _projectSettings.targetObject == null) { return; } _projectSettings.Update(); GUILayout.Label("Project Languages", EditorStyles.boldLabel); // Text languages var textLanguagesProp = _projectSettings.FindProperty("_textProjectLanguages"); var textLanguages = ProjectSettings.TextProjectLanguages; var remainingTextLanguages = Cultures.GetCultures().Where(c => textLanguages.Contains(c.NativeName) == false).ToArray(); var remainingTextLanguagesDisplayNames = remainingTextLanguages.Select(c => c.DisplayName).ToArray(); // Button and Dropdown List for adding a language GUILayout.BeginHorizontal(); if (remainingTextLanguages.Length < 1) { GUI.enabled = false; GUILayout.Button("No more available Project Languages"); GUI.enabled = true; } else { if (GUILayout.Button("Add language to project")) { textLanguagesProp.InsertArrayElementAtIndex(textLanguagesProp.arraySize); textLanguagesProp.GetArrayElementAtIndex(textLanguagesProp.arraySize - 1).stringValue = remainingTextLanguages[_textLanguagesListIndex].Name; _textLanguagesListIndex = 0; } } _textLanguagesListIndex = EditorGUILayout.Popup(_textLanguagesListIndex, remainingTextLanguagesDisplayNames); GUILayout.EndHorizontal(); // Text Language List _textLanguagesReorderableList.DoLayoutList(); // Audio languages (sub-selection from available text languages) var audioLanguagesProp = _projectSettings.FindProperty("_audioProjectLanguages"); var audioLanguages = ProjectSettings.AudioProjectLanguages; // Cleanup Audio Language List from languages that have been removed from the Project Languages for (int i = audioLanguages.Count - 1; i >= 0; i--) { string language = (string)audioLanguages[i]; if (!textLanguages.Contains(language)) { audioLanguagesProp.DeleteArrayElementAtIndex(i); } } _projectSettings.ApplyModifiedProperties(); // User's language preferences if (_preferences == null || _preferences.targetObject == null) { return; } GUILayout.Label("Language Preferences", EditorStyles.boldLabel); _preferences.Update(); // Text language popup related things SerializedProperty textLanguageProp = DrawLanguagePreference(LanguagePreference.TextLanguage); // Audio language popup related things SerializedProperty audioLanguageProp = DrawLanguagePreference(LanguagePreference.AudioLanguage); #if ADDRESSABLES GUILayout.Label("Voice Over Asset Handling", EditorStyles.boldLabel); var addressableVoiceOverAudioClipsProp = _projectSettings.FindProperty("_addressableVoiceOverAudioClips"); EditorGUILayout.PropertyField(addressableVoiceOverAudioClipsProp, new GUIContent("Use Addressables")); string message = $"This project has the Addressable Assets package installed. When this option is selected, {ObjectNames.NicifyVariableName(nameof(LocalizationDatabase)).ToLowerInvariant()}s will use addressable asset references to refer to assets that belong to lines, rather than directly referencing the asset. This allows for better performance during steps that have a large amount of dependencies.\n\nFor more information, click this box to open the Yarn Spinner documentation."; EditorGUILayout.HelpBox(message, MessageType.Info); // Make the HelpBox that we just rendered have a link cursor var lastRect = GUILayoutUtility.GetLastRect(); EditorGUIUtility.AddCursorRect(lastRect, MouseCursor.Link); // And also detect clicks on it; open the documentation when // this happens if (Event.current.type == EventType.MouseUp && lastRect.Contains(Event.current.mousePosition)) { Application.OpenURL(AddressableAssetsDocumentationURL); } _projectSettings.ApplyModifiedProperties(); #endif _preferences.ApplyModifiedProperties(); // Trigger events in case the preferences have been changed if (_textLanguageLastFrame != textLanguageProp.stringValue) { Preferences.LanguagePreferencesChanged?.Invoke(this, System.EventArgs.Empty); } if (_audioLanguageLastFrame != audioLanguageProp.stringValue) { Preferences.LanguagePreferencesChanged?.Invoke(this, System.EventArgs.Empty); } }