Renaming windows recursively? (Or: Where is getNextChild?)

For help with general CEGUI usage:
- Questions about the usage of CEGUI and its features, if not explained in the documentation.
- Problems with the CMAKE configuration or problems occuring during the build process/compilation.
- Errors or unexpected behaviour.

Moderators: CEGUI MVP, CEGUI Team

User avatar
Das Gurke
Not too shy to talk
Not too shy to talk
Posts: 31
Joined: Sat Sep 02, 2006 15:45

Renaming windows recursively? (Or: Where is getNextChild?)

Postby Das Gurke » Tue Jun 12, 2007 12:35

I need to load a layout, something like a playerframe, multiple times. Therefore I need to add some kind of prefix to every subwindow of the layout i want to load.

Searching through the forums I came to something like this: (from *here*)

Code: Select all

void Control_Playerframe::renameWindows(void)
{
   // Renaming the container
   CEGUI::String name = mContainer->getName();
   mContainer->rename(getPlayerName() + name);

   for(CEGUI::Window* child = mContainer->getFirstChild(), child, child = mContainer->getNextChild())
    {
      child->rename(getPlayerName() + name);
    }
}
But well, unluckily the getFirstChild() and getNextChild() don't seem to exist anymore. Are they renamed or dropped?

Or am I taking a completly wrong approach towards this?

User avatar
Levia
Quite a regular
Quite a regular
Posts: 83
Joined: Mon May 22, 2006 18:25
Location: Bergen op zoom, The Netherlands
Contact:

Postby Levia » Tue Jun 12, 2007 12:46

You can simple use the combination of getChildCount and getChildAtIdx

Code: Select all

for (int x = 0; x != mContainer->getChildCount(); ++x)
{
   Window * wnd = mContainer->getChildAtIdx(x);
   // do your stuff.
}
Image
Image

ppl
Not too shy to talk
Not too shy to talk
Posts: 31
Joined: Tue May 15, 2007 16:37
Location: Canada

Postby ppl » Tue Jun 12, 2007 12:52

I don't know if this is the best option but you should be able to call getChildCount() and getChildAtIdx().

HTH,
ppl

User avatar
Das Gurke
Not too shy to talk
Not too shy to talk
Posts: 31
Joined: Sat Sep 02, 2006 15:45

Postby Das Gurke » Tue Jun 12, 2007 13:05

The solution kind of works.

First: I guess the != was a "typo" in your code? Or am i mistaken?

Second: Well, at least that code itself does not crash or throw any exceptions. But it seems to corrupt CEGUI. After renaming all my window like this:

Code: Select all

