using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using UnityEngine.Events; using UnityEngine.EventSystems; namespace DuloGames.UI { public class Demo_Chat : MonoBehaviour { [System.Serializable] public enum TextEffect { None, Shadow, Outline } [System.Serializable] public class SendMessageEvent : UnityEvent { } [System.Serializable] public class TabInfo { public int id = 0; public UITab button; public Transform content; public ScrollRect scrollRect; } [SerializeField] private InputField m_InputField; [Header("Buttons")] [SerializeField] private Button m_Submit; [SerializeField] private Button m_ScrollTopButton; [SerializeField] private Button m_ScrollBottomButton; [SerializeField] private Button m_ScrollUpButton; [SerializeField] private Button m_ScrollDownButton; [Header("Tab Properties")] [SerializeField] private List m_Tabs = new List(); [Header("Text Properties")] [SerializeField] private Font m_TextFont = FontData.defaultFontData.font; [SerializeField] private int m_TextFontSize = FontData.defaultFontData.fontSize; [SerializeField] private float m_TextLineSpacing = FontData.defaultFontData.lineSpacing; [SerializeField] private Color m_TextColor = Color.white; [SerializeField] private TextEffect m_TextEffect = TextEffect.None; [SerializeField] private Color m_TextEffectColor = Color.black; [SerializeField] private Vector2 m_TextEffectDistance = new Vector2(1f, -1f); [Header("Events")] /// /// Fired when the clients sends a chat message. /// First paramenter - int tabId. /// Second parameter - string messageText. /// public SendMessageEvent onSendMessage = new SendMessageEvent(); private TabInfo m_ActiveTabInfo; protected void Awake() { // Find the active tab info this.m_ActiveTabInfo = this.FindActiveTab(); // Clear the lines of text if (this.m_Tabs != null && this.m_Tabs.Count > 0) { foreach (TabInfo info in this.m_Tabs) { // if we have a button if (info.content != null) { foreach (Transform t in info.content) { Destroy(t.gameObject); } } } } } protected void OnEnable() { // Hook the submit button click event if (this.m_Submit != null) { this.m_Submit.onClick.AddListener(OnSubmitClick); } // Hook the scroll up button click event if (this.m_ScrollUpButton != null) { this.m_ScrollUpButton.onClick.AddListener(OnScrollUpClick); } // Hook the scroll down button click event if (this.m_ScrollDownButton != null) { this.m_ScrollDownButton.onClick.AddListener(OnScrollDownClick); } // Hook the scroll to top button click event if (this.m_ScrollTopButton != null) { this.m_ScrollTopButton.onClick.AddListener(OnScrollToTopClick); } // Hook the scroll to bottom button click event if (this.m_ScrollBottomButton != null) { this.m_ScrollBottomButton.onClick.AddListener(OnScrollToBottomClick); } // Hook the input field end edit event if (this.m_InputField != null) { this.m_InputField.onEndEdit.AddListener(OnInputEndEdit); } // Hook the tab toggle change events if (this.m_Tabs != null && this.m_Tabs.Count > 0) { foreach (TabInfo info in this.m_Tabs) { // if we have a button if (info.button != null) { info.button.onValueChanged.AddListener(OnTabStateChange); } } } } protected void OnDisable() { // Unhook the submit button click event if (this.m_Submit != null) { this.m_Submit.onClick.RemoveListener(OnSubmitClick); } // Unhook the scroll up button click event if (this.m_ScrollUpButton != null) { this.m_ScrollUpButton.onClick.RemoveListener(OnScrollUpClick); } // Unhook the scroll down button click event if (this.m_ScrollDownButton != null) { this.m_ScrollDownButton.onClick.RemoveListener(OnScrollDownClick); } // Unhook the scroll to top button click event if (this.m_ScrollTopButton != null) { this.m_ScrollTopButton.onClick.RemoveListener(OnScrollToTopClick); } // Unhook the scroll to bottom button click event if (this.m_ScrollBottomButton != null) { this.m_ScrollBottomButton.onClick.RemoveListener(OnScrollToBottomClick); } // Unhook the tab toggle change events if (this.m_Tabs != null && this.m_Tabs.Count > 0) { foreach (TabInfo info in this.m_Tabs) { // if we have a button if (info.button != null) { info.button.onValueChanged.RemoveListener(OnTabStateChange); } } } } /// /// Fired when the submit button is clicked. /// public void OnSubmitClick() { // Get the input text if (this.m_InputField != null) { string text = this.m_InputField.text; // Make sure we have input text if (!string.IsNullOrEmpty(text)) { // Send the message this.SendChatMessage(text); } } } /// /// Fired when the scroll up button is pressed. /// public void OnScrollUpClick() { if (this.m_ActiveTabInfo == null || this.m_ActiveTabInfo.scrollRect == null) return; PointerEventData pointerEventData = new PointerEventData(EventSystem.current); pointerEventData.scrollDelta = new Vector2(0f, 1f); this.m_ActiveTabInfo.scrollRect.OnScroll(pointerEventData); } /// /// Fired when the scroll down button is pressed. /// public void OnScrollDownClick() { if (this.m_ActiveTabInfo == null || this.m_ActiveTabInfo.scrollRect == null) return; PointerEventData pointerEventData = new PointerEventData(EventSystem.current); pointerEventData.scrollDelta = new Vector2(0f, -1f); this.m_ActiveTabInfo.scrollRect.OnScroll(pointerEventData); } /// /// Fired when the scroll to top button is pressed. /// public void OnScrollToTopClick() { if (this.m_ActiveTabInfo == null || this.m_ActiveTabInfo.scrollRect == null) return; // Scroll to top this.m_ActiveTabInfo.scrollRect.verticalNormalizedPosition = 1f; } /// /// Fired when the scroll to bottom button is pressed. /// public void OnScrollToBottomClick() { if (this.m_ActiveTabInfo == null || this.m_ActiveTabInfo.scrollRect == null) return; // Scroll to bottom this.m_ActiveTabInfo.scrollRect.verticalNormalizedPosition = 0f; } /// /// Fired when the input field is submitted. /// /// public void OnInputEndEdit(string text) { // Make sure we have input text if (!string.IsNullOrEmpty(text)) { // Make sure the return key is pressed if (Input.GetKey(KeyCode.Return)) { // Send the message this.SendChatMessage(text); } } } /// /// Fired when a tab button is toggled. /// /// public void OnTabStateChange(bool state) { // If a tab was activated if (state) { // Find the active tab this.m_ActiveTabInfo = this.FindActiveTab(); } } /// /// Finds the active tab based on the tab buttons toggle state. /// /// The active tab info. private TabInfo FindActiveTab() { // If we have tabs if (this.m_Tabs != null && this.m_Tabs.Count > 0) { foreach (TabInfo info in this.m_Tabs) { // if we have a button if (info.button != null) { // If this button is active if (info.button.isOn) { return info; } } } } return null; } /// /// Gets the tab info for the specified tab by id. /// /// Tab id. /// public TabInfo GetTabInfo(int tabId) { // If we have tabs if (this.m_Tabs != null && this.m_Tabs.Count > 0) { foreach (TabInfo info in this.m_Tabs) { // If this is the tab we are looking for if (info.id == tabId) { return info; } } } return null; } /// /// Sends a chat message. /// /// The message. private void SendChatMessage(string text) { int tabId = (this.m_ActiveTabInfo != null ? this.m_ActiveTabInfo.id : 0); // Trigger the event if (this.onSendMessage != null) { this.onSendMessage.Invoke(tabId, text); } // Clear the input field if (this.m_InputField != null) { this.m_InputField.text = ""; } } /// /// Adds a chat message to the specified tab. /// /// The tab id. /// The message. public void ReceiveChatMessage(int tabId, string text) { TabInfo tabInfo = this.GetTabInfo(tabId); // Make sure we have tab info if (tabInfo == null || tabInfo.content == null) return; // Create the text line GameObject obj = new GameObject("Text " + tabInfo.content.childCount.ToString(), typeof(RectTransform)); // Prepare the game object obj.layer = this.gameObject.layer; // Get the rect transform RectTransform rectTransform = (obj.transform as RectTransform); // Prepare the rect transform rectTransform.localScale = new Vector3(1f, 1f, 1f); rectTransform.pivot = new Vector2(0f, 1f); rectTransform.anchorMin = new Vector2(0f, 1f); rectTransform.anchorMax = new Vector2(0f, 1f); // Set the parent rectTransform.SetParent(tabInfo.content, false); // Add the text component Text textComp = obj.AddComponent(); // Prepare the text component textComp.font = this.m_TextFont; textComp.fontSize = this.m_TextFontSize; textComp.lineSpacing = this.m_TextLineSpacing; textComp.color = this.m_TextColor; textComp.text = text; // Prepare the text effect if (this.m_TextEffect != TextEffect.None) { switch (this.m_TextEffect) { case TextEffect.Shadow: Shadow shadow = obj.AddComponent(); shadow.effectColor = this.m_TextEffectColor; shadow.effectDistance = this.m_TextEffectDistance; break; case TextEffect.Outline: Outline outline = obj.AddComponent(); outline.effectColor = this.m_TextEffectColor; outline.effectDistance = this.m_TextEffectDistance; break; } } // Rebuild the content layout LayoutRebuilder.ForceRebuildLayoutImmediate(tabInfo.content as RectTransform); // Scroll to bottom this.OnScrollToBottomClick(); } } }