Author Topic: UILabel.linewidth problem  (Read 10847 times)

phildo77

  • Guest
UILabel.linewidth problem
« on: June 28, 2012, 09:43:25 PM »
I may be misunderstanding the UILabel.lineWidth property.  I do the following:

m_NPCTxt.lineWidth = (int)(Camera.mainCamera.pixelWidth * 1/2);

And the label is clearly larger than half the gameview size.  I expected the width to be exactly half of the gameview. 

What I'm trying to do is resize the label so that it is sized relative to the display width.  It looks like lineWidth is the only way to change the width of the label so I'm a bit stuck. 
The UI label is a child of a UIPanel. 
There is no UIRoot. 
The scale of the parent transform and the child are both not one and not equal to eachother.
I am not using orthSize 1.
What am I missing?

Additionally, I see that UIFont.CalculatePrintedSize returns relative coordinates.... what are these coordinates in relation to (mathematically)?

Thank you!

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UILabel.linewidth problem
« Reply #1 on: June 29, 2012, 03:06:59 AM »
Try multiplying by 0.5f instead. 1/2 is an integer operation, and gives you a 0.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UILabel.linewidth problem
« Reply #2 on: June 29, 2012, 03:08:21 AM »
As for the relative coordinates, you can convert them to pixels by simply taking localScale into account.

Vector3.Scale(relativeSize, transform.localScale);

phildo77

  • Guest
Re: UILabel.linewidth problem
« Reply #3 on: June 29, 2012, 03:03:46 PM »
Thanks for the reply.  After updating the 1/2 to 0.5f the lineWidth still does not relate to half my current game view width.  What I am guessing is that the linewidth is in "character pixels" not current "Screen pixels"?

Since I'm scaling everything all the time I am rarely "pixel perfect".  Does linewidth only work with pixel perfect labels? 

I'm also still struggling with NGUIMath.CalculateAbsoluteWidgetBounds on some widgets.  I have some buttons that when I request extents they are twice as large as they should be.

I'm getting the feeling that these functions and coordinates are only valid given certain conditions and that I have missed these rules somewhere (ie scaling of widgets? Camera OrthSize?).  I'm just not able to get the results that I expect and I am struggling to correlate the results with anything concrete while troubleshooting/debugging.

Are there rules that I need to follow such that widgets, sizes, pixels, coordinates and positions work per their descriptions?
What could I possibly be doing incorrectly to cause this?

Thanks again for the support.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UILabel.linewidth problem
« Reply #4 on: June 29, 2012, 03:09:39 PM »
It works in pixels, so if your font size is 20 and you set the line width to be 200, it will be exactly 10 characters long when adding the widest possible character such as "@" (which would be 20x20)

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UILabel.linewidth problem
« Reply #5 on: June 29, 2012, 03:10:44 PM »
Keep the camera's ortho size at 1. I know the system works with the default UI setup you get, or a lot more people would be crying foul. :)

phildo77

  • Guest
Re: UILabel.linewidth problem
« Reply #6 on: June 29, 2012, 03:40:59 PM »
It works in pixels, so if your font size is 20 and you set the line width to be 200, it will be exactly 10 characters long when adding the widest possible character such as "@" (which would be 20x20)
Bingo.  This is where I was misunderstanding the linewidth.  It is indeed in character pixels and not screen pixels.  Thanks for that! 

So if:
 OrthographicSize = 100
and my display rez = 1024x768
(Note: CalculatedPrintedSize is a constant and does not change with orthosize or scale)
and font size in pixels (at orthosize of 1) = CalculatedPrintedSize("@") * label.localScale = 20 (font with all characters identical width)

font size in camera pixels = 20 / orthosize = 0.2;

then:
200 world coordinate units shown in the game view vertically (because OrthoSize 100)
267 world coordinate units shown in the game view horizontally (aspect of 3:4)
1 world coordinate unit vert = 768 pixels / 200 units = 3.84 pixels / unit (approx)
1 world coordinate unit horz = 1024 pixels / 267 units = 3.84 pixels / unit (approx)

Therefore:
1 character, size in world coords = 20 (font size) * 0.5 (scale) / 3.84 pixels = 2.6 units 
I should now have a method to size my labels based on available information.

I will confirm my calculations and methods when I am able...

Unfortunately I added NGUI to my project after a significant amount of work and changing orthosize based on screen aspect/rez is part of that, so OrthoSize = 1 is a last, last resort.
« Last Edit: June 30, 2012, 05:39:49 PM by phildo77 »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UILabel.linewidth problem
« Reply #7 on: June 29, 2012, 03:42:52 PM »
With NGUI's default layout 1 character pixel is 1 screen pixel, which is why I highly advise sticking with it to begin with... but if you can't then yeah, math is the way to go.

phildo77

  • Guest
Re: UILabel.linewidth problem
« Reply #8 on: June 30, 2012, 07:40:38 PM »
With NGUI's default layout 1 character pixel is 1 screen pixel, which is why I highly advise sticking with it to begin with... but if you can't then yeah, math is the way to go.

