I discovered the following problem concerning the GUILayout XML element processing in CEGUI 0.7.7. I've created a GUILayout consisting of a custom ScrollablePane widget, a "DragMeAround"-like child FrameWindow for testing (added to the ContentArea of the pane), and another "Minimap" child FrameWindow. The latter FrameWindow shall be handled as special "NonClient" window of the ScrollablePane, i.e. it should not move when the pane is scrolled. In order to realize this feature I've overloaded the ScrollablePane::addChild_impl() methods as follows
Code: Select all
void ZoomableScrollPaneWidget::addChild_impl(Window* wnd)
{
if ( wnd == NULL )
CEGUI_THROW(NullObjectException("Invalid handle!"));
// Check to see if 'wnd' is a regular non-client window, e.g. a Minimap
if ( !wnd->isAutoWindow() && wnd->isNonClientWindow() )
{
// Do NOT treat this window as ScrollablePane content
Window::addChild_impl(wnd);
}
else
{
// Use base implementation to handle other types of child widgets
ScrollablePane::addChild_impl(wnd);
}
} // ZoomableScrollPaneWidget::addChild_impl
The corresponding GUILayout looks like:
Code: Select all
<GUILayout>
<Window Type="DefaultWindow" Name="Root" >
<Property Name="UnifiedAreaRect" Value="{{0,0},{0,0},{1,0},{1,0}}" />
<Property Name="MousePassThroughEnabled" Value="True" />
<!-- Define a ZoomableScrollPaneWidget -->
<Window Type="ZoomableScrollPaneWidget" Name="Root/ScrollPane">
<Property Name="UnifiedAreaRect" Value="{{0,0},{0,0},{1,0},{1,0}}" />
<Property Name="ContentPaneAutoSized" Value="False" /> <!-- order matters! -->
<Property Name="ContentArea" Value="l:0.0 t:0.0 r:2048.0 b:1152.0" />
<Property Name="ForceVertScrollbar" Value="False" />
<Property Name="ForceHorzScrollbar" Value="False" />
<!-- Define a Minimap overlay (as NonClient child of our pane) -->
<Window Type="DarkLook/FrameWindow" Name="Root/ScrollPane/Minimap" >
<Property Name="UnifiedSize" Value="{{0,256},{0,256}}" />
<Property Name="UnifiedPosition" Value="{{0.1,0},{0.1,0}}" />
<Property Name="Text" Value="Minimap" />
<Property Name="NonClient" Value="True" />
<Property Name="AlwaysOnTop" Value="True" />
<AutoWindow NameSuffix="__auto_clientarea__" >
<Window Type="Vanilla/StaticImage" Name="ActiveScene" >
<Property Name="UnifiedSize" Value="{{1,0},{1,0}}" />
<Property Name="BackgroundEnabled" Value="False" />
<Property Name="FrameEnabled" Value="False" />
<Property Name="MousePassThroughEnabled" Value="True" />
</Window>
<Window Type="Vanilla/StaticImage" Name="BirdsEye" >
<Property Name="UnifiedSize" Value="{{0.2,0},{0.2,0}}" />
<Property Name="BackgroundEnabled" Value="True" />
<Property Name="FrameEnabled" Value="False" />
<Property Name="MousePassThroughEnabled" Value="False" />
<Property Name="Alpha" Value="0.4" />
</Window>
</AutoWindow>
</Window> <!-- end Root/ScrollPane/Minimap -->
<!-- Define "DragMeAround" - FrameWindow as ScrollPane content -->
<Window Type="DarkLook/FrameWindow" Name="Root/ScrollPane/Test" >
<Property Name="UnifiedSize" Value="{{0,128},{0,128}}" />
<Property Name="UnifiedPosition" Value="{{0.3,0},{0.2,0}}" />
<Property Name="Text" Value="DragMeAround" />
</Window>
</Window> <!-- End Root/ScrollPane -->
</Window> <!-- End Root -->
</GUILayout>
What's important here is that I set the "NonClient" property of the "Root/ScrollPane/Minimap" window to "True", so this child window should be specially handled within the overloaded addChild_impl() of my custom ScrollablePane widget.
I discovered the following problem: When loading the GUILayout, the GUILayout_xmlHandler will add the "Root/ScrollPane/Minimap" as child to "Root/ScrollPane" BEFORE setting its GUILayout properties, in particular, before setting the "NonClient" property to "True". So the overloaded ScrollablePane::addChild_impl() will not work as expected.
I have applied the following changes in class GUILayout_xmlHandler from CEGUI-0.7.7:
Code: Select all
void GUILayout_xmlHandler::elementWindowStart(const XMLAttributes& attributes)
{
// get type of window to create
String windowType(attributes.getValueAsString(WindowTypeAttribute));
// get name for new window
String windowName(attributes.getValueAsString(WindowNameAttribute));
// attempt to create window
CEGUI_TRY
{
Window* wnd = WindowManager::getSingleton().createWindow(windowType, d_namingPrefix + windowName);
// // add this window to the current parent (if any)
// if (!d_stack.empty())
// d_stack.back().first->addChildWindow(wnd);
// else
// d_root = wnd;
// Changed 04/23/2013, KS
if (d_stack.empty())
d_root = wnd;
// make this window the top of the stack
d_stack.push_back(WindowStackEntry(wnd,true));
// tell it that it is being initialised
wnd->beginInitialisation();
}
...
}
Code: Select all
void GUILayout_xmlHandler::elementWindowEnd()
{
// pop a window from the window stack
if (!d_stack.empty())
{
// d_stack.back().first->endInitialisation();
Window* wnd = d_stack.back().first;
wnd->endInitialisation();
d_stack.pop_back();
// Added 04/23/2013, KS
// - see also "Changed" section in elementWindowStart
// Add 'wnd' to its parent window (if any)
if ( !(wnd==d_root) && !d_stack.empty() )
d_stack.back().first->addChildWindow(wnd);
}
}
After recompiling the library the problem was fixed. The GUILayout was successfully loaded and all child window properties are now set to their configured values BEFORE the window is added to its parent.
I am not sure about the side effects of the above changes in other parts of the CEGUI library?! Maybe there a cases where this patch is not applicable?