Page 1 of 1

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

Posted: Tue Jun 12, 2007 12:35
by Das Gurke
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?

Posted: Tue Jun 12, 2007 12:46
by Levia
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.
}

Posted: Tue Jun 12, 2007 12:52
by ppl
I don't know if this is the best option but you should be able to call getChildCount() and getChildAtIdx().

HTH,
ppl

Posted: Tue Jun 12, 2007 13:05
by Das Gurke
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.

Posted: Tue Jun 12, 2007 13:20
by Rackle
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.

Posted: Tue Jun 12, 2007 18:45
by scriptkid
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.

Posted: Wed Jun 13, 2007 07:35
by Das Gurke
Well, guess that is what you call "owned by simplicity" ... Works like a charm!

Thanks =)