Author Topic: BUG(?): Dynamic Font in ScrollView, odd positioning  (Read 9594 times)

helmesjo

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 116
    • View Profile
Re: BUG(?): Dynamic Font in ScrollView, odd positioning
« Reply #15 on: May 14, 2014, 02:15:45 AM »
I agree that ideally it should be like that. Unfortunately the way panels work was set in stone many years ago, and even the eventual creation of UIRect in an attempt to optimize some of the common functionality was done years later. You can still use the common functionality via the UIRect's SetRect() function, set anchors the same way on both panels and widgets, and some other things, but there is a pretty big difference between panels and widgets that's not going to disappear due to backwards compatibility.

If I was to re-design it, throwing backwards compatibility to the wind, I'd do it differently. If I do NGUI for the Unreal Engine I will do just that. But this part of NGUI for Unity is not likely to change.

That's really unfortunate. I sure hope the new UI-Engine for Unity 4.x doesn't get polluted with this, since as I understand NGUI has a vital part in that, yes? "Open for extension, closed for modification" is key in OOP (not trying to lecture you but more push on the importance).

Anyways, I noticed another very annoying issue with nested panels (A scrollview with a nested panel as child). Keeping the story short the issue lies in that UIRect is abstract and not the "true" base class for a UI frame, so I have to chose wether to have a UIPanel as the "rect", or a UIWidget. Problem is, I really need it to be a UIPanel and I naturally use the frame as bounds to know when cells should be put pack on the reusable stack (it's a custom made table with reusable cells to be able to have "infinite" cells in the table). Now, if the user wants the table can auto expand to fully enclose all cells, and in this case the bounds from the NEXT UIPanel with clipping turned on should be used to know if cells are visible or not.

So I have this (simplified for this example since this is the use case causing the bug):

- ScrollView A (with UIPanel attached)
-- Panel A
--- UIWidget (cell)
--- UIWidget (cell)
--- etc.

Now, if I activate cells when they become visible (using UIScrollViews bounds), they will be rendered in the wrong position (even though positioned correctly).

So I do this:
  • Drag scrollView (fast/release it out of bounds to let it spring back)
  • While dragging, enable widgets inside Panel A (child panel)
  • Watch the widget being render incorrectly, and a force-refresh of Panel A is needed

Since this only happens while ACTIVATING a widget inside a child panel while DRAGGING the parent-panel, one might conclude that the problem lies in the offset of ScrollView A's panel messing up the drawing of child-panel A.

That's a mouthful, but you should get the picture. To temporarily fix it, I added the possibility for UIPanel.Find to ignore panels if disabled and a boolean "IgnoreIfDisabled" is set to true. Thanks to this the panel being scrolled will also be responsible for drawing my cells, and the offset won't mess it up.

Thanks!

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: BUG(?): Dynamic Font in ScrollView, odd positioning
« Reply #16 on: May 14, 2014, 06:49:42 AM »
If it's what I think it is, then it should be fixed in 3.6.0. You can fix it locally by modifying UIPanel's clipOffset to this:
  1.         public Vector2 clipOffset
  2.         {
  3.                 get
  4.                 {
  5.                         return mClipOffset;
  6.                 }
  7.                 set
  8.                 {
  9.                         if (Mathf.Abs(mClipOffset.x - value.x) > 0.001f ||
  10.                                 Mathf.Abs(mClipOffset.y - value.y) > 0.001f)
  11.                         {
  12.                                 mClipOffset = value;
  13.                                 InvalidateClipping();
  14.  
  15.                                 // Call the event delegate
  16.                                 if (onClipMove != null) onClipMove(this);
  17. #if UNITY_EDITOR
  18.                                 if (!Application.isPlaying) UpdateDrawCalls();
  19. #endif
  20.                         }
  21.                 }
  22.         }
  23.  
  24.         void InvalidateClipping ()
  25.         {
  26.                 mResized = true;
  27.                 mMatrixFrame = -1;
  28.                 mCullTime = (mCullTime == 0f) ? 0.001f : RealTime.time + 0.15f;
  29.  
  30.                 for (int i = 0; i < list.size; ++i)
  31.                 {
  32.                         UIPanel p = list[i];
  33.                         if (p != this && p.parentPanel == this)
  34.                                 p.InvalidateClipping();
  35.                 }
  36.         }
...and changing UIPanel.IsVisible(UIWidget) to this:
  1.         public bool IsVisible (UIWidget w)
  2.         {
  3.                 if ((mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip) && !w.hideIfOffScreen)
  4.                 {
  5.                         if (clipCount == 0) return true;
  6.                         if (mParentPanel != null) return mParentPanel.IsVisible(w);
  7.                 }
  8.  
  9.                 UIPanel p = this;
  10.                 Vector3[] corners = w.worldCorners;
  11.  
  12.                 while (p != null)
  13.                 {
  14.                         if (!IsVisible(corners[0], corners[1], corners[2], corners[3])) return false;
  15.                         p = p.mParentPanel;
  16.                 }
  17.                 return true;
  18.         }

helmesjo

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 116
    • View Profile
Re: BUG(?): Dynamic Font in ScrollView, odd positioning
« Reply #17 on: May 14, 2014, 10:38:31 AM »
If it's what I think it is, then it should be fixed in 3.6.0. You can fix it locally by modifying UIPanel's clipOffset to this:
  1.         public Vector2 clipOffset
  2.         {
  3.                 get
  4.                 {
  5.                         return mClipOffset;
  6.                 }
  7.                 set
  8.                 {
  9.                         if (Mathf.Abs(mClipOffset.x - value.x) > 0.001f ||
  10.                                 Mathf.Abs(mClipOffset.y - value.y) > 0.001f)
  11.                         {
  12.                                 mClipOffset = value;
  13.                                 InvalidateClipping();
  14.  
  15.                                 // Call the event delegate
  16.                                 if (onClipMove != null) onClipMove(this);
  17. #if UNITY_EDITOR
  18.                                 if (!Application.isPlaying) UpdateDrawCalls();
  19. #endif
  20.                         }
  21.                 }
  22.         }
  23.  
  24.         void InvalidateClipping ()
  25.         {
  26.                 mResized = true;
  27.                 mMatrixFrame = -1;
  28.                 mCullTime = (mCullTime == 0f) ? 0.001f : RealTime.time + 0.15f;
  29.  
  30.                 for (int i = 0; i < list.size; ++i)
  31.                 {
  32.                         UIPanel p = list[i];
  33.                         if (p != this && p.parentPanel == this)
  34.                                 p.InvalidateClipping();
  35.                 }
  36.         }
...and changing UIPanel.IsVisible(UIWidget) to this:
  1.         public bool IsVisible (UIWidget w)
  2.         {
  3.                 if ((mClipping == UIDrawCall.Clipping.None || mClipping == UIDrawCall.Clipping.ConstrainButDontClip) && !w.hideIfOffScreen)
  4.                 {
  5.                         if (clipCount == 0) return true;
  6.                         if (mParentPanel != null) return mParentPanel.IsVisible(w);
  7.                 }
  8.  
  9.                 UIPanel p = this;
  10.                 Vector3[] corners = w.worldCorners;
  11.  
  12.                 while (p != null)
  13.                 {
  14.                         if (!IsVisible(corners[0], corners[1], corners[2], corners[3])) return false;
  15.                         p = p.mParentPanel;
  16.                 }
  17.                 return true;
  18.         }

That seemed to do the trick indeed! Being too lazy to check, how much does this impact performance?

TY.

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: BUG(?): Dynamic Font in ScrollView, odd positioning
« Reply #18 on: May 14, 2014, 11:26:35 PM »
It shouldn't impact it much. If anything, it's now at the performance level it should have been. Before it was skipping some important checks. It would be nearly the same as having just a single scroll view in terms of performance.

helmesjo

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 116
    • View Profile
Re: BUG(?): Dynamic Font in ScrollView, odd positioning
« Reply #19 on: May 15, 2014, 01:40:14 AM »
It shouldn't impact it much. If anything, it's now at the performance level it should have been. Before it was skipping some important checks. It would be nearly the same as having just a single scroll view in terms of performance.

Alright.

About the next update, 3.6.0, could you make sure that using UIPanel & UIWidget through UIRect is transparent? I remember you added some more common functionality in UIRect (SetRect?), but just making sure you also add setters for width/height for UIPanel, pivotOffset (even if it's a constant, but it's definitely usable to have it customisable IMO), depth... Is what I can think of now. Everything that UIWidget & UIPanel have in common that makes sense (but as of now implemented differently) should be inherited from UIRect. So I don't have to mod it in myself, since then updating is always a fear... :P
I'll give you a golden star if you add a "onRectChanged" callback that is guaranteed to be invoked whenever any widget changes size. As of now, I mostly use MarkAsChanged to do this (to avoid polling), but with labels that is not 100% accurate (not getting invoked when typing new line etc.).

Thanks!

Edit. Center! You should be able to set/get center-position of UIRects.
« Last Edit: May 15, 2014, 10:46:34 AM by helmesjo »

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: BUG(?): Dynamic Font in ScrollView, odd positioning
« Reply #20 on: May 15, 2014, 11:31:40 AM »
  1. Vector3[] corners = widget.worldCorners; // or localCorners
  2. Vector3 center = Vector3.Lerp(corners[0], corners[2], 0.5f);

helmesjo

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 116
    • View Profile
Re: BUG(?): Dynamic Font in ScrollView, odd positioning
« Reply #21 on: May 15, 2014, 01:03:01 PM »
  1. Vector3[] corners = widget.worldCorners; // or localCorners
  2. Vector3 center = Vector3.Lerp(corners[0], corners[2], 0.5f);

See, two lines just for getting the center. Now imagine doing that over and over... That's the point with convenience methods: They make things more convenient! :)

ArenMook

  • Administrator
  • Hero Member
  • *****
  • Thank You
  • -Given: 337
  • -Receive: 1171
  • Posts: 22,128
  • Toronto, Canada
    • View Profile
Re: BUG(?): Dynamic Font in ScrollView, odd positioning
« Reply #22 on: May 16, 2014, 12:49:31 PM »
Well, you know, if the widget is using a center pivot, then its transform's position is its center. I can certainly add a method for it, but it still seems... unnecessary.

helmesjo

  • Full Member
  • ***
  • Thank You
  • -Given: 0
  • -Receive: 0
  • Posts: 116
    • View Profile
Re: BUG(?): Dynamic Font in ScrollView, odd positioning
« Reply #23 on: May 17, 2014, 01:11:59 AM »
Well, you know, if the widget is using a center pivot, then its transform's position is its center. I can certainly add a method for it, but it still seems... unnecessary.

Nah, I don't agree. There is a lot of times where you need to position widgets centered in a line without caring about pivot-point. Pivot-point might differ because of user-preferences. Say if I write a special table-class used by others and they want a different pivot-point than the one I'm expecting, then there is no way for me to allow that without things getting messed up.