Search Unity

  1. Unity 2020.1 has been released.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

TextMesh Pro Use of links with TMP for UGUI

Discussion in 'UGUI & TextMesh Pro' started by Cleverlie, May 31, 2019.

  1. Cleverlie


    Dec 23, 2013
    Hi all, I'm struggling with the usage of the links feature of TMP, in the examples found in youtube or googling, everyone seems to be doing the same thing, what I want to do is this:

    once the cursor is hovering a link, I want to change the style of the text inside the link, and once the cursor leaves the link it returns to it's original style, what I mean with this?

    for example:

    OnHoverEnter => adds "<u><b><color=blue>" before the link text and adds "</u></b></color>" to the end.

    OnHoverExit removes the tags.

    I don't need help with the details on how to implement Hover events etc, I got that, the problem is that things such as

    Code (CSharp):
    1. Debug.Log(text.textInfo.linkInfo[0].linkTextfirstCharacterIndex);
    3. Debug.Log(text.textInfo.linkInfo[0].linkTextLength);
    are returning indices not taking in account the invisible characters, so I can't do something like this:

    Code (CSharp):
    1. void SetLinkHovering(bool on)
    2.     {
    3.         var info = text.textInfo.linkInfo[linkIdx];
    5.         if (on)
    6.         {
    7.             text.text = text.text.Insert(info.linkTextfirstCharacterIndex + info.linkTextLength, hoverTagsEnd);
    8.             text.text = text.text.Insert(info.linkTextfirstCharacterIndex, hoverTagsStart);
    10.         }
    11.         else
    12.         {
    13.             text.text.Remove(info.linkTextfirstCharacterIndex + info.linkTextLength - hoverTagsEnd.Length, hoverTagsEnd.Length);
    14.             text.text.Remove(info.linkTextfirstCharacterIndex, hoverTagsStart.Length);
    15.         }
    16.     }
    Is there any way to get the indices accounting for invisible characters? so I can manipulate the actual raw text?

    thanks in advance.
  2. SosaIsaac


    Oct 5, 2018
    Hi Cleverlie, almost 6 years after your post but I found the problem and it has to do with the index after you add the characters.

    The remove methods should be: Remove(textIndex + hoverTagsEnd.Lenght, hoverTagsEnd.Length)//The close tag.

    And Remove(textIndex - hoverTagsStart.Lenght, hoverTagsStart.Length)// The open tag

    Sorry my TextIndex is equal to the textMeshProUgui.text.IndexOf(LinkInfoText.GetLinkText()); in separated methods off course.

    if you need more help with this please reply me ( sorry for the 6 years late xD)
  3. Cleverlie


    Dec 23, 2013
    Hi! thanks for the answer, btw I posted this today so you actually answered pretty fast haha.

    sadly your answer is not what I need in this context, I could just do a string.IndexOf(TheLinkText) but this is not ideal, I could not have control over the text content, meaning the string could appear multiple times in the text, so IndexOf would only return the first appearance index, which could be or not the link.

    I think what I'm asking for is if there is any such thing like text.textInfo.linkInfo.linkRAWTextCharacterIndex and text.textInfo.linkInfo.linkRAWTextLength
    but I guess there is nothing like that in the TMP api, this might be a feature request.

    besides, I can find many reason this could be necessary in different contexts, not only for links, for example to manipulate the raw text string given information about the index of certain words IN the raw text, not the parsed one.

    BTW the remove methods are ok the way I made them, see if you start with

    "and now <link=ID>THIS</link> text will have tags"

    after the Add() methods it will be:

    "and now <link=ID><u><b>THIS</b></u></link> text will have tags"

    then, assuming that the linkInfo returns indices and lenghts of the raw text and not the parsed one, the next time I enter the method to remove the tags, the linkText would be "<u><b>THIS</b></u>" and thus I have to seek to the first character of that link text, then add its lenght, then move back the lenght of the endTags, and then delete endTags.Lenght characters (yeah I know is a bit confusing but it works, or at least it would if linkInfo behave as I expected)

    So this would be fine:
    Remove(textIndex + TextLength - endTagsLength, endTagsLength)

    thanks for the help anyway, I'll see if Stephan comes here and has an elegant solution to this, or maybe adds the feature to the next update :D
  4. Cleverlie


    Dec 23, 2013
    I got it!

    textInfo.CharacterInfo is an array with info about the characters of the parsed text, and it includes the index of each of those characters IN the RAW unparsed text, meaning I can go back and forth like:


    I'll try this and keep this thread updated.
  5. Cleverlie


    Dec 23, 2013
    ok, this code will do exactly what I wanted, there are still some corner cases which are very unlikely but that could break the functionality, but for the most part it will work fine.

    Code (CSharp):
    1. void SetLinkHovering(bool on)
    2.     {
    3.         var info = text.textInfo.linkInfo[linkIdx];
    6.         // convert from parsed text indices to raw text indices
    7.         int startIdx = text.textInfo.characterInfo[info.linkTextfirstCharacterIndex].index;
    8.         // here we have to do a trick, "info.linkTextfirstCharacterIndex + info.linkTextLength" will give us the index of the first
    9.         // visible character AFTER the link text, in the parsed text. then we convert it to raw text index, and then we add +1 to have
    10.         // the index after all the link text ended.
    11.         int endIdx = text.textInfo.characterInfo[info.linkTextfirstCharacterIndex + info.linkTextLength - 1].index + 1;
    14.         if (on)
    15.         {
    16.             text.text = text.text.Insert(endIdx, hoverTagsEnd);
    17.             text.text = text.text.Insert(startIdx, hoverTagsStart);
    19.         }
    20.         else
    21.         {
    22.             // endIdx in this case tells us where the parsed text ends, since the tags we added do not add characters to the parsed text
    23.             // then endIdx is the startIdx of the endTags we added previously.
    25.             text.text = text.text.Remove(endIdx, hoverTagsEnd.Length);
    27.             // startIdx tells us where the visible parsed text starts, we previously added tags before it, now we need to remove them.
    28.             text.text = text.text.Remove(startIdx - hoverTagsStart.Length, hoverTagsStart.Length);
    29.         }
    30.     }

    I also found this solution which is more elegant and I think it doesn't have any corner cases of failure, for anyone wanting to decorate their links in TMP, here it goes:

    Code (CSharp):
    1. void SetLinkHovering(bool on)
    2.     {
    3.         var info = text.textInfo.linkInfo[linkIdx];
    5.         int startIndex = text.text.IndexOf('>', info.linkIdFirstCharacterIndex + info.linkIdLength) + 1;
    6.         int endIndex = text.text.IndexOf("</link>", info.linkIdFirstCharacterIndex + info.linkIdLength + 1);
    8.         if (on)
    9.         {
    10.             text.text = text.text.Insert(endIndex, hoverTagsEnd);
    11.             text.text = text.text.Insert(startIndex, hoverTagsStart);
    13.         }
    14.         else
    15.         {
    16.             text.text = text.text.Remove(endIndex - hoverTagsEnd.Length, hoverTagsEnd.Length);
    18.             // startIdx tells us where the visible parsed text starts, we previously added tags before it, now we need to remove them.
    19.             text.text = text.text.Remove(startIndex, hoverTagsStart.Length);
    20.         }
    21.     }
    Last edited: May 31, 2019