-
-
Save JimmyCushnie/fdbae61f28bed0d92c1f2dc239619e70 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using UnityEngine; | |
using UnityEngine.EventSystems; | |
using JimmysUnityUtilities; | |
using FancyInput; | |
using TMPro; | |
namespace LogicUI.TextMeshProUtilities | |
{ | |
/// <summary> | |
/// Allows links in TextMeshPro text objects to be clicked on, and gives them custom colors when they are hovered or clicked. | |
/// </summary> | |
[RequireComponent(typeof(TMP_Text))] | |
public class TextLinkHelper : MonoBehaviour, IPointerClickHandler, IPointerDownHandler, IPointerUpHandler, IPointerEnterHandler, IPointerExitHandler | |
{ | |
private TMP_Text _Text; | |
public TMP_Text Text | |
{ | |
get | |
{ | |
if (_Text == null) | |
_Text = GetComponent<TMP_Text>(); | |
return _Text; | |
} | |
} | |
private void OnValidate() | |
{ | |
SetAllLinksToNormalColor(); | |
} | |
void Start() | |
{ | |
// I've no idea why the frame delay is necessary, but it is. | |
CoroutineUtility.RunAfterOneFrame(SetAllLinksToNormalColor); | |
} | |
[ColorUsage(showAlpha: false), SerializeField] | |
Color32 LinkNormalColor = new Color32(0, 0, 255, 255); | |
[ColorUsage(showAlpha: false), SerializeField] | |
Color32 LinkHoveredColor = new Color32(50, 50, 255, 255); | |
[ColorUsage(showAlpha: false), SerializeField] | |
Color32 LinkClickColor = new Color32(80, 80, 255, 255); | |
public void SetColors(Color32 linkNormalColor, Color32 linkHoveredColor, Color32 linkClickColor) | |
{ | |
LinkNormalColor = linkNormalColor; | |
LinkHoveredColor = linkHoveredColor; | |
LinkClickColor = linkClickColor; | |
SetAllLinksToNormalColor(); | |
} | |
private Dictionary<string, Action> CustomLinks = new Dictionary<string, Action>(); | |
/// <summary> | |
/// Sets some code to be run when a link is clicked on. | |
/// If a link doesn't have a custom action set, we will use <see cref="Application.OpenURL(string)"/> on it. | |
/// </summary> | |
/// <param name="linkID"></param> | |
/// <param name="linkAction"></param> | |
public void SetCustomLink(string linkID, Action linkAction) | |
{ | |
CustomLinks[linkID] = linkAction; | |
} | |
void IPointerClickHandler.OnPointerClick(PointerEventData eventData) | |
{ | |
int linkIndex = TMP_TextUtilities.FindIntersectingLink(Text, eventData.pressPosition, eventData.pressEventCamera); | |
if (linkIndex > -1) | |
{ | |
var link = Text.textInfo.linkInfo[linkIndex]; | |
ClickOnLink(link.GetLinkID()); | |
} | |
void ClickOnLink(string linkID) | |
{ | |
if (CustomLinks.TryGetValue(linkID, out var action)) | |
action?.Invoke(); | |
else | |
Application.OpenURL(linkID); | |
Debug.Log($"clicked on link: {linkID}"); | |
} | |
} | |
void IPointerDownHandler.OnPointerDown(PointerEventData eventData) | |
{ | |
PointerIsDown = true; | |
SetLinkToColor(PreviouslyHoveredLink, LinkClickColor); | |
} | |
void IPointerUpHandler.OnPointerUp(PointerEventData eventData) | |
{ | |
PointerIsDown = false; | |
SetLinkToColor(PreviouslyHoveredLink, LinkNormalColor); | |
} | |
void IPointerEnterHandler.OnPointerEnter(PointerEventData eventData) | |
{ | |
CurrentlyHoveredOver = true; | |
PointerIsDown = false; | |
cachedCamera = eventData.enterEventCamera; | |
} | |
void IPointerExitHandler.OnPointerExit(PointerEventData eventData) | |
{ | |
CurrentlyHoveredOver = false; | |
} | |
Camera cachedCamera; | |
bool CurrentlyHoveredOver; | |
bool PointerIsDown; | |
TMP_LinkInfo? PreviouslyHoveredLink = null; | |
void Update() | |
{ | |
if (!CurrentlyHoveredOver) | |
return; | |
if (PointerIsDown) | |
return; | |
SetLinkToColor(PreviouslyHoveredLink, LinkNormalColor); | |
int linkIndex = TMP_TextUtilities.FindIntersectingLink(Text, GameInput.MousePosition, cachedCamera); | |
if (linkIndex > -1) | |
{ | |
var link = Text.textInfo.linkInfo[linkIndex]; | |
SetLinkToColor(link, LinkHoveredColor); | |
PreviouslyHoveredLink = link; | |
} | |
else | |
{ | |
PreviouslyHoveredLink = null; | |
} | |
} | |
public void SetAllLinksToNormalColor() | |
{ | |
if (Text.textInfo == null) // Text object isn't initialized yet; required as of TMP 2.1 | |
return; | |
foreach (var link in Text.textInfo.linkInfo.OrEmptyIfNull()) | |
SetLinkToColor(link, LinkNormalColor); | |
} | |
private void SetLinkToColor(TMP_LinkInfo? linkInfo, Color32 color) | |
{ | |
if (linkInfo == null) | |
return; | |
var link = linkInfo.Value; | |
if (link.linkTextfirstCharacterIndex + link.linkTextLength - 1 >= Text.textInfo.characterInfo.Length) | |
return; | |
for (int i = 0; i < link.linkTextLength; i++) | |
{ | |
int characterIndex = link.linkTextfirstCharacterIndex + i; | |
var charInfo = Text.textInfo.characterInfo[characterIndex]; | |
int meshIndex = charInfo.materialReferenceIndex; | |
int vertexIndex = charInfo.vertexIndex; | |
var characterVertexColors = Text.textInfo.meshInfo[meshIndex].colors32; | |
if (charInfo.isVisible) | |
{ | |
characterVertexColors[vertexIndex + 0] = color; | |
characterVertexColors[vertexIndex + 1] = color; | |
characterVertexColors[vertexIndex + 2] = color; | |
characterVertexColors[vertexIndex + 3] = color; | |
} | |
} | |
Text.UpdateVertexData(TMP_VertexDataUpdateFlags.All); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment