Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How to hide/show the underline of link text on mouse hover

Discussion in 'UGUI & TextMesh Pro' started by AnomalusUndrdog, Feb 21, 2021.

  1. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,541
    I want my link text to show their underline only when the mouse is hovering over them. Based on the code I found in another thread, and the example code for reacting to mouse hover (TMP_TextSelector_B.cs) I have made my own code.

    My problem is that the underline doesn't match the look of the text. If the text has outline and "drop shadow" effects, those do not automatically apply on the underline I make since I'm only making them with simple mesh generation code.

    I notice that in TextMeshPro's TMP_Text.cs it has a DrawUnderlineMesh method. Is there somehow a way to get the vertex indices of those underline meshes? Hiding and showing would (hopefully) be a simple matter of setting their vertex color alpha to 0.

    So instead of making my own underline meshes I could just use the existing underline mesh generated by TMP. The only thing I like about the custom generated underline mesh that I have right now is that it will be easy to make underlines that have a dotted line pattern.

    I am on Unity 2018.4 and using TextMesh Pro 1.4.1 if that matters.

     
  2. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    6,588
    The underline geometry is after the last character and always 12 vertices per segment. The underline segment uses the glyph of the underline character of the primary font asset. The first 4 vertices of the segment are the front end of the underling glyph, then 4 for the middle and last 4 for the end part.

    Although, there is no cross reference in the characterInfo to the vertex index of the underline for each character, you should be able to use a similar logic to what you have right now which should be something like: Find first character that is underlined and last visible character of that line. This segment will be using the first 12 vertices after the last character vertex index and so on for the other segments.

    Note that strikethrough would be weaved in there so that might complicate things
     
    AnomalusUndrdog likes this.
  3. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,541
    Could you clarify what "segment" means? I tried getting the last character index of a link's text, multiply that by 4 since they're quads, then setting the alpha value of the next 12 colors from that, but I end up changing the wrong thing.

    I am also wondering about the output of my debug log. characterInfo Length is 128, but the colors Length when divided by 4 (because they're quads I assume) is only 121 (value changes depending on how much word-wrapped the text is).

    Code (CSharp):
    1.  
    2. void ShowUnderline(bool show, int linkIndex)
    3. {
    4.   var textInfo = m_TextComponent.textInfo;
    5.   var linkInfo = textInfo.linkInfo[linkIndex];
    6.   var lastCharIndex = linkInfo.linkTextfirstCharacterIndex + linkInfo.linkTextLength - 1;
    7.  
    8.   int materialIndex = textInfo.characterInfo[lastCharIndex].materialReferenceIndex;
    9.   var colors = textInfo.meshInfo[materialIndex].colors32;
    10.  
    11.   Debug.Log($"link text: \"{linkInfo.GetLinkText()}\" last char: {textInfo.characterInfo[lastCharIndex].character} (index: {lastCharIndex} of {textInfo.characterInfo.Length}) colors length: {colors.Length} per 4: {colors.Length/4}");
    12.  
    13.   // each underline is 12 vertices, and starts after the last character
    14.   int indexX4 = (lastCharIndex+1) * 4;
    15.   var alphaValue = show ? byte.MaxValue : byte.MinValue;
    16.   colors[indexX4 + 0].a = alphaValue;
    17.   colors[indexX4 + 1].a = alphaValue;
    18.   colors[indexX4 + 2].a = alphaValue;
    19.   colors[indexX4 + 3].a = alphaValue;
    20.  
    21.   colors[indexX4 + 4].a = alphaValue;
    22.   colors[indexX4 + 5].a = alphaValue;
    23.   colors[indexX4 + 6].a = alphaValue;
    24.   colors[indexX4 + 7].a = alphaValue;
    25.  
    26.   colors[indexX4 + 8].a = alphaValue;
    27.   colors[indexX4 + 9].a = alphaValue;
    28.   colors[indexX4 + 10].a = alphaValue;
    29.   colors[indexX4 + 11].a = alphaValue;
    30.  
    31.   m_TextComponent.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32);
    32. }
    33.  
     
  4. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    6,588
    Since internal arrays are allocated in blocks, you have to query the textInfo to get the character count for instance. You cannot rely on the length of the characterInfo for instance.

    The underline geometry is at the end after the geometry of ALL characters. So you have to check the vertex index of the last visible character. Then any geometry related to underline should follow and since each underline segment is made up of 12 vertices, you need to keep track of each of those segment.

    For instance, in your example the first segment would be for "example script". So the first 12 vertices after the last visible character index would belong to that segment. Then "to" would be the next 12 and then "words" the next.
     
  5. AnomalusUndrdog

    AnomalusUndrdog

    Joined:
    Jul 3, 2009
    Posts:
    1,541
    I kind of understand the theory behind what you said, but I know so little about TMP_TextInfo, and TMP_CharacterInfo and the other Info structs, I have no idea where to begin. I've only been looking through the TMP source code and guessing which field I need to use. I'm gonna have to put this on hold and return to it when I have time.
     
  6. Stephan_B

    Stephan_B

    Unity Technologies

    Joined:
    Feb 26, 2017
    Posts:
    6,588
    Add the TMP_TextInfoDebugTool.cs script to a TMP object. This script is located in the TMP Examples & Extras.

    I created this script for my own needs initially to help visualize the content of the textInfo. This script should serve as a good example of how to access the various information contained in the textInfo.