void Control_Playerframe::renameWindows(void)
{
   // Renaming the container
   CEGUI::String name = mContainer->getName();
   mContainer->rename(getPlayerName() + name);

   for (int x = 0; x < mContainer->getChildCount(); ++x)
   {
      CEGUI::Window * wnd = mContainer->getChildAtIdx(x);
      //mWindowManager->renameWindow(wnd, getPlayerName() + wnd->getName());
      wnd->rename(getPlayerName() + wnd->getName());
   }
}
As you can see I gave it a second try via the WindowManager, that does not change anything :(

My app throws an ItemNotFound Exception whenever I try to do something with CEGUI afterwards, eg injecting input or rendering it (via ogre). The log looks like this:
12/06/2007 15:01:33 (InfL1) ---- Successfully completed loading of GUI layout from 'Playerframe.layout' ----
12/06/2007 15:01:33 (Error) Exception: WindowManager::getWindow - A Window object with the name 'MarcusPlayerFrame/Container__auto_titlebar__' does not exist within the system
12/06/2007 15:01:33 (Error) Exception: WindowManager::getWindow - A Window object with the name 'MarcusPlayerFrame/Container__auto_titlebar__' does not exist within the system
12/06/2007 15:01:33 (Error) Exception: FontManager::getFont - A Font object with the specified name 'BlueHighway-14' does not exist within the system
12/06/2007 15:01:33 (Error) Exception: FontManager::getFont - A Font object with the specified name 'BlueHighway-14' does not exist within the system
12/06/2007 15:01:33 (Error) Exception: FontManager::getFont - A Font object with the specified name 'BlueHighway-14' does not exist within the system
12/06/2007 15:01:33 (Error) Exception: FontManager::getFont - A Font object with the specified name 'BlueHighway-14' does not exist within the system
12/06/2007 15:01:33 (Error) Exception: FontManager::getFont - A Font object with the specified name 'BlueHighway-14' does not exist within the system
12/06/2007 15:01:33 (InfL1) ---- Successfully completed loading of GUI layout from 'Performance.layout' ----
12/06/2007 15:01:33 (Error) Exception: WindowManager::getWindow - A Window object with the name 'MarcusPlayerFrame/Container__auto_titlebar__' does not exist within the system
12/06/2007 15:01:33 (Error) Exception: WindowManager::getWindow - A Window object with the name 'MarcusPlayerFrame/Container__auto_titlebar__' does not exist within the system
12/06/2007 15:01:33 (Error) Exception: WindowManager::getWindow - A Window object with the name 'MarcusPlayerFrame/Container__auto_titlebar__' does not exist within the system
In this case, 'Marcus' is the prefix. This might be a bug, because the corresponding window does not have a titlebar enabled.

Rackle
CEGUI Team (Retired)
Posts: 534
Joined: Mon Jan 16, 2006 11:59
Location: Montréal

Postby Rackle » Tue Jun 12, 2007 13:20

This is part of my Drag and Drop thingy. Sadly I have to go through yet another revision as I'm still not happy with where the code took me. However this bit is fine.

CloningSystem.h

Code: Select all

#ifndef _CloningSystem_
#define _CloningSystem_

#include <CEGUIWindow.h>
#include <CEGUIString.h>


class CloningSystem
{
public:
   // Constructor.
   CloningSystem();

   // Destructor
   virtual ~CloningSystem();

    // Clone a parent window.
    virtual CEGUI::Window* cloneWindow(CEGUI::Window* pOriginalWindow);

    // Return the desired name of the clone.
    virtual CEGUI::String getParentName(CEGUI::Window* pOriginalWindow);

    // Return the name of the cloned child.
    virtual CEGUI::String getChildName(const CEGUI::String& pClonedParentWindowName,
                              CEGUI::Window* pOriginalChildWindow);

   // Copy the properties of one window to another
   virtual void copyProperties(CEGUI::Window* pSource,
                        CEGUI::Window* pDestination);

private:
   // Recursively clone the children of a window
   void cloneChildren(const CEGUI::String pClonedWindowName,
                       CEGUI::Window* pOriginalWindow,
                       CEGUI::Window* pCloneWindow);

};

#endif // _CloningSystem_



CloningSystem.cpp

Code: Select all

#include <cegui.h>
#include "CloningSystem.h"


const char SEPARATOR = ':';

//---------------------------------------------------------------------------
CloningSystem::CloningSystem()
{
}

//---------------------------------------------------------------------------
CloningSystem::~CloningSystem()
{
}

//---------------------------------------------------------------------------
CEGUI::Window* CloningSystem::cloneWindow(CEGUI::Window* pOriginalWindow)
{
    CEGUI::String clonedName = getParentName(pOriginalWindow);
   CEGUI::Window* clonedWindow = CEGUI::WindowManager::getSingleton().createWindow(pOriginalWindow->getType(), clonedName );
   if(clonedWindow)
   {
      copyProperties(pOriginalWindow, clonedWindow);
      cloneChildren(clonedName, pOriginalWindow, clonedWindow);
   }

   return clonedWindow;
}

//---------------------------------------------------------------------------
CEGUI::String CloningSystem::getParentName(CEGUI::Window* pOriginalWindow)
{
    /*   This implementation prefixe the name with a version number and a separator,
      a special character that will not be used when creating a .layout file.  This
      scheme allows the easy retrieval of the version as well as the original name.
      Two usage can be derived from this.

      First, retrieving the "original" command determines whether the version will be
      meaningful.  For example a DragItem called "/HotKeys/CommandQuit" is cloned into
      the DragItem called "0:/HotKeys/CommandQuit".  In this instance the version does
      not matter; "/HotKeys/CommandQuit", "0:/HotKeys/CommandQuit", and
      "999:/HotKeys/CommandQuit" all desire to be treated in an identical matter,
      namely to quit.

      And for those cases where the version is meaningful, that version number can be
      used as a parameter to the function handling that particular command.  For
      example a "/HotKeys/Macro" DragItem can be cloned to "0:/HotKeys/Macro" and
      interpreted as the command to execute a macro and passing "0" as the macro ID to
      execute.
   */

   // Strip any version that may be present
   CEGUI::String originalParentName( pOriginalWindow->getName() );
   CEGUI::String::size_type separatorPosition = originalParentName.find(SEPARATOR);
   if(separatorPosition != CEGUI::String::npos)
   {
      originalParentName = originalParentName.substr(separatorPosition + 1);
   }

   // Generate a versioned named
    CEGUI::String clonedParentName;
    int version = 0;
    do
    {
        clonedParentName = CEGUI::PropertyHelper::intToString(version)
                     + SEPARATOR
                     + originalParentName;
        ++version;
    }
    while( CEGUI::WindowManager::getSingleton().isWindowPresent( clonedParentName ) );

    return clonedParentName;
}

//---------------------------------------------------------------------------
CEGUI::String CloningSystem::getChildName(const CEGUI::String& pClonedParentWindowName,
                                CEGUI::Window* pOriginalChildWindow)
{
   // Strip any version that may be present
   CEGUI::String originalChildName( pOriginalChildWindow->getName() );
   CEGUI::String::size_type separatorPosition = originalChildName.find(SEPARATOR);
   if(separatorPosition != CEGUI::String::npos)
   {
      originalChildName = originalChildName.substr(separatorPosition + 1);
   }

   separatorPosition = pClonedParentWindowName.find(SEPARATOR);
   if(separatorPosition == CEGUI::String::npos)
    {
        // This is weird; the parent DragItem is not versioned.  It is more likely that
        // getDragItemName() was overidden but not getDragItemChildName().  Let's return
        // nothing and have Cegui throw an exception.
        return "";
    }
    else
    {
        // Add the version to the string making up the name of the child window.  A DragItem
        // "/HotKeys/PlantFlower" is composed of an image and some text.  When cloned it would
        // call upon onCloningDragItem() to generate a name, let's say "15:/HotKeys/PlantFlower".
        // Then onCloningWindow() would be called for the child image and once more for the text
        // child.  The child "/HotKeys/PlantFlower/Image" would become
        // "15:/HotKeys/PlantFlower/Image" and the child "/HotKeys/PlantFlower/Text" would become
        // "15:/HotKeys/PlantFlower/Text".  This way unique names are generated and they can
        // fairly easily be converted back to their original names.
        return pClonedParentWindowName.substr(0, separatorPosition + 1) // Retrieve the version
             + originalChildName;                              // Use the unversioned named
    }
}

//---------------------------------------------------------------------------
void CloningSystem::cloneChildren(const CEGUI::String pClonedDragItemName,
                                  CEGUI::Window* pOriginalWindow,
                                  CEGUI::Window* pCloneWindow)
{
   CEGUI::String clonedChildName;
    CEGUI::Window* clonedChild;
   for(size_t childIdx = 0;
         childIdx < pOriginalWindow->getChildCount();
         childIdx++)
   {
      // Skip auto windows
      if( !pOriginalWindow->getChildAtIdx(childIdx)->isAutoWindow() )
      {
         clonedChildName = getChildName( pClonedDragItemName, pOriginalWindow->getChildAtIdx(childIdx) );
         clonedChild = CEGUI::WindowManager::getSingleton().createWindow(pOriginalWindow->getChildAtIdx(childIdx)->getType(), clonedChildName );
         pCloneWindow->addChildWindow(clonedChild);
         copyProperties(pOriginalWindow->getChildAtIdx(childIdx), clonedChild);
         cloneChildren(pClonedDragItemName,
                    pOriginalWindow->getChildAtIdx(childIdx),
                    clonedChild);
      }
   }
}

//---------------------------------------------------------------------------
void CloningSystem::copyProperties(CEGUI::Window* pSource, CEGUI::Window* pDestination)
{
   CEGUI::PropertySet::Iterator itPropertySet = ((CEGUI::PropertySet*) pSource)->getIterator();
   while (!itPropertySet.isAtEnd())
   {
      if (itPropertySet.getCurrentKey().length() != 0 // Key is valid (weird that it would not be valid but just in case)
         && pSource->getProperty( itPropertySet.getCurrentKey() ).length() != 0 // Ensures that the key has a value
         )
      {
         if( (itPropertySet.getCurrentKey().compare("LookNFeel") == 0
            && pDestination->getProperty(itPropertySet.getCurrentKey()).length() != 0)
            || (itPropertySet.getCurrentKey().compare("WindowRenderer") == 0
            && pDestination->getProperty(itPropertySet.getCurrentKey()).length() != 0)
            )
         {
            // This property has already been set so avoid generating an error
         }
         else
         {
            //CEGUI::Logger::getSingleton().logEvent(itPropertySet.getCurrentKey() + ": " + pSource->getProperty( itPropertySet.getCurrentKey() ), CEGUI::Informative);
            pDestination->setProperty(   itPropertySet.getCurrentKey(),
                                 pSource->getProperty( itPropertySet.getCurrentKey() ) );
         }
      }
      itPropertySet++;
   }
}



You would use it as follows:

Code: Select all

CEGUI::DragContainer* clonedDragItem = static_cast<CEGUI::DragContainer*>( mCloningSystem->cloneWindow(pDragItem) );


where pDragItem is a CEGUI::DragContainer*

You may have to adapt it to clone any window rather than just DragContainers (that should not be a problem). The idea is that you would load a first .layout and then rather than reload a new .layout you'd clone the existing one.

I wonder if there's a way to append something to the widgets created from the .layout.

User avatar
scriptkid
Home away from home
Home away from home
Posts: 1178
Joined: Wed Jan 12, 2005 12:06
Location: The Hague, The Netherlands
Contact:

Postby scriptkid » Tue Jun 12, 2007 18:45

Therefore I need to add some kind of prefix to every subwindow of the layout i want to load.


WindowManager::loadWindowLayout does exactly that, you need to pass a value for the 'prefix' argument.

HTH.

User avatar
Das Gurke
Not too shy to talk
Not too shy to talk
Posts: 31
Joined: Sat Sep 02, 2006 15:45

Postby Das Gurke » Wed Jun 13, 2007 07:35

Well, guess that is what you call "owned by simplicity" ... Works like a charm!

Thanks =)


Return to “Help”

Who is online

Users browsing this forum: MSN [Bot] and 8 guests