2026-05-06 15:07:56 +02:00

421 lines
14 KiB
C#

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<int, string> { }
[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<TabInfo> m_Tabs = new List<TabInfo>();
[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")]
/// <summary>
/// Fired when the clients sends a chat message.
/// First paramenter - int tabId.
/// Second parameter - string messageText.
/// </summary>
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);
}
}
}
}
/// <summary>
/// Fired when the submit button is clicked.
/// </summary>
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);
}
}
}
/// <summary>
/// Fired when the scroll up button is pressed.
/// </summary>
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);
}
/// <summary>
/// Fired when the scroll down button is pressed.
/// </summary>
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);
}
/// <summary>
/// Fired when the scroll to top button is pressed.
/// </summary>
public void OnScrollToTopClick()
{
if (this.m_ActiveTabInfo == null || this.m_ActiveTabInfo.scrollRect == null)
return;
// Scroll to top
this.m_ActiveTabInfo.scrollRect.verticalNormalizedPosition = 1f;
}
/// <summary>
/// Fired when the scroll to bottom button is pressed.
/// </summary>
public void OnScrollToBottomClick()
{
if (this.m_ActiveTabInfo == null || this.m_ActiveTabInfo.scrollRect == null)
return;
// Scroll to bottom
this.m_ActiveTabInfo.scrollRect.verticalNormalizedPosition = 0f;
}
/// <summary>
/// Fired when the input field is submitted.
/// </summary>
/// <param name="text"></param>
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);
}
}
}
/// <summary>
/// Fired when a tab button is toggled.
/// </summary>
/// <param name="state"></param>
public void OnTabStateChange(bool state)
{
// If a tab was activated
if (state)
{
// Find the active tab
this.m_ActiveTabInfo = this.FindActiveTab();
}
}
/// <summary>
/// Finds the active tab based on the tab buttons toggle state.
/// </summary>
/// <returns>The active tab info.</returns>
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;
}
/// <summary>
/// Gets the tab info for the specified tab by id.
/// </summary>
/// <param name="tabId">Tab id.</param>
/// <returns></returns>
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;
}
/// <summary>
/// Sends a chat message.
/// </summary>
/// <param name="text">The message.</param>
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 = "";
}
}
/// <summary>
/// Adds a chat message to the specified tab.
/// </summary>
/// <param name="tabId">The tab id.</param>
/// <param name="text">The message.</param>
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<Text>();
// 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>();
shadow.effectColor = this.m_TextEffectColor;
shadow.effectDistance = this.m_TextEffectDistance;
break;
case TextEffect.Outline:
Outline outline = obj.AddComponent<Outline>();
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();
}
}
}