Author Topic: UILabel.GetUrlAtPosition() not working when text is justified  (Read 5458 times)

samdemers

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 2
    • View Profile
When a UILabel contains a link such as Click Me and the label's Alignment is set to Justified, GetUrlAtPosition() returns null unless the click was at the very beginning of the text line containing the link and the link happened to be at the beginning of the line.

The root of the problem is in the NGUIText.PrintExactCharacterPositions() method used internally by GetUrlAtPosition(). That method recalculates the position of every glyph in the text and then calls NGUIText.Align() to apply the selected alignment (Right, Center or Justified). When the alignment is Justified, NGUIText.Align() expects its first argument, the verts array, to contain 4 elements per index: one for each corner. However, when NGUIText.PrintExactCharacterPositions() calls it, the array has 2 elements per index: bottom left and top right, causing the array to be incorrectly updated and calls to NGUIText.GetExactCharacterIndex(), which depends on the array, to fail.

Note: this is with NGUI 3.7.7. See the attached patch for a partial solution.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UILabel.GetUrlAtPosition() not working when text is justified
« Reply #1 on: May 05, 2015, 10:43:48 PM »
That function currently has a special section for justified text. I'm not sure if it was added before or after 377.

samdemers

  • Newbie
  • *
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 2
    • View Profile
Re: UILabel.GetUrlAtPosition() not working when text is justified
« Reply #2 on: May 06, 2015, 08:30:45 AM »
Yes, the NGUIText.Align() function has a section that deals with justified text, and the issue lies in that section:
  1.         static public void Align (BetterList<Vector3> verts, int indexOffset, float printedWidth)
  2.         {
  3.                 switch (alignment)
  4.                 {
  5.                         /* ... */
  6.  
  7.                         case Alignment.Justified:
  8.                         {
  9.                                 /* ... */
  10.  
  11.                                 for (int i = indexOffset + 4, charIndex = 1; i < verts.size; ++charIndex)
  12.                                 {
  13.                                         float x0 = verts.buffer[i].x;
  14.                                         float x1 = verts.buffer[i + 2].x;
  15.  
  16.                                         /* ... */
  17. #if UNITY_FLASH
  18.                                         verts.buffer[i] = verts.buffer[i] + new Vector3(x0, 0f);
  19.                                         verts.buffer[i+1] = verts.buffer[i+1] + new Vector3(x0, 0f);
  20.                                         verts.buffer[i+2] = verts.buffer[i+2] + new Vector3(x1, 0f);
  21.                                         verts.buffer[i+3] = verts.buffer[i+3] + new Vector3(x1, 0f);
  22.                                         i += 4;
  23. #else
  24.                                         verts.buffer[i++].x = x0;
  25.                                         verts.buffer[i++].x = x0;
  26.                                         verts.buffer[i++].x = x1;
  27.                                         verts.buffer[i++].x = x1;
  28. #endif
  29.                                 }
  30.                                 break;
  31.                         }
  32.                 }
  33.         }
  34.  

Clearly, the verts buffer is assumed to contain 4 elements per index and it is updated 4 elements at a time. That is correct when the method is called from NGUIText.Print(), which adds 4 elements for each glyph:
  1.                                 verts.Add(new Vector3(v0x, v0y));
  2.                                 verts.Add(new Vector3(v0x, v1y));
  3.                                 verts.Add(new Vector3(v1x, v1y));
  4.                                 verts.Add(new Vector3(v1x, v0y));
  5.  

That is why the text is rendered correctly. However, before calling the same method, NGUIText.PrintExactCharacterPositions() adds only 2 elements per glyph into the verts buffer:
  1.                                         verts.Add(new Vector3(x, -y - fullSize));
  2.                                         verts.Add(new Vector3(x + w, -y));
  3.  

Note that although I didn't test it, NGUIText.PrintApproximateCharacterPositions() seems to have a similar problem.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UILabel.GetUrlAtPosition() not working when text is justified
« Reply #3 on: May 07, 2015, 06:39:44 PM »
I'll have a look, thanks.