IGUIElement::setEnabled isn't (dis)enableling children

Discuss about anything related to the Irrlicht Engine, or read announcements about any significant features or usage changes.
Post Reply
JonLT
Posts: 152
Joined: Thu Mar 15, 2007 5:47 pm
Location: Denmark

IGUIElement::setEnabled isn't (dis)enableling children

Post by JonLT »

When working on some gui stuff i found that the IGUIElement::setEnabled isn't (dis)enableling its children.
Currently the function is this:

Code: Select all

virtual void setEnabled(bool enabled)
{
   IsEnabled = enabled;
}
shouldn't it be like this

Code: Select all

virtual void setEnabled(bool enabled)
{
   IsEnabled = enabled;

   core::list<IGUIElement*>::Iterator it = Children.begin();
   for (; it != Children.end(); ++it)
      (*it)->IsEnabled = enabled;
}
Or is there some reason that it isn't?
vitek
Bug Slayer
Posts: 3919
Joined: Mon Jan 16, 2006 10:52 am
Location: Corvallis, OR

Post by vitek »

That wouldn't work for the children of children. But making a recursive call down the tree that problem could be solved.

The only reason I can think of to not do it that way would be the issues that come up when you would disable a high level control. Say you had a window with a few buttons, and one of the buttons was disabled. Something happens in the UI and the entire window is disabled for a short period. When the window disabled state is restored, the button that was disabled would be enabled, and that would most likely be bad.

I think a more appropriate solution would be to have a function like getEnabledAbsolute() that would be used by a control to decide how to render itself. That function would walk up its parent pointer trying to see if one of the ancestor controls was disabled.

Code: Select all

bool IGUIElement_getEnabledAbsolute(IGUIElement* element)
{
  for (/**/; element; element = element->getParent())
  {
    if (!element->getEnabled())
      return false;
  }

  return true;
}
Unfortunately this makes rendering gui elements more expensive because they have to walk the heirarchy every render to see if they are enabled or not.

Another possible option is to keep a few enabled flags. One enabled flag indicates that this control is the one that is enabled, and another indicating that all ancestors are enabled. I think it would look something like this...

Code: Select all

// bit 1 indicates we are enabled
// bit 2 indicates all ancestors are enabled
u8 IsEnabled;

bool ISceneNode::getEnabled() const
{
  return (IsEnabled & 3) == 3; // fully enabled
}

void ISceneNode::setEnabled(bool enabled)
{
  // set/clear bit indicating this control is enabled
  if (enabled)
    IsEnabled |= 1;
  else
    IsEnabled &= ~1;

  // tell children that parent is enabled or disabled
  core::list<IGUIElement*>::Iterator it = Children.begin(); 
  for (; it != Children.end(); ++it) 
     (*it)->setEnabledAncestor(enabled);
}

void ISceneNode::setEnabledAncestor(bool enabled)
{
  // set/clear bit indicating that ancestor is enabled
  if (enabled)
    IsEnabled |= 2;
  else
    IsEnabled &= ~2;

  // if ancestor is getting enabled and we are currently disabled don't
  // bother updating children states. the child 'ancestor enabled' flag
  // will remain false this way.
  if (enabled && !(IsEnabled & 1))
    return;

  core::list<IGUIElement*>::Iterator it = Children.begin(); 
  for (; it != Children.end(); ++it) 
     (*it)->setEnabledAncestor(enabled);
}
Travis
bitplane
Admin
Posts: 3204
Joined: Mon Mar 28, 2005 3:45 am
Location: England
Contact:

Post by bitplane »

hmm yes, I like it. thanks travis. i'll add this to my todo list :)
Submit bugs/patches to the tracker!
Need help right now? Visit the chat room
Post Reply