Page 1 of 2

[Solved] Element::SetPosition() and SequentialLayoutContainers

Posted: Wed Mar 08, 2017 21:54
by TheWanderer
Hey everyone,

I recently wrapped some of my UI items in SequentialLayoutContainers in order to give me greater flexibility in what is displayed in my UI windows. I'm running into an issue though where setting the position of the parent window (via SetPosition()) is not updating the position of the container, leaving its child elements in their old position. If I remove the layout container, everything works as expected.

Here's part of the layout for the window:

Code: Select all

<Window name="PlayStateTileInfo_FrameWindow"  type="TaharezLook/FrameWindow" >

    <Property name="Size" value="{{0,325},{0,350}}" />
    <Property name="FrameEnabled" value="true" />
    <Property name="Disabled" value="true" />
    <Property name="Visible" value="false" />
    <Property name="Text" value="Tile Information" />
    <Property name="TitlebarEnabled" value="true" />
    <Property name="CloseButtonEnabled" value="true" />
    <Property name="RollUpEnabled" value="false" />
    <Property name="SizingEnabled" value="false" />
           
    <!-- Coordinates Information  -->
    <Window name="GPSCoordinates_HLC" type="HorizontalLayoutContainer" >
        <Property name="Position" value="{{0.1,-15.0},{0.05,-12.5}}" />
        <Property name="Size" value="{{1.0,0.0},{0.0,25.0}}" />             
           
        <Window name="GPSCoordinatesTag_Label"  type="TaharezLook/Label" >
            <Property name="Text" value="Coordinates:" />
            <Property name="Size" value="{{0.0,0.0},{0.0,25.0}}" />
            <Property name="HorzFormatting" value="LeftAligned" />
        </Window>

        <Window name="GPSCoordinates_Label"  type="TaharezLook/Label" >
            <Property name="Size" value="{{0,0.0},{0,25}}" />
            <Property name="HorzFormatting" value="LeftAligned" />
            <Property name="Margin" value="{top:{0.0,0.0},left:{0.05,0.0},bottom:{0.0,0.0},right:{0.0,0.0}}" />
        </Window>               
           
    </Window>
       
</Window>


Here's the code updating the position

Code: Select all

tileContentsWindow = static_cast< CEGUI::FrameWindow * >( m_uiSheet->getChildRecursive("PlayStateTileInfo_FrameWindow"));
tileContentsWindow ->setPosition( CEGUI::UVector2(
                                                   CEGUI::UDim( 0.f, mouseX + 40 ),
                                                   CEGUI::UDim( 0.f, mouseY - 100 ) ) );


Any thoughts on why the update to the position is not being propagated properly? Thank you in advance for the help :D

CEGUI Info

Code: Select all

---- Version: 0.8.4 (Build: Jul 13 2016 Static Debug Microsoft Windows MSVC++ 11.0 32 bit) ----
---- Renderer module is: CEGUI::OgreRenderer - Official OGRE based 2nd generation renderer module. ----
---- XML Parser module is: CEGUI::RapidXMLParser - Official RapidXML based parser module for CEGUI ----
---- Image Codec module is: OgreImageCodec - Integrated ImageCodec using the Ogre engine. ----
---- Scripting module is: None ----

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Wed Mar 08, 2017 22:04
by Ident
Is there any chance you could try out v0-8 from the repository? we recently fixed a bug regarding FrameWindow positions not being propagated properly to the children. It could be related.

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Wed Mar 08, 2017 22:19
by TheWanderer
Do you mean 0.8.7 for CEGUI? I'm not using CEED, which is what appears to be a v0-8.

I can certainly try it; will take a bit while I set everything up.

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Wed Mar 08, 2017 22:53
by Ident
v0-8 is a CEGUI branch, not CEED. There is also a CEED branch v0-8 but that is just made to go along with CEGUI v0-8.

Link:
https://bitbucket.org/cegui/cegui/src/c ... 1/?at=v0-8

This is what is going to be 0.8.8

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Wed Mar 08, 2017 23:28
by TheWanderer
Ah, I see. I'll DL it and let you know what I find. (Will be a bit)

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Thu Mar 09, 2017 00:27
by TheWanderer
Updating the version to the 0-8 branch did not make a difference :-/. The child elements remained in the old position after the parent window of the LayoutContainer was moved.