So this is the closest I've been able to get.  This works...ish.  It is still somewhat off.  My main problem is that I am not sure exactly what CalculatePrintedSize results mean in relation to units in unity and the same with what lineWidth represents.  Maybe this will help someone else?  Maybe someone else can chime in if they get any further than me?  I've spent a lot of time on trying to figure this out with orthosize != 1 and no UIRoot scaling.  It would have saved me a ton of time if I could have set the label size in unity world coordinates instead of pixels.  Is this a fair feature request?   

 
  1. //Pieces to break up space into
  2.         float spaceScale = 25f;
  3.  
  4.         //Get required environment data
  5.         Vector2 viewPixSize = new Vector2(Camera.mainCamera.pixelWidth, Camera.mainCamera.pixelHeight);
  6.         float aspectR = viewPixSize.x / viewPixSize.y;
  7.         Vector3 lblScale = m_NPCTxt.transform.lossyScale;
  8.         float orthSize = Camera.mainCamera.orthographicSize;
  9.  
  10.         //Get NGUI calculatedprintedsize of character
  11.         //It is still unclear to me how this number is calculated and what it is realtive to
  12.         Vector2 charPixSize = m_NPCTxt.font.CalculatePrintedSize("x", false, UIFont.SymbolStyle.Uncolored);
  13.  
  14.         //Get PixelSize relative to the lineWidth of the label?
  15.         Vector2 lwCharPixSize = new Vector2(charPixSize.x * m_NPCTxt.transform.localScale.x, charPixSize.y * m_NPCTxt.transform.localScale.y);
  16.  
  17.         //Get World coordinate size of each character?
  18.         charPixSize.Scale(m_NPCTxt.transform.lossyScale);
  19.        
  20.         //Calculate how many characters fit into allotted space
  21.         int charCount = (int)(xSpace * ((spaceScale - 2) / spaceScale) / charPixSize.x);
  22.  
  23.         //Set all labels to fit that space (num of characters * lineWidth relative pixels per character)
  24.         m_NPCTxt.lineWidth = m_DlgOpt1.lineWidth = m_DlgOpt2.lineWidth = m_DlgOpt3.lineWidth = (int)(charCount * lwCharPixSize.x);
« Last Edit: July 01, 2012, 12:31:30 AM by phildo77 »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UILabel.linewidth problem
« Reply #9 on: June 30, 2012, 09:04:46 PM »
Go to the definition of CalculatePrintedSize:

Quote
/// <summary>
/// Get the printed size of the specified string. The returned value is in local coordinates. Multiply by transform's scale to get pixels.
/// </summary>

So all you need to do is Vector3.Scale that value by the transform's localScale to get pixels, or by lossyScale to get world size.

If you want label size in world coordinates, just create a method that does what I just described above. World coordinates can vary greatly with each resolution/screen size when UIRoot is used, so it makes no sense to use them.

phildo77

  • Guest
Re: UILabel.linewidth problem
« Reply #10 on: July 01, 2012, 12:26:25 AM »
Go to the definition of CalculatePrintedSize:

So all you need to do is Vector3.Scale that value by the transform's localScale to get pixels, or by lossyScale to get world size.

If you want label size in world coordinates, just create a method that does what Maximum width of the label in pixels. just described above. World coordinates can vary greatly with each resolution/screen size when UIRoot is used, so it makes no sense to use them.
Understood.  We are not using UIRoot nor OrhtoSize = 1. Which, I believe, is why I'm struggling here because the documentation assumes that Orthosize = 1 (and other?). I have done the above with limited success but cannot confirm whether the anomolies I see are due to my error or misunderstanding of NGUI function results (I have not delved into NGUI code):
  1. //Get World coordinate size of each character?
  2.         charPixSize.Scale(m_NPCTxt.transform.lossyScale);

It is not clear (to me) from the description of the provided functions in the docs because I am not in pixel perfect situations where OrthSize = 1 and UIRoot is activated:

CalculatePrintedSize: "Get the printed size of the specified string. The returned value is in local coordinates (define coordinates mathematically/relative to). Multiply by transform's scale to get pixels (define pixels mathematically/relative to)."

int UILabel.lineWidth: "Maximum width of the label in pixels (define pixels mathematically/relative to)."


The reason it makes sense to me to use World coords is because I am able to get the world coordinates of the edges of the screen using ViewportToWorldPoint.  I can then identify exactly where and how large/small I want each element of my GUI by percentages of the total screen size and in world coordinates.  In our application, we don't care about pixel perfect, we care about consistent widget location for different resolutions and aspect ratios.

I do appreciate the continued support on this.  I have something that works thanks to that!  This is a great tool and it has saved me significant time in other areas.  Thanks!

I will say, however, that in the future, when using NGUI, I will attempt to stick to using UIRoot and Orthosize = 1 to avoid confusion.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: UILabel.linewidth problem
« Reply #11 on: July 01, 2012, 10:37:34 AM »
That would be advised, yes. :)

In general "local coordinates" means some internal value that must be scaled by the transform in order to make sense. "Pixels" means scaled by the widget's local transform.