In order to debug this better, how are positional updates propagated to the children? Is it somehow different from dragging? Because that works without issue.

Edit:
I tried tracing the behavior of the window ( concentrating on Element::notifyScreenAreaChanged() ) and compared the behavior of a mouse drag with the setPosition() call (basically, the one that works and the one that doesn't). As far as I can tell, there is little difference between the two; the children of the LayoutContainer do get called during this updated. I'll keep digging, as the difference should be here.

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Thu Mar 09, 2017 22:39
by TheWanderer
Brief Update: Updating the size of one of the child windows inside the LayoutContainer after the position of the parent window has been modified results in the child position being updated properly. Could the child window not be getting properly set to dirty when inside a layout container? (Though, I admit, that it appears that it is; at least notifyScreenAreaChanged() is called on it)

Any thoughts on where to look next, Ident?

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Thu Mar 09, 2017 22:57
by Ident
LayoutContainers are relatively new compared to some other widgets, there could easily be bugs.

I did not write them so I got no clue where to look next, I probably know as much as you at this point and would just have to do what you are doing.

What you can try is to call notifyDisplaySizeChanged on the child after the parent container position was changed. If this changes something then this likely means "something" wasnt set dirty that probably should have. :pint:

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Fri Mar 10, 2017 23:16
by TheWanderer
Al'right, this has taken me down quite the Rabbit Hole, but I believe I have an answer.

When the position of a Window is set ( Element::setArea_impl() ), it first invalidates its unclipped rects (both outer and inner), updates the size of its area, then propagates the changes to its children through the onMoved() event.

The children follow a similar pattern ( Window::notifyScreenAreaChanged() ), first invalidating their own unclipped rects, passing the event to their children, then updating their geometry. As the children update their geometry, they make calls to Element::getUnclippedOuterRect() which, since it was invalidated previously, now gets recalculated in Element::getUnclippedOuterRect_impl(), which itself updates the outter rect for the parent.

The problem for LayoutContainers, as I see it, is that they only mark their unclipped rects *AFTER* they've passed the notifyScreenAreaChanged() to their children. Specifically:

Code: Select all

void LayoutContainer::notifyScreenAreaChanged(bool recursive)
{
    Window::notifyScreenAreaChanged(recursive);
   
    d_clientChildContentArea.invalidateCache();
}


This means all the children are re-calculating their position with the old position of the layout container. If you perform a change to any of the LayoutContainer's children after the original call to setPosition(), the children will correctly update the LayoutContainer's area (since it was marked dirty) and be updated correctly.

This actually explains why mouse dragging works... or at least appears to. The fact that my app is going at 300 FPS means that, at most, positional updates are going to be 1 or 2 pixels away from the last update, so I'd never really notice.

My fix was the following:

Code: Select all

void LayoutContainer::notifyScreenAreaChanged(bool recursive)
{
    d_clientChildContentArea.invalidateCache();
   
    Window::notifyScreenAreaChanged(recursive);
}


As far as I can tell, positional updates are now being carried out correctly (in my brief test case). Does this seem like a valid analysis? Would this change hurt anything else?

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Sat Mar 11, 2017 10:17
by Ident
I do not see what could go wrong by doing this. Have you played around with it enough to be confident about it being non-breaking? The sample browser uses a bunch of layout containers if I remember right , so that might be a good case to test. If you want you can make a pull-request on v0-8 and i ll look at it.

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Sat Mar 11, 2017 18:51
by TheWanderer
I will do so, but give me until Monday. I promised myself a bit of time off this weekend :pint:

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Sat Mar 11, 2017 23:35
by Ident
I will even give you time until Wednesday! :pint:

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Mon Mar 13, 2017 23:02
by TheWanderer
I tried out the changes on a few of my UI elements which are heavy on layout containers (both Horizontal and Vertical; haven't tried Grid) and, as far as I can tell, everything is working as expected.

The pull request should be on your desk. (If not, here's the link). Let me know if there's anything else you need.

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Tue Mar 14, 2017 19:41
by Ident
You need to make a PR against the official CEGUI bitbucket, not against your own fork
https://confluence.atlassian.com/bitbuc ... 20593.html

Re: Element::SetPosition() and SequentialLayoutContainers

Posted: Tue Mar 14, 2017 23:03
by TheWanderer
Sorry about that; first time using BitBucket. :)

Updated link!