Explorar o código

2D Forms now draw into a FrameBuffer. Controls are only redrawn when dirty.
Some code style changes (indentation).
Minor update to the particles sample.

Adam Blake %!s(int64=13) %!d(string=hai) anos
pai
achega
6192fd04b7

+ 38 - 35
gameplay/src/AbsoluteLayout.cpp

@@ -5,53 +5,56 @@
 
 
 namespace gameplay
 namespace gameplay
 {
 {
-    static AbsoluteLayout* __instance;
 
 
-    AbsoluteLayout::AbsoluteLayout()
-    {
-    }
+static AbsoluteLayout* __instance;
+
+AbsoluteLayout::AbsoluteLayout()
+{
+}
+
+AbsoluteLayout::AbsoluteLayout(const AbsoluteLayout& copy)
+{
+}
 
 
-    AbsoluteLayout::AbsoluteLayout(const AbsoluteLayout& copy)
+AbsoluteLayout::~AbsoluteLayout()
+{
+    __instance = NULL;
+}
+
+AbsoluteLayout* AbsoluteLayout::create()
+{
+    if (!__instance)
     {
     {
+        __instance = new AbsoluteLayout();
     }
     }
-
-    AbsoluteLayout::~AbsoluteLayout()
+    else
     {
     {
+        __instance->addRef();
     }
     }
 
 
-    AbsoluteLayout* AbsoluteLayout::create()
-    {
-        if (!__instance)
-        {
-            __instance = new AbsoluteLayout();
-        }
-        else
-        {
-            __instance->addRef();
-        }
+    return __instance;
+}
 
 
-        return __instance;
-    }
+Layout::Type AbsoluteLayout::getType()
+{
+    return Layout::LAYOUT_ABSOLUTE;
+}
 
 
-    Layout::Type AbsoluteLayout::getType()
+void AbsoluteLayout::update(const Container* container)
+{
+    // An AbsoluteLayout does nothing to modify the layout of Controls.
+    std::vector<Control*> controls = container->getControls();
+    unsigned int controlsCount = controls.size();
+    for (unsigned int i = 0; i < controlsCount; i++)
     {
     {
-        return Layout::LAYOUT_ABSOLUTE;
-    }
+        Control* control = controls[i];
 
 
-    void AbsoluteLayout::update(const Container* container)
-    {
-        // An AbsoluteLayout does nothing to modify the layout of Controls.
-        std::vector<Control*> controls = container->getControls();
-        unsigned int controlsCount = controls.size();
-        for (unsigned int i = 0; i < controlsCount; i++)
+        if (control->isDirty() || control->isContainer())
         {
         {
-            Control* control = controls[i];
-
-            if (control->isDirty() || control->isContainer())
-            {
-                align(control, container);
-                control->update(container->getClip(), Vector2::zero());
-            }
+            align(control, container);
+            control->update(container->getClip(), Vector2::zero());
         }
         }
     }
     }
+}
+
 }
 }

+ 30 - 30
gameplay/src/Button.cpp

@@ -3,41 +3,41 @@
 
 
 namespace gameplay
 namespace gameplay
 {
 {
-    Button::Button()
-    {
-    }
 
 
-    Button::~Button()
-    {
-    }
+Button::Button()
+{
+}
 
 
-    Button* Button::create(Theme::Style* style, Properties* properties)
-    {
-        Button* button = new Button();
-        button->initialize(style, properties);
+Button::~Button()
+{
+}
 
 
-        return button;
+Button* Button::create(Theme::Style* style, Properties* properties)
+{
+    Button* button = new Button();
+    button->initialize(style, properties);
+
+    return button;
+}
+
+bool Button::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+{
+    if (!isEnabled())
+    {
+        return false;
     }
     }
 
 
-    bool Button::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+    switch (evt)
     {
     {
-        if (!isEnabled())
-        {
-            return false;
-        }
-
-        switch (evt)
-        {
-        case Touch::TOUCH_PRESS:
-            _state = Control::ACTIVE;
-            _dirty = true;
-            break;
-        case Touch::TOUCH_RELEASE:
-            _dirty = true;
-            setState(Control::NORMAL);
-            break;
-        }
-
-        return Control::touchEvent(evt, x, y, contactIndex);
+    case Touch::TOUCH_PRESS:
+        setState(Control::ACTIVE);
+        break;
+    case Touch::TOUCH_RELEASE:
+        setState(Control::NORMAL);
+        break;
     }
     }
+
+    return Control::touchEvent(evt, x, y, contactIndex);
+}
+
 }
 }

+ 2 - 1
gameplay/src/CheckBox.cpp

@@ -39,6 +39,7 @@ void CheckBox::setChecked(bool checked)
     if (_checked != checked)
     if (_checked != checked)
     {
     {
         _checked = checked;
         _checked = checked;
+        _dirty = true;
         notifyListeners(Control::Listener::VALUE_CHANGED);
         notifyListeners(Control::Listener::VALUE_CHANGED);
     }
     }
 }
 }
@@ -150,7 +151,7 @@ void CheckBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
 
 
     Vector2 pos(_viewportBounds.x, _viewportBounds.y + _viewportBounds.height * 0.5f - size.y * 0.5f);
     Vector2 pos(_viewportBounds.x, _viewportBounds.y + _viewportBounds.height * 0.5f - size.y * 0.5f);
 
 
-    spriteBatch->draw(pos.x, pos.y, size.x, size.y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _clip);
+    spriteBatch->draw(pos.x, pos.y, size.x, size.y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
 }
 }
 
 
 }
 }

+ 347 - 337
gameplay/src/Container.cpp

@@ -15,450 +15,460 @@
 
 
 namespace gameplay
 namespace gameplay
 {
 {
-    Container::Container() : _layout(NULL)
-    {
-    }
 
 
-    Container::Container(const Container& copy)
-    {
-    }
+Container::Container() : _layout(NULL)
+{
+}
 
 
-    Container::~Container()
-    {
-        std::vector<Control*>::iterator it;
-        for (it = _controls.begin(); it < _controls.end(); it++)
-        {
-            SAFE_RELEASE((*it));
-        }
+Container::Container(const Container& copy)
+{
+}
 
 
-        SAFE_RELEASE(_layout);
+Container::~Container()
+{
+    std::vector<Control*>::iterator it;
+    for (it = _controls.begin(); it < _controls.end(); it++)
+    {
+        SAFE_RELEASE((*it));
     }
     }
 
 
-    Container* Container::create(Layout::Type type)
+    SAFE_RELEASE(_layout);
+}
+
+Container* Container::create(Layout::Type type)
+{
+    Layout* layout = NULL;
+    switch (type)
     {
     {
-        Layout* layout = NULL;
-        switch (type)
-        {
-        case Layout::LAYOUT_ABSOLUTE:
-            layout = AbsoluteLayout::create();
-            break;
-        case Layout::LAYOUT_FLOW:
-            layout = FlowLayout::create();
-            break;
-        case Layout::LAYOUT_VERTICAL:
-            layout = VerticalLayout::create();
-            break;
-        case Layout::LAYOUT_SCROLL:
-            layout = ScrollLayout::create();
-            break;
-        }
+    case Layout::LAYOUT_ABSOLUTE:
+        layout = AbsoluteLayout::create();
+        break;
+    case Layout::LAYOUT_FLOW:
+        layout = FlowLayout::create();
+        break;
+    case Layout::LAYOUT_VERTICAL:
+        layout = VerticalLayout::create();
+        break;
+    case Layout::LAYOUT_SCROLL:
+        layout = ScrollLayout::create();
+        break;
+    }
 
 
-        Container* container = new Container();
-        container->_layout = layout;
+    Container* container = new Container();
+    container->_layout = layout;
 
 
-        return container;
-    }
+    return container;
+}
 
 
-    Container* Container::create(Theme::Style* style, Properties* properties, Theme* theme)
-    {
-        const char* layoutString = properties->getString("layout");
-        Container* container = Container::create(getLayoutType(layoutString));
-        container->initialize(style, properties);
-        container->addControls(theme, properties);
+Container* Container::create(Theme::Style* style, Properties* properties, Theme* theme)
+{
+    const char* layoutString = properties->getString("layout");
+    Container* container = Container::create(getLayoutType(layoutString));
+    container->initialize(style, properties);
+    container->addControls(theme, properties);
 
 
-        return container;
-    }
+    return container;
+}
 
 
-    void Container::addControls(Theme* theme, Properties* properties)
+void Container::addControls(Theme* theme, Properties* properties)
+{
+    // Add all the controls to this container.
+    Properties* controlSpace = properties->getNextNamespace();
+    while (controlSpace != NULL)
     {
     {
-        // Add all the controls to this container.
-        Properties* controlSpace = properties->getNextNamespace();
-        while (controlSpace != NULL)
-        {
-            Control* control = NULL;
-
-            const char* controlStyleName = controlSpace->getString("style");
-            Theme::Style* controlStyle = NULL;
-            if (controlStyleName)
-            {
-                 controlStyle = theme->getStyle(controlStyleName);
-            }
-            assert(controlStyle);
+        Control* control = NULL;
 
 
-            std::string controlName(controlSpace->getNamespace());
-            std::transform(controlName.begin(), controlName.end(), controlName.begin(), (int(*)(int))toupper);
-            if (controlName == "LABEL")
-            {
-                control = Label::create(controlStyle, controlSpace);
-            }
-            else if (controlName == "BUTTON")
-            {
-                control = Button::create(controlStyle, controlSpace);
-            }
-            else if (controlName == "CHECKBOX")
-            {
-                control = CheckBox::create(controlStyle, controlSpace);
-            }
-            else if (controlName == "RADIOBUTTON")
-            {
-                control = RadioButton::create(controlStyle, controlSpace);
-            }
-            else if (controlName == "CONTAINER")
-            {
-                control = Container::create(controlStyle, controlSpace, theme);
-            }
-            else if (controlName == "SLIDER")
-            {
-                control = Slider::create(controlStyle, controlSpace);
-            }
-            else if (controlName == "TEXTBOX")
-            {
-                control = TextBox::create(controlStyle, controlSpace);
-            }
+        const char* controlStyleName = controlSpace->getString("style");
+        Theme::Style* controlStyle = NULL;
+        if (controlStyleName)
+        {
+                controlStyle = theme->getStyle(controlStyleName);
+        }
+        assert(controlStyle);
 
 
-            // Add the new control to the form.
-            if (control)
-            {
-                addControl(control);
-            }
+        std::string controlName(controlSpace->getNamespace());
+        std::transform(controlName.begin(), controlName.end(), controlName.begin(), (int(*)(int))toupper);
+        if (controlName == "LABEL")
+        {
+            control = Label::create(controlStyle, controlSpace);
+        }
+        else if (controlName == "BUTTON")
+        {
+            control = Button::create(controlStyle, controlSpace);
+        }
+        else if (controlName == "CHECKBOX")
+        {
+            control = CheckBox::create(controlStyle, controlSpace);
+        }
+        else if (controlName == "RADIOBUTTON")
+        {
+            control = RadioButton::create(controlStyle, controlSpace);
+        }
+        else if (controlName == "CONTAINER")
+        {
+            control = Container::create(controlStyle, controlSpace, theme);
+        }
+        else if (controlName == "SLIDER")
+        {
+            control = Slider::create(controlStyle, controlSpace);
+        }
+        else if (controlName == "TEXTBOX")
+        {
+            control = TextBox::create(controlStyle, controlSpace);
+        }
 
 
-            // Get the next control.
-            controlSpace = properties->getNextNamespace();
+        // Add the new control to the form.
+        if (control)
+        {
+            addControl(control);
         }
         }
-    }
 
 
-    Layout* Container::getLayout()
-    {
-        return _layout;
+        // Get the next control.
+        controlSpace = properties->getNextNamespace();
     }
     }
+}
 
 
-    unsigned int Container::addControl(Control* control)
-    {
-        _controls.push_back(control);
+Layout* Container::getLayout()
+{
+    return _layout;
+}
 
 
-        return _controls.size() - 1;
-    }
+unsigned int Container::addControl(Control* control)
+{
+    _controls.push_back(control);
 
 
-    void Container::insertControl(Control* control, unsigned int index)
-    {
-        std::vector<Control*>::iterator it = _controls.begin() + index;
-        _controls.insert(it, control);
-    }
+    return _controls.size() - 1;
+}
 
 
-    void Container::removeControl(unsigned int index)
-    {
-        std::vector<Control*>::iterator it = _controls.begin() + index;
-        _controls.erase(it);
-    }
+void Container::insertControl(Control* control, unsigned int index)
+{
+    std::vector<Control*>::iterator it = _controls.begin() + index;
+    _controls.insert(it, control);
+}
 
 
-    void Container::removeControl(const char* id)
+void Container::removeControl(unsigned int index)
+{
+    std::vector<Control*>::iterator it = _controls.begin() + index;
+    _controls.erase(it);
+}
+
+void Container::removeControl(const char* id)
+{
+    std::vector<Control*>::iterator it;
+    for (it = _controls.begin(); it < _controls.end(); it++)
     {
     {
-        std::vector<Control*>::iterator it;
-        for (it = _controls.begin(); it < _controls.end(); it++)
+        Control* c = *it;
+        if (strcmp(id, c->getID()) == 0)
         {
         {
-            Control* c = *it;
-            if (strcmp(id, c->getID()) == 0)
-            {
-                _controls.erase(it);
-            }
+            _controls.erase(it);
         }
         }
     }
     }
+}
 
 
-    void Container::removeControl(Control* control)
+void Container::removeControl(Control* control)
+{
+    std::vector<Control*>::iterator it;
+    for (it = _controls.begin(); it < _controls.end(); it++)
     {
     {
-        std::vector<Control*>::iterator it;
-        for (it = _controls.begin(); it < _controls.end(); it++)
+        if (*it == control)
         {
         {
-            if (*it == control)
-            {
-                _controls.erase(it);
-            }
+            _controls.erase(it);
         }
         }
     }
     }
+}
 
 
-    Control* Container::getControl(unsigned int index) const
-    {
-        std::vector<Control*>::const_iterator it = _controls.begin() + index;
-        return *it;
-    }
+Control* Container::getControl(unsigned int index) const
+{
+    std::vector<Control*>::const_iterator it = _controls.begin() + index;
+    return *it;
+}
 
 
-    Control* Container::getControl(const char* id) const
+Control* Container::getControl(const char* id) const
+{
+    std::vector<Control*>::const_iterator it;
+    for (it = _controls.begin(); it < _controls.end(); it++)
     {
     {
-        std::vector<Control*>::const_iterator it;
-        for (it = _controls.begin(); it < _controls.end(); it++)
+        Control* c = *it;
+        if (strcmp(id, c->getID()) == 0)
         {
         {
-            Control* c = *it;
-            if (strcmp(id, c->getID()) == 0)
-            {
-                return c;
-            }
-            else if (c->isContainer())
+            return c;
+        }
+        else if (c->isContainer())
+        {
+            Control* cc = ((Container*)c)->getControl(id);
+            if (cc)
             {
             {
-                Control* cc = ((Container*)c)->getControl(id);
-                if (cc)
-                {
-                    return cc;
-                }
+                return cc;
             }
             }
         }
         }
-
-        return NULL;
     }
     }
 
 
-    std::vector<Control*> Container::getControls() const
-    {
-        return _controls;
-    }
+    return NULL;
+}
 
 
-    Animation* Container::getAnimation(const char* id) const
-    {
-        std::vector<Control*>::const_iterator itr = _controls.begin();
-        std::vector<Control*>::const_iterator end = _controls.end();
+std::vector<Control*> Container::getControls() const
+{
+    return _controls;
+}
+
+Animation* Container::getAnimation(const char* id) const
+{
+    std::vector<Control*>::const_iterator itr = _controls.begin();
+    std::vector<Control*>::const_iterator end = _controls.end();
         
         
-        Control* control = NULL;
-        for (; itr != end; itr++)
+    Control* control = NULL;
+    for (; itr != end; itr++)
+    {
+        control = *itr;
+        Animation* animation = control->getAnimation(id);
+        if (animation)
+            return animation;
+
+        if (control->isContainer())
         {
         {
-            control = *itr;
-            Animation* animation = control->getAnimation(id);
+            animation = ((Container*)control)->getAnimation(id);
             if (animation)
             if (animation)
                 return animation;
                 return animation;
-
-            if (control->isContainer())
-            {
-                animation = ((Container*)control)->getAnimation(id);
-                if (animation)
-                    return animation;
-            }
         }
         }
-
-        return NULL;
     }
     }
 
 
-    void Container::update(const Rectangle& clip, const Vector2& offset)
-    {
-        // Update this container's viewport.
-        Control::update(clip, offset);
+    return NULL;
+}
 
 
-        _layout->update(this);
-    }
-    /*
-    void Container::drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip, const Vector2& offset)
-    {
-        // First draw our own border.
-        Control::drawBorder(spriteBatch, clip);
+void Container::update(const Rectangle& clip, const Vector2& offset)
+{
+    // Update this container's viewport.
+    Control::update(clip, offset);
 
 
-        // Now call drawBorder on all controls within this container.
-        std::vector<Control*>::const_iterator it;
-        for (it = _controls.begin(); it < _controls.end(); it++)
-        {
-            Control* control = *it;
-            if (control->isDirty())
-            {
-                control->drawBorder(spriteBatch, _clip);
-            }
-        }
-    }
+    _layout->update(this);
+}
+/*
+void Container::drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip, const Vector2& offset)
+{
+    // First draw our own border.
+    Control::drawBorder(spriteBatch, clip);
 
 
-    void Container::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
+    // Now call drawBorder on all controls within this container.
+    std::vector<Control*>::const_iterator it;
+    for (it = _controls.begin(); it < _controls.end(); it++)
     {
     {
-        std::vector<Control*>::const_iterator it;
-        for (it = _controls.begin(); it < _controls.end(); it++)
+        Control* control = *it;
+        if (control->isDirty())
         {
         {
-            Control* control = *it;
-            if (control->isDirty())
-                control->drawImages(spriteBatch, _clip);
+            control->drawBorder(spriteBatch, _viewportClipBounds);
         }
         }
+    }
+}
 
 
-        _dirty = false;
+void Container::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
+{
+    std::vector<Control*>::const_iterator it;
+    for (it = _controls.begin(); it < _controls.end(); it++)
+    {
+        Control* control = *it;
+        if (control->isDirty())
+            control->drawImages(spriteBatch, _viewportClipBounds);
     }
     }
 
 
-    void Container::drawText(const Rectangle& clip)
+    _dirty = false;
+}
+
+void Container::drawText(const Rectangle& clip)
+{
+    std::vector<Control*>::const_iterator it;
+    for (it = _controls.begin(); it < _controls.end(); it++)
     {
     {
-        std::vector<Control*>::const_iterator it;
-        for (it = _controls.begin(); it < _controls.end(); it++)
-        {
-            Control* control = *it;
-            if (control->isDirty())
-                control->drawText(_clip);
-        }
+        Control* control = *it;
+        if (control->isDirty())
+            control->drawText(_viewportClipBounds);
+    }
 
 
-        _dirty = false;
-    }*/
+    _dirty = false;
+}*/
 
 
-    void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip)
+void Container::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, float targetHeight)
+{
+    if (_skin && needsClear)
     {
     {
         GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
         GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
         GL_ASSERT( glClearColor(0, 0, 0, 1) );
         GL_ASSERT( glClearColor(0, 0, 0, 1) );
-        GL_ASSERT( glScissor(_absoluteBounds.x, Game::getInstance()->getHeight() - _absoluteBounds.y - _absoluteBounds.height,
-            _absoluteBounds.width, _absoluteBounds.height) );
+        float clearY = targetHeight - _clearBounds.y - _clearBounds.height;
+        GL_ASSERT( glScissor(_clearBounds.x, clearY,
+            _clearBounds.width, _clearBounds.height) );
         GL_ASSERT( glClear(GL_COLOR_BUFFER_BIT) );
         GL_ASSERT( glClear(GL_COLOR_BUFFER_BIT) );
         GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
         GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
 
 
-        Control::drawBorder(spriteBatch, clip);
+        needsClear = false;
+    }
 
 
-        std::vector<Control*>::const_iterator it;
-        for (it = _controls.begin(); it < _controls.end(); it++)
+    Control::drawBorder(spriteBatch, clip);
+
+    std::vector<Control*>::const_iterator it;
+    Rectangle boundsUnion = Rectangle::empty();
+    for (it = _controls.begin(); it < _controls.end(); it++)
+    {
+        Control* control = *it;
+        if (!needsClear || control->isDirty() || control->_clearBounds.intersects(boundsUnion))
         {
         {
-            Control* control = *it;
-            //if (control->isDirty())
-            {
-                control->draw(spriteBatch, _clip);
-            }
+            control->draw(spriteBatch, _viewportClipBounds, needsClear, targetHeight);
+            Rectangle::combine(control->_clearBounds, boundsUnion, &boundsUnion);
         }
         }
-
-        _dirty = false;
     }
     }
 
 
-    bool Container::isDirty()
+    _dirty = false;
+}
+
+bool Container::isDirty()
+{
+    if (_dirty)
     {
     {
-        if (_dirty)
-        {
-            return true;
-        }
-        else
+        return true;
+    }
+    else
+    {
+        std::vector<Control*>::const_iterator it;
+        for (it = _controls.begin(); it < _controls.end(); it++)
         {
         {
-            std::vector<Control*>::const_iterator it;
-            for (it = _controls.begin(); it < _controls.end(); it++)
+            if ((*it)->isDirty())
             {
             {
-                if ((*it)->isDirty())
-                {
-                    return true;
-                }
+                return true;
             }
             }
         }
         }
-
-        return false;
     }
     }
 
 
-    bool Container::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-    {
-        if (!isEnabled())
-        {
-            return false;
-        }
+    return false;
+}
 
 
-        bool eventConsumed = false;
+bool Container::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+{
+    if (!isEnabled())
+    {
+        return false;
+    }
 
 
-        const Theme::Border& border = getBorder(_state);
-        const Theme::Padding& padding = getPadding();
-        float xPos = border.left + padding.left;
-        float yPos = border.top + padding.top;
+    bool eventConsumed = false;
 
 
-        Vector2* offset = NULL;
-        if (_layout->getType() == Layout::LAYOUT_SCROLL)
-        {
-            offset = &((ScrollLayout*)_layout)->_scrollPosition;
-        }
+    const Theme::Border& border = getBorder(_state);
+    const Theme::Padding& padding = getPadding();
+    float xPos = border.left + padding.left;
+    float yPos = border.top + padding.top;
 
 
-        std::vector<Control*>::const_iterator it;
-        for (it = _controls.begin(); it < _controls.end(); it++)
-        {
-            Control* control = *it;
-            if (!control->isEnabled())
-            {
-                continue;
-            }
-
-            const Rectangle& bounds = control->getBounds();
-            float boundsX = bounds.x;
-            float boundsY = bounds.y;
-            if (offset)
-            {
-                boundsX += offset->x;
-                boundsY += offset->y;
-            }
-
-            if (control->getState() != Control::NORMAL ||
-                (evt == Touch::TOUCH_PRESS &&
-                 x >= xPos + boundsX &&
-                 x <= xPos + boundsX + bounds.width &&
-                 y >= yPos + boundsY &&
-                 y <= yPos + boundsY + bounds.height))
-            {
-                // Pass on the event's clip relative to the control.
-                eventConsumed |= control->touchEvent(evt, x - xPos - boundsX, y - yPos - boundsY, contactIndex);
-            }
-        }
+    Vector2* offset = NULL;
+    if (_layout->getType() == Layout::LAYOUT_SCROLL)
+    {
+        offset = &((ScrollLayout*)_layout)->_scrollPosition;
+    }
 
 
-        if (!isEnabled())
+    std::vector<Control*>::const_iterator it;
+    for (it = _controls.begin(); it < _controls.end(); it++)
+    {
+        Control* control = *it;
+        if (!control->isEnabled())
         {
         {
-            return (_consumeTouchEvents | eventConsumed);
+            continue;
         }
         }
 
 
-        switch (evt)
+        const Rectangle& bounds = control->getBounds();
+        float boundsX = bounds.x;
+        float boundsY = bounds.y;
+        if (offset)
         {
         {
-        case Touch::TOUCH_PRESS:
-            setState(Control::FOCUS);
-            break;
-        case Touch::TOUCH_RELEASE:
-            setState(Control::NORMAL);
-            break;
+            boundsX += offset->x;
+            boundsY += offset->y;
         }
         }
 
 
-        if (!eventConsumed)
+        if (control->getState() != Control::NORMAL ||
+            (evt == Touch::TOUCH_PRESS &&
+                x >= xPos + boundsX &&
+                x <= xPos + boundsX + bounds.width &&
+                y >= yPos + boundsY &&
+                y <= yPos + boundsY + bounds.height))
         {
         {
-            // Pass the event on to the layout.
-            if (_layout->touchEvent(evt, x - xPos, y - yPos, contactIndex))
-            {
-                _dirty = true;
-            }
+            // Pass on the event's clip relative to the control.
+            eventConsumed |= control->touchEvent(evt, x - xPos - boundsX, y - yPos - boundsY, contactIndex);
         }
         }
-
-        return (_consumeTouchEvents | eventConsumed);
     }
     }
 
 
-    void Container::keyEvent(Keyboard::KeyEvent evt, int key)
+    if (!isEnabled())
     {
     {
-        std::vector<Control*>::const_iterator it;
-        for (it = _controls.begin(); it < _controls.end(); it++)
-        {
-            Control* control = *it;
-            if (!control->isEnabled())
-            {
-                continue;
-            }
-
-            if (control->isContainer() || control->getState() == Control::FOCUS)
-            {
-                control->keyEvent(evt, key);
-            }
-        }
+        return (_consumeTouchEvents | eventConsumed);
     }
     }
 
 
-    bool Container::isContainer()
+    switch (evt)
     {
     {
-        return true;
+    case Touch::TOUCH_PRESS:
+        setState(Control::FOCUS);
+        break;
+    case Touch::TOUCH_RELEASE:
+        setState(Control::NORMAL);
+        break;
     }
     }
 
 
-    Layout::Type Container::getLayoutType(const char* layoutString)
+    if (!eventConsumed)
     {
     {
-        if (!layoutString)
+        // Pass the event on to the layout.
+        if (_layout->touchEvent(evt, x - xPos, y - yPos, contactIndex))
         {
         {
-            return Layout::LAYOUT_ABSOLUTE;
+            _dirty = true;
         }
         }
+    }
 
 
-        std::string layoutName(layoutString);
-        std::transform(layoutName.begin(), layoutName.end(), layoutName.begin(), (int(*)(int))toupper);
-        if (layoutName == "LAYOUT_ABSOLUTE")
-        {
-            return Layout::LAYOUT_ABSOLUTE;
-        }
-        else if (layoutName == "LAYOUT_VERTICAL")
-        {
-            return Layout::LAYOUT_VERTICAL;
-        }
-        else if (layoutName == "LAYOUT_FLOW")
-        {
-            return Layout::LAYOUT_FLOW;
-        }
-        else if (layoutName == "LAYOUT_SCROLL")
+    return (_consumeTouchEvents | eventConsumed);
+}
+
+void Container::keyEvent(Keyboard::KeyEvent evt, int key)
+{
+    std::vector<Control*>::const_iterator it;
+    for (it = _controls.begin(); it < _controls.end(); it++)
+    {
+        Control* control = *it;
+        if (!control->isEnabled())
         {
         {
-            return Layout::LAYOUT_SCROLL;
+            continue;
         }
         }
-        else
+
+        if (control->isContainer() || control->getState() == Control::FOCUS)
         {
         {
-            // Default.
-            return Layout::LAYOUT_ABSOLUTE;
+            control->keyEvent(evt, key);
         }
         }
     }
     }
 }
 }
+
+bool Container::isContainer()
+{
+    return true;
+}
+
+Layout::Type Container::getLayoutType(const char* layoutString)
+{
+    if (!layoutString)
+    {
+        return Layout::LAYOUT_ABSOLUTE;
+    }
+
+    std::string layoutName(layoutString);
+    std::transform(layoutName.begin(), layoutName.end(), layoutName.begin(), (int(*)(int))toupper);
+    if (layoutName == "LAYOUT_ABSOLUTE")
+    {
+        return Layout::LAYOUT_ABSOLUTE;
+    }
+    else if (layoutName == "LAYOUT_VERTICAL")
+    {
+        return Layout::LAYOUT_VERTICAL;
+    }
+    else if (layoutName == "LAYOUT_FLOW")
+    {
+        return Layout::LAYOUT_FLOW;
+    }
+    else if (layoutName == "LAYOUT_SCROLL")
+    {
+        return Layout::LAYOUT_SCROLL;
+    }
+    else
+    {
+        // Default.
+        return Layout::LAYOUT_ABSOLUTE;
+    }
+}
+
+}

+ 1 - 1
gameplay/src/Container.h

@@ -245,7 +245,7 @@ private:
 
 
     Container(const Container& copy);
     Container(const Container& copy);
 
 
-    virtual void draw(SpriteBatch* spriteBatch, const Rectangle& clip);
+    virtual void draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, float targetHeight);
 };
 };
 
 
 }
 }

+ 930 - 899
gameplay/src/Control.cpp

@@ -4,1172 +4,1203 @@
 
 
 namespace gameplay
 namespace gameplay
 {
 {
-    Control::Control()
-        : _id(""), _state(Control::NORMAL), _bounds(Rectangle::empty()), _clipBounds(Rectangle::empty()), _clip(Rectangle::empty()),
-            _dirty(true), _consumeTouchEvents(true), _listeners(NULL), _styleOverridden(false)
-    {
-    }
 
 
-    Control::Control(const Control& copy)
-    {
-    }
+Control::Control()
+    : _id(""), _state(Control::NORMAL), _bounds(Rectangle::empty()), _clipBounds(Rectangle::empty()), _viewportClipBounds(Rectangle::empty()),
+        _dirty(true), _consumeTouchEvents(true), _listeners(NULL), _styleOverridden(false)
+{
+}
+
+Control::Control(const Control& copy)
+{
+}
 
 
-    Control::~Control()
+Control::~Control()
+{
+    if (_listeners)
     {
     {
-        if (_listeners)
+        for (std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->begin(); itr != _listeners->end(); itr++)
         {
         {
-            for (std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->begin(); itr != _listeners->end(); itr++)
-            {
-                std::list<Listener*>* list = itr->second;
-                SAFE_DELETE(list);
-            }
-            SAFE_DELETE(_listeners);
+            std::list<Listener*>* list = itr->second;
+            SAFE_DELETE(list);
         }
         }
+        SAFE_DELETE(_listeners);
+    }
 
 
-        if (_styleOverridden)
-        {
-            SAFE_DELETE(_style);
-        }
+    if (_styleOverridden)
+    {
+        SAFE_DELETE(_style);
     }
     }
+}
+
+void Control::initialize(Theme::Style* style, Properties* properties)
+{
+    _style = style;
+
+    // Properties not defined by the style.
+    _alignment = getAlignment(properties->getString("alignment"));
+    _autoWidth = properties->getBool("autoWidth");
+    _autoHeight = properties->getBool("autoHeight");
 
 
-    void Control::initialize(Theme::Style* style, Properties* properties)
+    Vector2 position;
+    Vector2 size;
+    if (properties->exists("position"))
+    {
+        properties->getVector2("position", &position);
+    }
+    else
+    {
+        position.x = properties->getFloat("x");
+        position.y = properties->getFloat("y");
+    }
+        
+    if (properties->exists("size"))
+    {
+        properties->getVector2("size", &size);
+    }
+    else
     {
     {
-        _style = style;
+        size.x = properties->getFloat("width");
+        size.y = properties->getFloat("height");
+    }
+    _bounds.set(position.x, position.y, size.x, size.y);
 
 
-        // Properties not defined by the style.
-        _alignment = getAlignment(properties->getString("alignment"));
-        _autoWidth = properties->getBool("autoWidth");
-        _autoHeight = properties->getBool("autoHeight");
+    _state = Control::getState(properties->getString("state"));
 
 
-        Vector2 position;
-        Vector2 size;
-        if (properties->exists("position"))
+    const char* id = properties->getId();
+    if (id)
+        _id = id;
+
+    // Potentially override themed properties for all states.
+    overrideThemedProperties(properties, STATE_ALL);
+
+    // Override themed properties on specific states.
+    Properties* innerSpace = properties->getNextNamespace();
+    while (innerSpace != NULL)
+    {
+        std::string spaceName(innerSpace->getNamespace());
+        std::transform(spaceName.begin(), spaceName.end(), spaceName.begin(), (int(*)(int))toupper);
+        if (spaceName == "STATENORMAL")
         {
         {
-            properties->getVector2("position", &position);
+            overrideThemedProperties(innerSpace, NORMAL);
         }
         }
-        else
+        else if (spaceName == "STATEFOCUS")
         {
         {
-            position.x = properties->getFloat("x");
-            position.y = properties->getFloat("y");
+            overrideThemedProperties(innerSpace, FOCUS);
         }
         }
-        
-        if (properties->exists("size"))
+        else if (spaceName == "STATEACTIVE")
         {
         {
-            properties->getVector2("size", &size);
+            overrideThemedProperties(innerSpace, ACTIVE);
         }
         }
-        else
+        else if (spaceName == "STATEDISABLED")
         {
         {
-            size.x = properties->getFloat("width");
-            size.y = properties->getFloat("height");
+            overrideThemedProperties(innerSpace, DISABLED);
         }
         }
-        _bounds.set(position.x, position.y, size.x, size.y);
-
-        _state = Control::getState(properties->getString("state"));
-
-        const char* id = properties->getId();
-        if (id)
-            _id = id;
-
-        // Potentially override themed properties for all states.
-        overrideThemedProperties(properties, STATE_ALL);
-
-        // Override themed properties on specific states.
-        Properties* innerSpace = properties->getNextNamespace();
-        while (innerSpace != NULL)
+        else if (spaceName == "MARGIN")
         {
         {
-            std::string spaceName(innerSpace->getNamespace());
-            std::transform(spaceName.begin(), spaceName.end(), spaceName.begin(), (int(*)(int))toupper);
-            if (spaceName == "STATENORMAL")
-            {
-                overrideThemedProperties(innerSpace, NORMAL);
-            }
-            else if (spaceName == "STATEFOCUS")
-            {
-                overrideThemedProperties(innerSpace, FOCUS);
-            }
-            else if (spaceName == "STATEACTIVE")
-            {
-                overrideThemedProperties(innerSpace, ACTIVE);
-            }
-            else if (spaceName == "STATEDISABLED")
-            {
-                overrideThemedProperties(innerSpace, DISABLED);
-            }
-            else if (spaceName == "MARGIN")
-            {
-                setMargin(innerSpace->getFloat("top"), innerSpace->getFloat("bottom"),
-                    innerSpace->getFloat("left"), innerSpace->getFloat("right"));
-            }
-            else if (spaceName == "PADDING")
-            {
-                setPadding(innerSpace->getFloat("top"), innerSpace->getFloat("bottom"),
-                    innerSpace->getFloat("left"), innerSpace->getFloat("right"));
-            }
-
-            innerSpace = properties->getNextNamespace();
+            setMargin(innerSpace->getFloat("top"), innerSpace->getFloat("bottom"),
+                innerSpace->getFloat("left"), innerSpace->getFloat("right"));
+        }
+        else if (spaceName == "PADDING")
+        {
+            setPadding(innerSpace->getFloat("top"), innerSpace->getFloat("bottom"),
+                innerSpace->getFloat("left"), innerSpace->getFloat("right"));
         }
         }
-    }
 
 
-    const char* Control::getID() const
-    {
-        return _id.c_str();
+        innerSpace = properties->getNextNamespace();
     }
     }
+}
+
+const char* Control::getID() const
+{
+    return _id.c_str();
+}
 
 
-    void Control::setPosition(float x, float y)
+void Control::setPosition(float x, float y)
+{
+    if (x != _bounds.x || y != _bounds.y)
     {
     {
         _bounds.x = x;
         _bounds.x = x;
         _bounds.y = y;
         _bounds.y = y;
         _dirty = true;
         _dirty = true;
     }
     }
+}
 
 
-    void Control::setSize(float width, float height)
+void Control::setSize(float width, float height)
+{
+    if (width != _bounds.width || height != _bounds.height)
     {
     {
         _bounds.width = width;
         _bounds.width = width;
         _bounds.height = height;
         _bounds.height = height;
         _dirty = true;
         _dirty = true;
     }
     }
+}
 
 
-    void Control::setBounds(const Rectangle& bounds)
-    {
-        _bounds.set(bounds);
-    }
+void Control::setBounds(const Rectangle& bounds)
+{
+    _bounds.set(bounds);
+}
 
 
-    const Rectangle& Control::getBounds() const
-    {
-        return _bounds;
-    }
+const Rectangle& Control::getBounds() const
+{
+    return _bounds;
+}
 
 
-    float Control::getX() const
-    {
-        return _bounds.x;
-    }
+float Control::getX() const
+{
+    return _bounds.x;
+}
 
 
-    float Control::getY() const
-    {
-        return _bounds.y;
-    }
+float Control::getY() const
+{
+    return _bounds.y;
+}
 
 
-    float Control::getWidth() const
-    {
-        return _bounds.width;
-    }
+float Control::getWidth() const
+{
+    return _bounds.width;
+}
 
 
-    float Control::getHeight() const
-    {
-        return _bounds.height;
-    }
+float Control::getHeight() const
+{
+    return _bounds.height;
+}
 
 
-    void Control::setAlignment(Alignment alignment)
-    {
-        _alignment = alignment;
-    }
+void Control::setAlignment(Alignment alignment)
+{
+    _alignment = alignment;
+}
 
 
-    Control::Alignment Control::getAlignment() const
-    {
-        return _alignment;
-    }
+Control::Alignment Control::getAlignment() const
+{
+    return _alignment;
+}
 
 
-    void Control::setAutoWidth(bool autoWidth)
-    {
-        _autoWidth = autoWidth;
-    }
+void Control::setAutoWidth(bool autoWidth)
+{
+    _autoWidth = autoWidth;
+}
 
 
-    bool Control::getAutoWidth() const
-    {
-        return _autoWidth;
-    }
+bool Control::getAutoWidth() const
+{
+    return _autoWidth;
+}
+
+void Control::setAutoHeight(bool autoHeight)
+{
+    _autoHeight = autoHeight;
+}
 
 
-    void Control::setAutoHeight(bool autoHeight)
+void Control::setOpacity(float opacity, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
+
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        _autoHeight = autoHeight;
+        overlays[i]->setOpacity(opacity);
     }
     }
+        
+    _dirty = true;
+}
 
 
-    void Control::setOpacity(float opacity, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+float Control::getOpacity(State state) const
+{
+    return getOverlay(state)->getOpacity();
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setOpacity(opacity);
-        }
-        
-        _dirty = true;
-    }
+void Control::setBorder(float top, float bottom, float left, float right, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-    float Control::getOpacity(State state) const
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        return getOverlay(state)->getOpacity();
+        overlays[i]->setBorder(top, bottom, left, right);
     }
     }
 
 
-    void Control::setBorder(float top, float bottom, float left, float right, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setBorder(top, bottom, left, right);
-        }
+const Theme::Border& Control::getBorder(State state) const
+{
+    return getOverlay(state)->getBorder();
+}
 
 
-        _dirty = true;
-    }
+void Control::setSkinRegion(const Rectangle& region, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-    const Theme::Border& Control::getBorder(State state) const
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        return getOverlay(state)->getBorder();
+        overlays[i]->setSkinRegion(region, _style->_tw, _style->_th);
     }
     }
 
 
-    void Control::setSkinRegion(const Rectangle& region, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setSkinRegion(region, _style->_tw, _style->_th);
-        }
+const Rectangle& Control::getSkinRegion(State state) const
+{
+    return getOverlay(state)->getSkinRegion();
+}
 
 
-        _dirty = true;
-    }
+const Theme::UVs& Control::getSkinUVs(Theme::Skin::SkinArea area, State state) const
+{
+    return getOverlay(state)->getSkinUVs(area);
+}
 
 
-    const Rectangle& Control::getSkinRegion(State state) const
-    {
-        return getOverlay(state)->getSkinRegion();
-    }
+void Control::setSkinColor(const Vector4& color, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-    const Theme::UVs& Control::getSkinUVs(Theme::Skin::SkinArea area, State state) const
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        return getOverlay(state)->getSkinUVs(area);
+        overlays[i]->setSkinColor(color);
     }
     }
 
 
-    void Control::setSkinColor(const Vector4& color, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setSkinColor(color);
-        }
+const Vector4& Control::getSkinColor(State state) const
+{
+    return getOverlay(state)->getSkinColor();
+}
 
 
-        _dirty = true;
-    }
+void Control::setMargin(float top, float bottom, float left, float right)
+{
+    overrideStyle();
+    _style->setMargin(top, bottom, left, right);
+    _dirty = true;
+}
 
 
-    const Vector4& Control::getSkinColor(State state) const
-    {
-        return getOverlay(state)->getSkinColor();
-    }
+const Theme::Margin& Control::getMargin() const
+{
+    return _style->getMargin();
+}
 
 
-    void Control::setMargin(float top, float bottom, float left, float right)
-    {
-        _style->setMargin(top, bottom, left, right);
-        _dirty = true;
-    }
+void Control::setPadding(float top, float bottom, float left, float right)
+{
+    overrideStyle();
+    _style->setPadding(top, bottom, left, right);
+    _dirty = true;
+}
+    
+const Theme::Padding& Control::getPadding() const
+{
+    return _style->getPadding();
+}
 
 
-    const Theme::Margin& Control::getMargin() const
-    {
-        return _style->getMargin();
-    }
+void Control::setImageRegion(const char* id, const Rectangle& region, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-    void Control::setPadding(float top, float bottom, float left, float right)
-    {
-        _style->setPadding(top, bottom, left, right);
-        _dirty = true;
-    }
-    
-    const Theme::Padding& Control::getPadding() const
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        return _style->getPadding();
+        overlays[i]->setImageRegion(id, region, _style->_tw, _style->_th);
     }
     }
 
 
-    void Control::setImageRegion(const char* id, const Rectangle& region, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setImageRegion(id, region, _style->_tw, _style->_th);
-        }
+const Rectangle& Control::getImageRegion(const char* id, State state) const
+{
+    return getOverlay(state)->getImageRegion(id);
+}
 
 
-        _dirty = true;
-    }
+void Control::setImageColor(const char* id, const Vector4& color, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-    const Rectangle& Control::getImageRegion(const char* id, State state) const
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        return getOverlay(state)->getImageRegion(id);
+        overlays[i]->setImageColor(id, color);
     }
     }
 
 
-    void Control::setImageColor(const char* id, const Vector4& color, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setImageColor(id, color);
-        }
+const Vector4& Control::getImageColor(const char* id, State state) const
+{
+    return getOverlay(state)->getImageColor(id);
+}
 
 
-        _dirty = true;
-    }
+const Theme::UVs& Control::getImageUVs(const char* id, State state) const
+{
+    return getOverlay(state)->getImageUVs(id);
+}
 
 
-    const Vector4& Control::getImageColor(const char* id, State state) const
-    {
-        return getOverlay(state)->getImageColor(id);
-    }
+void Control::setCursorRegion(const Rectangle& region, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-    const Theme::UVs& Control::getImageUVs(const char* id, State state) const
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        return getOverlay(state)->getImageUVs(id);
+        overlays[i]->setCursorRegion(region, _style->_tw, _style->_th);
     }
     }
 
 
-    void Control::setCursorRegion(const Rectangle& region, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setCursorRegion(region, _style->_tw, _style->_th);
-        }
+const Rectangle& Control::getCursorRegion(State state) const
+{
+    return getOverlay(state)->getCursorRegion();
+}
 
 
-        _dirty = true;
-    }
+void Control::setCursorColor(const Vector4& color, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-    const Rectangle& Control::getCursorRegion(State state) const
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        return getOverlay(state)->getCursorRegion();
+        overlays[i]->setCursorColor(color);
     }
     }
 
 
-    void Control::setCursorColor(const Vector4& color, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setCursorColor(color);
-        }
+const Vector4& Control::getCursorColor(State state)
+{
+    return getOverlay(state)->getCursorColor();
+}
+    
+const Theme::UVs& Control::getCursorUVs(State state)
+{
+    return getOverlay(state)->getCursorUVs();
+}
 
 
-        _dirty = true;
-    }
+void Control::setFont(Font* font, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-    const Vector4& Control::getCursorColor(State state)
-    {
-        return getOverlay(state)->getCursorColor();
-    }
-    
-    const Theme::UVs& Control::getCursorUVs(State state)
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        return getOverlay(state)->getCursorUVs();
+        overlays[i]->setFont(font);
     }
     }
 
 
-    void Control::setFont(Font* font, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setFont(font);
-        }
+Font* Control::getFont(State state) const
+{
+    return getOverlay(state)->getFont();
+}
 
 
-        _dirty = true;
-    }
+void Control::setFontSize(unsigned int fontSize, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-    Font* Control::getFont(State state) const
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        return getOverlay(state)->getFont();
+        overlays[i]->setFontSize(fontSize);
     }
     }
 
 
-    void Control::setFontSize(unsigned int fontSize, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setFontSize(fontSize);
-        }
+unsigned int Control::getFontSize(State state) const
+{
+    return getOverlay(state)->getFontSize();
+}
 
 
-        _dirty = true;
-    }
+void Control::setTextColor(const Vector4& color, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-    unsigned int Control::getFontSize(State state) const
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        return getOverlay(state)->getFontSize();
+        overlays[i]->setTextColor(color);
     }
     }
 
 
-    void Control::setTextColor(const Vector4& color, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setTextColor(color);
-        }
+const Vector4& Control::getTextColor(State state) const
+{
+    return getOverlay(state)->getTextColor();
+}
 
 
-        _dirty = true;
-    }
+void Control::setTextAlignment(Font::Justify alignment, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-    const Vector4& Control::getTextColor(State state) const
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        return getOverlay(state)->getTextColor();
+        overlays[i]->setTextAlignment(alignment);
     }
     }
 
 
-    void Control::setTextAlignment(Font::Justify alignment, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setTextAlignment(alignment);
-        }
+Font::Justify Control::getTextAlignment(State state) const
+{
+    return getOverlay(state)->getTextAlignment();
+}
 
 
-        _dirty = true;
-    }
+void Control::setTextRightToLeft(bool rightToLeft, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-    Font::Justify Control::getTextAlignment(State state) const
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
     {
     {
-        return getOverlay(state)->getTextAlignment();
+        overlays[i]->setTextRightToLeft(rightToLeft);
     }
     }
 
 
-    void Control::setTextRightToLeft(bool rightToLeft, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setTextRightToLeft(rightToLeft);
-        }
+bool Control::getTextRightToLeft(State state) const
+{
+    return getOverlay(state)->getTextRightToLeft();
+}
 
 
-        _dirty = true;
-    }
+const Rectangle& Control::getClipBounds() const
+{
+    return _clipBounds;
+}
 
 
-    bool Control::getTextRightToLeft(State state) const
-    {
-        return getOverlay(state)->getTextRightToLeft();
-    }
+const Rectangle& Control::getClip() const
+{
+    return _viewportClipBounds;
+}
 
 
-    const Rectangle& Control::getClipBounds() const
+void Control::setStyle(Theme::Style* style)
+{
+    if (style != _style)
     {
     {
-        return _clipBounds;
+        _dirty = true;
     }
     }
 
 
-    const Rectangle& Control::getClip() const
-    {
-        return _clip;
-    }
+    _style = style;
+}
 
 
-    void Control::setStyle(Theme::Style* style)
-    {
-        if (style != _style)
-        {
-            _dirty = true;
-        }
+Theme::Style* Control::getStyle() const
+{
+    return _style;
+}
 
 
-        _style = style;
-    }
+void Control::setState(State state)
+{
+    if (getOverlay(_state) != getOverlay(state))
+        _dirty = true;
 
 
-    Theme::Style* Control::getStyle() const
-    {
-        return _style;
+    _state = state;
+}
+
+Control::State Control::getState() const
+{
+    return _state;
+}
+
+void Control::disable()
+{
+    _state = DISABLED;
+    _dirty = true;
+}
+
+void Control::enable()
+{
+    _state = NORMAL;
+    _dirty = true;
+}
+
+bool Control::isEnabled()
+{
+    return _state != DISABLED;
+}
+
+Theme::Style::OverlayType Control::getOverlayType() const
+{
+    switch (_state)
+    {
+    case Control::NORMAL:
+        return Theme::Style::OVERLAY_NORMAL;
+    case Control::FOCUS:
+        return Theme::Style::OVERLAY_FOCUS;
+    case Control::ACTIVE:
+        return Theme::Style::OVERLAY_ACTIVE;
+    case Control::DISABLED:
+        return Theme::Style::OVERLAY_DISABLED;
+    default:
+        return Theme::Style::OVERLAY_NORMAL;
     }
     }
+}
+
+void Control::setConsumeTouchEvents(bool consume)
+{
+    _consumeTouchEvents = consume;
+}
+    
+bool Control::getConsumeTouchEvents()
+{
+    return _consumeTouchEvents;
+}
 
 
-    void Control::setState(State state)
+void Control::addListener(Control::Listener* listener, int eventFlags)
+{
+    if ((eventFlags & Listener::PRESS) == Listener::PRESS)
     {
     {
-        _state = state;
-        _dirty = true;
+        addSpecificListener(listener, Listener::PRESS);
     }
     }
 
 
-    Control::State Control::getState() const
+    if ((eventFlags & Listener::RELEASE) == Listener::RELEASE)
     {
     {
-        return _state;
+        addSpecificListener(listener, Listener::RELEASE);
     }
     }
 
 
-    void Control::disable()
+    if ((eventFlags & Listener::CLICK) == Listener::CLICK)
     {
     {
-        _state = DISABLED;
-        _dirty = true;
+        addSpecificListener(listener, Listener::CLICK);
     }
     }
 
 
-    void Control::enable()
+    if ((eventFlags & Listener::VALUE_CHANGED) == Listener::VALUE_CHANGED)
     {
     {
-        _state = NORMAL;
-        _dirty = true;
+        addSpecificListener(listener, Listener::VALUE_CHANGED);
     }
     }
 
 
-    bool Control::isEnabled()
+    if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
     {
     {
-        return _state != DISABLED;
+        addSpecificListener(listener, Listener::TEXT_CHANGED);
     }
     }
+}
 
 
-    Theme::Style::OverlayType Control::getOverlayType() const
+void Control::addSpecificListener(Control::Listener* listener, Listener::EventType eventType)
+{
+    if (!_listeners)
     {
     {
-        switch (_state)
-        {
-        case Control::NORMAL:
-            return Theme::Style::OVERLAY_NORMAL;
-        case Control::FOCUS:
-            return Theme::Style::OVERLAY_FOCUS;
-        case Control::ACTIVE:
-            return Theme::Style::OVERLAY_ACTIVE;
-        case Control::DISABLED:
-            return Theme::Style::OVERLAY_DISABLED;
-        default:
-            return Theme::Style::OVERLAY_NORMAL;
-        }
+        _listeners = new std::map<Listener::EventType, std::list<Listener*>*>();
     }
     }
 
 
-    void Control::setConsumeTouchEvents(bool consume)
+    std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->find(eventType);
+    if (itr == _listeners->end())
     {
     {
-        _consumeTouchEvents = consume;
+        _listeners->insert(std::make_pair(eventType, new std::list<Listener*>()));
+        itr = _listeners->find(eventType);
     }
     }
-    
-    bool Control::getConsumeTouchEvents()
+
+    std::list<Listener*>* listenerList = itr->second;
+    listenerList->push_back(listener);
+}
+
+bool Control::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+{
+    if (!isEnabled())
     {
     {
-        return _consumeTouchEvents;
+        return false;
     }
     }
 
 
-    void Control::addListener(Control::Listener* listener, int eventFlags)
+    switch (evt)
     {
     {
-        if ((eventFlags & Listener::PRESS) == Listener::PRESS)
-        {
-            addSpecificListener(listener, Listener::PRESS);
-        }
-
-        if ((eventFlags & Listener::RELEASE) == Listener::RELEASE)
-        {
-            addSpecificListener(listener, Listener::RELEASE);
-        }
+    case Touch::TOUCH_PRESS:
+        notifyListeners(Listener::PRESS);
+        break;
+            
+    case Touch::TOUCH_RELEASE:
+        // Always trigger Listener::RELEASE
+        notifyListeners(Listener::RELEASE);
 
 
-        if ((eventFlags & Listener::CLICK) == Listener::CLICK)
+        // Only trigger Listener::CLICK if both PRESS and RELEASE took place within the control's bounds.
+        if (x > 0 && x <= _bounds.width &&
+            y > 0 && y <= _bounds.height)
         {
         {
-            addSpecificListener(listener, Listener::CLICK);
+            notifyListeners(Listener::CLICK);
         }
         }
+        break;
+    }
 
 
-        if ((eventFlags & Listener::VALUE_CHANGED) == Listener::VALUE_CHANGED)
-        {
-            addSpecificListener(listener, Listener::VALUE_CHANGED);
-        }
+    return _consumeTouchEvents;
+}
 
 
-        if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
-        {
-            addSpecificListener(listener, Listener::TEXT_CHANGED);
-        }
-    }
+void Control::keyEvent(Keyboard::KeyEvent evt, int key)
+{
+}
 
 
-    void Control::addSpecificListener(Control::Listener* listener, Listener::EventType eventType)
+void Control::notifyListeners(Listener::EventType eventType)
+{
+    if (_listeners)
     {
     {
-        if (!_listeners)
-        {
-            _listeners = new std::map<Listener::EventType, std::list<Listener*>*>();
-        }
-
         std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->find(eventType);
         std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->find(eventType);
-        if (itr == _listeners->end())
+        if (itr != _listeners->end())
         {
         {
-            _listeners->insert(std::make_pair(eventType, new std::list<Listener*>()));
-            itr = _listeners->find(eventType);
+            std::list<Listener*>* listenerList = itr->second;
+            for (std::list<Listener*>::iterator listenerItr = listenerList->begin(); listenerItr != listenerList->end(); listenerItr++)
+            {
+                (*listenerItr)->controlEvent(this, eventType);
+            }
         }
         }
-
-        std::list<Listener*>* listenerList = itr->second;
-        listenerList->push_back(listener);
     }
     }
+}
 
 
-    bool Control::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-    {
-        if (!isEnabled())
-        {
-            return false;
-        }
+void Control::update(const Rectangle& clip, const Vector2& offset)
+{
+    _clearBounds.set(_absoluteClipBounds);
 
 
-        switch (evt)
-        {
-        case Touch::TOUCH_PRESS:
-            notifyListeners(Listener::PRESS);
-            break;
-            
-        case Touch::TOUCH_RELEASE:
-            // Always trigger Listener::RELEASE
-            notifyListeners(Listener::RELEASE);
+    // Calculate the clipped bounds.
+    float x = _bounds.x + offset.x;
+    float y = _bounds.y + offset.y;
+    float width = _bounds.width;
+    float height = _bounds.height;
 
 
-            // Only trigger Listener::CLICK if both PRESS and RELEASE took place within the control's bounds.
-            if (x > 0 && x <= _bounds.width &&
-                y > 0 && y <= _bounds.height)
-            {
-                notifyListeners(Listener::CLICK);
-            }
-            break;
-        }
+    float clipX2 = clip.x + clip.width;
+    float x2 = clip.x + x + width;
+    if (x2 > clipX2)
+        width -= x2 - clipX2;
 
 
-        return _consumeTouchEvents;
-    }
+    float clipY2 = clip.y + clip.height;
+    float y2 = clip.y + y + height;
+    if (y2 > clipY2)
+        height -= y2 - clipY2;
 
 
-    void Control::keyEvent(Keyboard::KeyEvent evt, int key)
+    if (x < 0)
     {
     {
+        width += x;
+        x = -x;
     }
     }
-
-    void Control::notifyListeners(Listener::EventType eventType)
+    else
     {
     {
-        if (_listeners)
-        {
-            std::map<Listener::EventType, std::list<Listener*>*>::const_iterator itr = _listeners->find(eventType);
-            if (itr != _listeners->end())
-            {
-                std::list<Listener*>* listenerList = itr->second;
-                for (std::list<Listener*>::iterator listenerItr = listenerList->begin(); listenerItr != listenerList->end(); listenerItr++)
-                {
-                    (*listenerItr)->controlEvent(this, eventType);
-                }
-            }
-        }
+        x = 0;
     }
     }
 
 
-    void Control::update(const Rectangle& clip, const Vector2& offset)
+    if (y < 0)
+    {
+        height += y;
+        y = -y;
+    }
+    else
     {
     {
-        // Calculate the clipped bounds.
-        float x = _bounds.x + offset.x;
-        float y = _bounds.y + offset.y;
-        float width = _bounds.width;
-        float height = _bounds.height;
+        y = 0;
+    }
 
 
-        float clipX2 = clip.x + clip.width;
-        float x2 = clip.x + x + width;
-        if (x2 > clipX2)
-            width -= x2 - clipX2;
+    _clipBounds.set(x, y, width, height);
 
 
-        float clipY2 = clip.y + clip.height;
-        float y2 = clip.y + y + height;
-        if (y2 > clipY2)
-            height -= y2 - clipY2;
+    // Calculate the absolute bounds.
+    x = _bounds.x + offset.x + clip.x;
+    y = _bounds.y + offset.y + clip.y;
+    _absoluteBounds.set(x, y, _bounds.width, _bounds.height);
 
 
-        if (x < 0)
-        {
-            width += x;
-            x = -x;
-        }
-        else
-        {
-            x = 0;
-        }
+    // Calculate the absolute viewport bounds.
+    // Absolute bounds minus border and padding.
+    const Theme::Border& border = getBorder(_state);
+    const Theme::Padding& padding = getPadding();
 
 
-        if (y < 0)
-        {
-            height += y;
-            y = -y;
-        }
-        else
-        {
-            y = 0;
-        }
+    x += border.left + padding.left;
+    y += border.top + padding.top;
+    width = _bounds.width - border.left - padding.left - border.right - padding.right;
+    height = _bounds.height - border.top - padding.top - border.bottom - padding.bottom;
 
 
-        _clipBounds.set(x, y, width, height);
+    _viewportBounds.set(x, y, width, height);
 
 
-        // Calculate the absolute bounds.
-        x = _bounds.x + offset.x + clip.x;
-        y = _bounds.y + offset.y + clip.y;
+    // Calculate the clip area.
+    // Absolute bounds, minus border and padding,
+    // clipped to the parent container's clip area.
+    clipX2 = clip.x + clip.width;
+    x2 = x + width;
+    if (x2 > clipX2)
+        width = clipX2 - x;
 
 
-        _absoluteBounds.set(x, y, _bounds.width, _bounds.height);
+    clipY2 = clip.y + clip.height;
+    y2 = y + height;
+    if (y2 > clipY2)
+        height = clipY2 - y;
 
 
-        // Calculate the absolute viewport bounds.
-        // Absolute bounds minus border and padding.
-        const Theme::Border& border = getBorder(_state);
-        const Theme::Padding& padding = getPadding();
+    if (x < clip.x)
+    {
+        float dx = clip.x - x;
+        width -= dx;
+        x = clip.x;
+    }
 
 
-        x += border.left + padding.left;
-        y += border.top + padding.top;
-        width = _bounds.width - border.left - padding.left - border.right - padding.right;
-        height = _bounds.height - border.top - padding.top - border.bottom - padding.bottom;
+    if (y < clip.y)
+    {
+        float dy = clip.y - y;
+        height -= dy;
+        y = clip.y;
+    }
+ 
+    _viewportClipBounds.set(x, y, width, height);
 
 
-        _viewportBounds.set(x, y, width, height);
+    _absoluteClipBounds.set(x - border.left - padding.left, y - border.top - padding.top,
+        width + border.left + padding.left + border.right + padding.right,
+        height + border.top + padding.top + border.bottom + padding.bottom);
+    if (_clearBounds.isEmpty())
+    {
+        _clearBounds.set(_absoluteClipBounds);
+    }
 
 
-        // Calculate the clip area.
-        // Absolute bounds, minus border and padding,
-        // clipped to the parent container's clip area.
-        clipX2 = clip.x + clip.width;
-        x2 = x + width;
-        if (x2 > clipX2)
-            width = clipX2 - x;
+    // Cache themed attributes for performance.
+    _skin = getSkin(_state);
+    _opacity = getOpacity(_state);
+}
 
 
-        clipY2 = clip.y + clip.height;
-        y2 = y + height;
-        if (y2 > clipY2)
-            height = clipY2 - y;
+void Control::drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip)
+{
+    if (!_skin || _bounds.width <= 0 || _bounds.height <= 0)
+        return;
+
+    // Get the border and background images for this control's current state.
+    const Theme::UVs& topLeft = _skin->getUVs(Theme::Skin::TOP_LEFT);
+    const Theme::UVs& top = _skin->getUVs(Theme::Skin::TOP);
+    const Theme::UVs& topRight = _skin->getUVs(Theme::Skin::TOP_RIGHT);
+    const Theme::UVs& left = _skin->getUVs(Theme::Skin::LEFT);
+    const Theme::UVs& center = _skin->getUVs(Theme::Skin::CENTER);
+    const Theme::UVs& right = _skin->getUVs(Theme::Skin::RIGHT);
+    const Theme::UVs& bottomLeft = _skin->getUVs(Theme::Skin::BOTTOM_LEFT);
+    const Theme::UVs& bottom = _skin->getUVs(Theme::Skin::BOTTOM);
+    const Theme::UVs& bottomRight = _skin->getUVs(Theme::Skin::BOTTOM_RIGHT);
+
+    // Calculate screen-space positions.
+    const Theme::Border& border = getBorder(_state);
+    const Theme::Padding& padding = getPadding();
+    Vector4 skinColor = _skin->getColor();
+    skinColor.w *= _opacity;
+
+    float midWidth = _bounds.width - border.left - border.right;
+    float midHeight = _bounds.height - border.top - border.bottom;
+    float midX = _absoluteBounds.x + border.left;
+    float midY = _absoluteBounds.y + border.top;
+    float rightX = _absoluteBounds.x + _bounds.width - border.right;
+    float bottomY = _absoluteBounds.y + _bounds.height - border.bottom;
+
+    // Draw themed border sprites.
+    if (!border.left && !border.right && !border.top && !border.bottom)
+    {
+        // No border, just draw the image.
+        spriteBatch->draw(_absoluteBounds.x, _absoluteBounds.y, _bounds.width, _bounds.height, center.u1, center.v1, center.u2, center.v2, skinColor, clip);
+    }
+    else
+    {
+        if (border.left && border.top)
+            spriteBatch->draw(_absoluteBounds.x, _absoluteBounds.y, border.left, border.top, topLeft.u1, topLeft.v1, topLeft.u2, topLeft.v2, skinColor, clip);
+        if (border.top)
+            spriteBatch->draw(_absoluteBounds.x + border.left, _absoluteBounds.y, midWidth, border.top, top.u1, top.v1, top.u2, top.v2, skinColor, clip);
+        if (border.right && border.top)
+            spriteBatch->draw(rightX, _absoluteBounds.y, border.right, border.top, topRight.u1, topRight.v1, topRight.u2, topRight.v2, skinColor, clip);
+        if (border.left)
+            spriteBatch->draw(_absoluteBounds.x, midY, border.left, midHeight, left.u1, left.v1, left.u2, left.v2, skinColor, clip);
+        if (border.left && border.right && border.top && border.bottom)
+            spriteBatch->draw(_absoluteBounds.x + border.left, _absoluteBounds.y + border.top, _bounds.width - border.left - border.right, _bounds.height - border.top - border.bottom,
+                center.u1, center.v1, center.u2, center.v2, skinColor, clip);
+        if (border.right)
+            spriteBatch->draw(rightX, midY, border.right, midHeight, right.u1, right.v1, right.u2, right.v2, skinColor, clip);
+        if (border.bottom && border.left)
+            spriteBatch->draw(_absoluteBounds.x, bottomY, border.left, border.bottom, bottomLeft.u1, bottomLeft.v1, bottomLeft.u2, bottomLeft.v2, skinColor, clip);
+        if (border.bottom)
+            spriteBatch->draw(midX, bottomY, midWidth, border.bottom, bottom.u1, bottom.v1, bottom.u2, bottom.v2, skinColor, clip);
+        if (border.bottom && border.right)
+            spriteBatch->draw(rightX, bottomY, border.right, border.bottom, bottomRight.u1, bottomRight.v1, bottomRight.u2, bottomRight.v2, skinColor, clip);
+    }
+}
 
 
-        if (x < clip.x)
-        {
-            float dx = clip.x - x;
-            width -= dx;
-            x = clip.x;
-        }
+void Control::drawImages(SpriteBatch* spriteBatch, const Rectangle& position)
+{
+}
 
 
-        if (y < clip.y)
-        {
-            float dy = clip.y - y;
-            height -= dy;
-            y = clip.y;
-        }
- 
-        _clip.set(x, y, width, height);
-
-        // Cache themed attributes for performance.
-        _skin = getSkin(_state);
-        _opacity = getOpacity(_state);
-    }
-
-    void Control::drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip)
-    {
-        if (!_skin || _bounds.width <= 0 || _bounds.height <= 0)
-            return;
-
-        // Get the border and background images for this control's current state.
-        const Theme::UVs& topLeft = _skin->getUVs(Theme::Skin::TOP_LEFT);
-        const Theme::UVs& top = _skin->getUVs(Theme::Skin::TOP);
-        const Theme::UVs& topRight = _skin->getUVs(Theme::Skin::TOP_RIGHT);
-        const Theme::UVs& left = _skin->getUVs(Theme::Skin::LEFT);
-        const Theme::UVs& center = _skin->getUVs(Theme::Skin::CENTER);
-        const Theme::UVs& right = _skin->getUVs(Theme::Skin::RIGHT);
-        const Theme::UVs& bottomLeft = _skin->getUVs(Theme::Skin::BOTTOM_LEFT);
-        const Theme::UVs& bottom = _skin->getUVs(Theme::Skin::BOTTOM);
-        const Theme::UVs& bottomRight = _skin->getUVs(Theme::Skin::BOTTOM_RIGHT);
-
-        // Calculate screen-space positions.
-        const Theme::Border& border = getBorder(_state);
-        const Theme::Padding& padding = getPadding();
-        Vector4 skinColor = _skin->getColor();
-        skinColor.w *= _opacity;
-
-        float midWidth = _bounds.width - border.left - border.right;
-        float midHeight = _bounds.height - border.top - border.bottom;
-        float midX = _absoluteBounds.x + border.left;
-        float midY = _absoluteBounds.y + border.top;
-        float rightX = _absoluteBounds.x + _bounds.width - border.right;
-        float bottomY = _absoluteBounds.y + _bounds.height - border.bottom;
-
-        // Draw themed border sprites.
-        if (!border.left && !border.right && !border.top && !border.bottom)
-        {
-            // No border, just draw the image.
-            spriteBatch->draw(_absoluteBounds.x, _absoluteBounds.y, _bounds.width, _bounds.height, center.u1, center.v1, center.u2, center.v2, skinColor, clip);
-        }
-        else
-        {
-            if (border.left && border.top)
-                spriteBatch->draw(_absoluteBounds.x, _absoluteBounds.y, border.left, border.top, topLeft.u1, topLeft.v1, topLeft.u2, topLeft.v2, skinColor, clip);
-            if (border.top)
-                spriteBatch->draw(_absoluteBounds.x + border.left, _absoluteBounds.y, midWidth, border.top, top.u1, top.v1, top.u2, top.v2, skinColor, clip);
-            if (border.right && border.top)
-                spriteBatch->draw(rightX, _absoluteBounds.y, border.right, border.top, topRight.u1, topRight.v1, topRight.u2, topRight.v2, skinColor, clip);
-            if (border.left)
-                spriteBatch->draw(_absoluteBounds.x, midY, border.left, midHeight, left.u1, left.v1, left.u2, left.v2, skinColor, clip);
-            if (border.left && border.right && border.top && border.bottom)
-                spriteBatch->draw(_absoluteBounds.x + border.left, _absoluteBounds.y + border.top, _bounds.width - border.left - border.right, _bounds.height - border.top - border.bottom,
-                    center.u1, center.v1, center.u2, center.v2, skinColor, clip);
-            if (border.right)
-                spriteBatch->draw(rightX, midY, border.right, midHeight, right.u1, right.v1, right.u2, right.v2, skinColor, clip);
-            if (border.bottom && border.left)
-                spriteBatch->draw(_absoluteBounds.x, bottomY, border.left, border.bottom, bottomLeft.u1, bottomLeft.v1, bottomLeft.u2, bottomLeft.v2, skinColor, clip);
-            if (border.bottom)
-                spriteBatch->draw(midX, bottomY, midWidth, border.bottom, bottom.u1, bottom.v1, bottom.u2, bottom.v2, skinColor, clip);
-            if (border.bottom && border.right)
-                spriteBatch->draw(rightX, bottomY, border.right, border.bottom, bottomRight.u1, bottomRight.v1, bottomRight.u2, bottomRight.v2, skinColor, clip);
-        }
-    }
+void Control::drawText(const Rectangle& position)
+{
+}
 
 
-    void Control::drawImages(SpriteBatch* spriteBatch, const Rectangle& position)
+void Control::draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, float targetHeight)
+{
+    if (needsClear)
     {
     {
+        GL_ASSERT( glEnable(GL_SCISSOR_TEST) );
+        GL_ASSERT( glClearColor(0, 0, 0, 1) );
+        GL_ASSERT( glScissor(_clearBounds.x, targetHeight - _clearBounds.y - _clearBounds.height,
+            _clearBounds.width, _clearBounds.height) );
+        GL_ASSERT( glClear(GL_COLOR_BUFFER_BIT) );
+        GL_ASSERT( glDisable(GL_SCISSOR_TEST) );
     }
     }
 
 
-    void Control::drawText(const Rectangle& position)
+    drawBorder(spriteBatch, clip);
+    drawImages(spriteBatch, clip);
+    drawText(clip);
+    _dirty = false;
+}
+
+bool Control::isDirty()
+{
+    return _dirty;
+}
+
+bool Control::isContainer()
+{
+    return false;
+}
+
+Control::State Control::getState(const char* state)
+{
+    if (!state)
     {
     {
+        return NORMAL;
     }
     }
 
 
-    void Control::draw(SpriteBatch* spriteBatch, const Rectangle& clip)
+    if (strcmp(state, "NORMAL") == 0)
     {
     {
-        drawBorder(spriteBatch, clip);
-        drawImages(spriteBatch, clip);
-        drawText(clip);
-        _dirty = false;
+        return NORMAL;
     }
     }
-
-    bool Control::isDirty()
+    else if (strcmp(state, "ACTIVE") == 0)
     {
     {
-        return _dirty;
+        return ACTIVE;
     }
     }
-
-    bool Control::isContainer()
+    else if (strcmp(state, "FOCUS") == 0)
     {
     {
-        return false;
+        return FOCUS;
     }
     }
+    else if (strcmp(state, "DISABLED") == 0)
+    {
+        return DISABLED;
+    }
+
+    return NORMAL;
+}
 
 
-    Control::State Control::getState(const char* state)
+Theme::ThemeImage* Control::getImage(const char* id, State state)
+{
+    return getOverlay(state)->getImageList()->getImage(id);
+}
+
+// Implementation of AnimationHandler
+unsigned int Control::getAnimationPropertyComponentCount(int propertyId) const
+{
+    switch(propertyId)
     {
     {
-        if (!state)
-        {
-            return NORMAL;
-        }
+    case ANIMATE_POSITION:
+    case ANIMATE_SIZE:
+        return 2;
 
 
-        if (strcmp(state, "NORMAL") == 0)
-        {
-            return NORMAL;
-        }
-        else if (strcmp(state, "ACTIVE") == 0)
-        {
-            return ACTIVE;
-        }
-        else if (strcmp(state, "FOCUS") == 0)
-        {
-            return FOCUS;
-        }
-        else if (strcmp(state, "DISABLED") == 0)
-        {
-            return DISABLED;
-        }
+    case ANIMATE_POSITION_X:
+    case ANIMATE_POSITION_Y:
+    case ANIMATE_SIZE_WIDTH:
+    case ANIMATE_SIZE_HEIGHT:
+    case ANIMATE_OPACITY:
+        return 1;
 
 
-        return NORMAL;
+    default:
+        return -1;
     }
     }
+}
 
 
-    Theme::ThemeImage* Control::getImage(const char* id, State state)
+void Control::getAnimationPropertyValue(int propertyId, AnimationValue* value)
+{
+    switch(propertyId)
+    {
+    case ANIMATE_POSITION:
+        value->setFloat(0, _bounds.x);
+        value->setFloat(1, _bounds.y);
+        break;
+    case ANIMATE_SIZE:
+        value->setFloat(0, _bounds.width);
+        value->setFloat(1, _bounds.height);
+        break;
+    case ANIMATE_POSITION_X:
+        value->setFloat(0, _bounds.x);
+        break;
+    case ANIMATE_POSITION_Y:
+        value->setFloat(0, _bounds.y);
+        break;
+    case ANIMATE_SIZE_WIDTH:
+        value->setFloat(0, _bounds.width);
+        break;
+    case ANIMATE_SIZE_HEIGHT:
+        value->setFloat(0, _bounds.height);
+        break;
+    case ANIMATE_OPACITY:
+    default:
+        break;
+    }
+}
+
+void Control::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight)
+{
+    switch(propertyId)
     {
     {
-        return getOverlay(state)->getImageList()->getImage(id);
+    case ANIMATE_POSITION:
+        _bounds.x = Curve::lerp(blendWeight, _bounds.x, value->getFloat(0));
+        _bounds.y = Curve::lerp(blendWeight, _bounds.y, value->getFloat(1));
+        _dirty = true;
+        break;
+    case ANIMATE_POSITION_X:
+        _bounds.x = Curve::lerp(blendWeight, _bounds.x, value->getFloat(0));
+        _dirty = true;
+        break;
+    case ANIMATE_POSITION_Y:
+        _bounds.y = Curve::lerp(blendWeight, _bounds.y, value->getFloat(0));
+        _dirty = true;
+        break;
+    case ANIMATE_SIZE:
+        _bounds.width = Curve::lerp(blendWeight, _bounds.width, value->getFloat(0));
+        _bounds.height = Curve::lerp(blendWeight, _bounds.height, value->getFloat(1));
+        _dirty = true;
+        break;
+    case ANIMATE_SIZE_WIDTH:
+        _bounds.width = Curve::lerp(blendWeight, _bounds.width, value->getFloat(0));
+        _dirty = true;
+        break;
+    case ANIMATE_SIZE_HEIGHT:
+        _bounds.height = Curve::lerp(blendWeight, _bounds.height, value->getFloat(0));
+        _dirty = true;
+        break;
+    case ANIMATE_OPACITY:
+        _dirty = true;
+    default:
+        break;
     }
     }
+}
+    
 
 
-    // Implementation of AnimationHandler
-    unsigned int Control::getAnimationPropertyComponentCount(int propertyId) const
+Theme::Style::Overlay** Control::getOverlays(unsigned char overlayTypes, Theme::Style::Overlay** overlays)
+{
+    unsigned int index = 0;
+    if ((overlayTypes & NORMAL) == NORMAL)
     {
     {
-        switch(propertyId)
-        {
-        case ANIMATE_POSITION:
-        case ANIMATE_SIZE:
-            return 2;
-
-        case ANIMATE_POSITION_X:
-        case ANIMATE_POSITION_Y:
-        case ANIMATE_SIZE_WIDTH:
-        case ANIMATE_SIZE_HEIGHT:
-        case ANIMATE_OPACITY:
-            return 1;
-
-        default:
-            return -1;
-        }
+        overlays[index++] = _style->getOverlay(Theme::Style::OVERLAY_NORMAL);
     }
     }
 
 
-    void Control::getAnimationPropertyValue(int propertyId, AnimationValue* value)
+    if ((overlayTypes & FOCUS) == FOCUS)
     {
     {
-        switch(propertyId)
-        {
-        case ANIMATE_POSITION:
-            value->setFloat(0, _bounds.x);
-            value->setFloat(1, _bounds.y);
-            break;
-        case ANIMATE_SIZE:
-            value->setFloat(0, _bounds.width);
-            value->setFloat(1, _bounds.height);
-            break;
-        case ANIMATE_POSITION_X:
-            value->setFloat(0, _bounds.x);
-            break;
-        case ANIMATE_POSITION_Y:
-            value->setFloat(0, _bounds.y);
-            break;
-        case ANIMATE_SIZE_WIDTH:
-            value->setFloat(0, _bounds.width);
-            break;
-        case ANIMATE_SIZE_HEIGHT:
-            value->setFloat(0, _bounds.height);
-            break;
-        case ANIMATE_OPACITY:
-        default:
-            break;
-        }
+        overlays[index++] = _style->getOverlay(Theme::Style::OVERLAY_FOCUS);
     }
     }
 
 
-    void Control::setAnimationPropertyValue(int propertyId, AnimationValue* value, float blendWeight)
+    if ((overlayTypes & ACTIVE) == ACTIVE)
     {
     {
-        switch(propertyId)
-        {
-        case ANIMATE_POSITION:
-            _bounds.x = Curve::lerp(blendWeight, _bounds.x, value->getFloat(0));
-            _bounds.y = Curve::lerp(blendWeight, _bounds.y, value->getFloat(1));
-            _dirty = true;
-            break;
-        case ANIMATE_POSITION_X:
-            _bounds.x = Curve::lerp(blendWeight, _bounds.x, value->getFloat(0));
-            _dirty = true;
-            break;
-        case ANIMATE_POSITION_Y:
-            _bounds.y = Curve::lerp(blendWeight, _bounds.y, value->getFloat(0));
-            _dirty = true;
-            break;
-        case ANIMATE_SIZE:
-            _bounds.width = Curve::lerp(blendWeight, _bounds.width, value->getFloat(0));
-            _bounds.height = Curve::lerp(blendWeight, _bounds.height, value->getFloat(1));
-            _dirty = true;
-            break;
-        case ANIMATE_SIZE_WIDTH:
-            _bounds.width = Curve::lerp(blendWeight, _bounds.width, value->getFloat(0));
-            _dirty = true;
-            break;
-        case ANIMATE_SIZE_HEIGHT:
-            _bounds.height = Curve::lerp(blendWeight, _bounds.height, value->getFloat(0));
-            _dirty = true;
-            break;
-        case ANIMATE_OPACITY:
-            _dirty = true;
-        default:
-            break;
-        }
+        overlays[index++] = _style->getOverlay(Theme::Style::OVERLAY_ACTIVE);
     }
     }
-    
 
 
-    Theme::Style::Overlay** Control::getOverlays(unsigned char overlayTypes, Theme::Style::Overlay** overlays)
+    if ((overlayTypes & DISABLED) == DISABLED)
     {
     {
-        unsigned int index = 0;
-        if ((overlayTypes & NORMAL) == NORMAL)
-        {
-            overlays[index++] = _style->getOverlay(Theme::Style::OVERLAY_NORMAL);
-        }
+        overlays[index++] = _style->getOverlay(Theme::Style::OVERLAY_DISABLED);
+    }
 
 
-        if ((overlayTypes & FOCUS) == FOCUS)
-        {
-            overlays[index++] = _style->getOverlay(Theme::Style::OVERLAY_FOCUS);
-        }
+    return overlays;
+}
 
 
-        if ((overlayTypes & ACTIVE) == ACTIVE)
-        {
-            overlays[index++] = _style->getOverlay(Theme::Style::OVERLAY_ACTIVE);
-        }
+Theme::Style::Overlay* Control::getOverlay(State state) const
+{
+    switch(state)
+    {
+    case Control::NORMAL:
+        return _style->getOverlay(Theme::Style::OVERLAY_NORMAL);
+    case Control::FOCUS:
+        return _style->getOverlay(Theme::Style::OVERLAY_FOCUS);
+    case Control::ACTIVE:
+        return _style->getOverlay(Theme::Style::OVERLAY_ACTIVE);
+    case Control::DISABLED:
+        return _style->getOverlay(Theme::Style::OVERLAY_DISABLED);
+    default:
+        return NULL;
+    }
+}
 
 
-        if ((overlayTypes & DISABLED) == DISABLED)
-        {
-            overlays[index++] = _style->getOverlay(Theme::Style::OVERLAY_DISABLED);
-        }
+void Control::overrideStyle()
+{
+    if (_styleOverridden)
+    {
+        return;
+    }
 
 
-        return overlays;
+    // Copy the style.
+    WARN_VARG("%d", sizeof(Theme::Style::Overlay));
+    _style = new Theme::Style(*_style);
+    _styleOverridden = true;
+}
+
+void Control::overrideThemedProperties(Properties* properties, unsigned char states)
+{
+    Theme::ImageList* imageList = NULL;
+    Theme::ThemeImage* cursor = NULL;
+    Theme::Skin* skin = NULL;
+    _style->_theme->lookUpSprites(properties, &imageList, &cursor, &skin);
+
+    if (imageList)
+    {
+        setImageList(imageList, states);
     }
     }
 
 
-    Theme::Style::Overlay* Control::getOverlay(State state) const
+    if (cursor)
     {
     {
-        switch(state)
-        {
-        case Control::NORMAL:
-            return _style->getOverlay(Theme::Style::OVERLAY_NORMAL);
-        case Control::FOCUS:
-            return _style->getOverlay(Theme::Style::OVERLAY_FOCUS);
-        case Control::ACTIVE:
-            return _style->getOverlay(Theme::Style::OVERLAY_ACTIVE);
-        case Control::DISABLED:
-            return _style->getOverlay(Theme::Style::OVERLAY_DISABLED);
-        default:
-            return NULL;
-        }
+        setCursor(cursor, states);
     }
     }
 
 
-    void Control::overrideStyle()
+    if (skin)
     {
     {
-        if (_styleOverridden)
-        {
-            return;
-        }
+        setSkin(skin, states);
+    }
 
 
-        // Copy the style.
-        WARN_VARG("%d", sizeof(Theme::Style::Overlay));
-        _style = new Theme::Style(*_style);
-        _styleOverridden = true;
+    if (properties->exists("font"))
+    {
+        Font* font = Font::create(properties->getString("font"));
+        setFont(font, states);
+        font->release();
     }
     }
 
 
-    void Control::overrideThemedProperties(Properties* properties, unsigned char states)
+    if (properties->exists("fontSize"))
     {
     {
-        Theme::ImageList* imageList = NULL;
-        Theme::ThemeImage* cursor = NULL;
-        Theme::Skin* skin = NULL;
-        _style->_theme->lookUpSprites(properties, &imageList, &cursor, &skin);
+        setFontSize(properties->getInt("fontSize"), states);
+    }
 
 
-        if (imageList)
-        {
-            setImageList(imageList, states);
-        }
+    if (properties->exists("textColor"))
+    {
+        Vector4 textColor(0, 0, 0, 1);
+        properties->getColor("textColor", &textColor);
+        setTextColor(textColor, states);
+    }
 
 
-        if (cursor)
-        {
-            setCursor(cursor, states);
-        }
+    if (properties->exists("textAlignment"))
+    {
+        setTextAlignment(Font::getJustify(properties->getString("textAlignment")), states);
+    }
 
 
-        if (skin)
-        {
-            setSkin(skin, states);
-        }
+    if (properties->exists("rightToLeft"))
+    {
+        setTextRightToLeft(properties->getBool("rightToLeft"), states);
+    }
 
 
-        if (properties->exists("font"))
-        {
-            Font* font = Font::create(properties->getString("font"));
-            setFont(font, states);
-            font->release();
-        }
+    if (properties->exists("opacity"))
+    {
+        setOpacity(properties->getFloat("opacity"), states);
+    }
+}
 
 
-        if (properties->exists("fontSize"))
-        {
-            setFontSize(properties->getInt("fontSize"), states);
-        }
+void Control::setImageList(Theme::ImageList* imageList, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-        if (properties->exists("textColor"))
-        {
-            Vector4 textColor(0, 0, 0, 1);
-            properties->getColor("textColor", &textColor);
-            setTextColor(textColor, states);
-        }
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
+    {
+        overlays[i]->setImageList(imageList);
+    }
 
 
-        if (properties->exists("textAlignment"))
-        {
-            setTextAlignment(Font::getJustify(properties->getString("textAlignment")), states);
-        }
+    _dirty = true;
+}
 
 
-        if (properties->exists("rightToLeft"))
-        {
-            setTextRightToLeft(properties->getBool("rightToLeft"), states);
-        }
+void Control::setCursor(Theme::ThemeImage* cursor, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-        if (properties->exists("opacity"))
-        {
-            setOpacity(properties->getFloat("opacity"), states);
-        }
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
+    {
+        overlays[i]->setCursor(cursor);
     }
     }
 
 
-    void Control::setImageList(Theme::ImageList* imageList, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setImageList(imageList);
-        }
+void Control::setSkin(Theme::Skin* skin, unsigned char states)
+{
+    overrideStyle();
+    Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
+    getOverlays(states, overlays);
 
 
-        _dirty = true;
+    for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
+    {
+        overlays[i]->setSkin(skin);
     }
     }
 
 
-    void Control::setCursor(Theme::ThemeImage* cursor, unsigned char states)
-    {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
+    _dirty = true;
+}
 
 
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setCursor(cursor);
-        }
+Theme::Skin* Control::getSkin(State state)
+{
+    return getOverlay(state)->getSkin();
+}
 
 
-        _dirty = true;
+Control::Alignment Control::getAlignment(const char* alignment)
+{
+    if (!alignment)
+    {
+        return Control::ALIGN_TOP_LEFT;
     }
     }
 
 
-    void Control::setSkin(Theme::Skin* skin, unsigned char states)
+    if (strcmp(alignment, "ALIGN_LEFT") == 0)
     {
     {
-        overrideStyle();
-        Theme::Style::Overlay* overlays[Theme::Style::OVERLAY_MAX] = { 0 };
-        getOverlays(states, overlays);
-
-        for (int i = 0; i < Theme::Style::OVERLAY_MAX - 1 && overlays[i]; ++i)
-        {
-            overlays[i]->setSkin(skin);
-        }
-
-        _dirty = true;
+        return Control::ALIGN_LEFT;
     }
     }
-
-    Theme::Skin* Control::getSkin(State state)
+    else if (strcmp(alignment, "ALIGN_HCENTER") == 0)
     {
     {
-        return getOverlay(state)->getSkin();
+        return Control::ALIGN_HCENTER;
     }
     }
-
-    Control::Alignment Control::getAlignment(const char* alignment)
+    else if (strcmp(alignment, "ALIGN_RIGHT") == 0)
+    {
+        return Control::ALIGN_RIGHT;
+    }
+    else if (strcmp(alignment, "ALIGN_TOP") == 0)
+    {
+        return Control::ALIGN_TOP;
+    }
+    else if (strcmp(alignment, "ALIGN_VCENTER") == 0)
+    {
+        return Control::ALIGN_VCENTER;
+    }
+    else if (strcmp(alignment, "ALIGN_BOTTOM") == 0)
+    {
+        return Control::ALIGN_BOTTOM;
+    }
+    else if (strcmp(alignment, "ALIGN_TOP_LEFT") == 0)
     {
     {
-        if (!alignment)
-        {
-            return Control::ALIGN_TOP_LEFT;
-        }
-
-        if (strcmp(alignment, "ALIGN_LEFT") == 0)
-        {
-            return Control::ALIGN_LEFT;
-        }
-        else if (strcmp(alignment, "ALIGN_HCENTER") == 0)
-        {
-            return Control::ALIGN_HCENTER;
-        }
-        else if (strcmp(alignment, "ALIGN_RIGHT") == 0)
-        {
-            return Control::ALIGN_RIGHT;
-        }
-        else if (strcmp(alignment, "ALIGN_TOP") == 0)
-        {
-            return Control::ALIGN_TOP;
-        }
-        else if (strcmp(alignment, "ALIGN_VCENTER") == 0)
-        {
-            return Control::ALIGN_VCENTER;
-        }
-        else if (strcmp(alignment, "ALIGN_BOTTOM") == 0)
-        {
-            return Control::ALIGN_BOTTOM;
-        }
-        else if (strcmp(alignment, "ALIGN_TOP_LEFT") == 0)
-        {
-            return Control::ALIGN_TOP_LEFT;
-        }
-        else if (strcmp(alignment, "ALIGN_VCENTER_LEFT") == 0)
-        {
-            return Control::ALIGN_VCENTER_LEFT;
-        }
-        else if (strcmp(alignment, "ALIGN_BOTTOM_LEFT") == 0)
-        {
-            return Control::ALIGN_BOTTOM_LEFT;
-        }
-        else if (strcmp(alignment, "ALIGN_TOP_HCENTER") == 0)
-        {
-            return Control::ALIGN_TOP_HCENTER;
-        }
-        else if (strcmp(alignment, "ALIGN_VCENTER_HCENTER") == 0)
-        {
-            return Control::ALIGN_VCENTER_HCENTER;
-        }
-        else if (strcmp(alignment, "ALIGN_BOTTOM_HCENTER") == 0)
-        {
-            return Control::ALIGN_BOTTOM_HCENTER;
-        }
-        else if (strcmp(alignment, "ALIGN_TOP_RIGHT") == 0)
-        {
-            return Control::ALIGN_TOP_RIGHT;
-        }
-        else if (strcmp(alignment, "ALIGN_VCENTER_RIGHT") == 0)
-        {
-            return Control::ALIGN_VCENTER_RIGHT;
-        }
-        else if (strcmp(alignment, "ALIGN_BOTTOM_RIGHT") == 0)
-        {
-            return Control::ALIGN_BOTTOM_RIGHT;
-        }
-
-        // Default.
         return Control::ALIGN_TOP_LEFT;
         return Control::ALIGN_TOP_LEFT;
     }
     }
+    else if (strcmp(alignment, "ALIGN_VCENTER_LEFT") == 0)
+    {
+        return Control::ALIGN_VCENTER_LEFT;
+    }
+    else if (strcmp(alignment, "ALIGN_BOTTOM_LEFT") == 0)
+    {
+        return Control::ALIGN_BOTTOM_LEFT;
+    }
+    else if (strcmp(alignment, "ALIGN_TOP_HCENTER") == 0)
+    {
+        return Control::ALIGN_TOP_HCENTER;
+    }
+    else if (strcmp(alignment, "ALIGN_VCENTER_HCENTER") == 0)
+    {
+        return Control::ALIGN_VCENTER_HCENTER;
+    }
+    else if (strcmp(alignment, "ALIGN_BOTTOM_HCENTER") == 0)
+    {
+        return Control::ALIGN_BOTTOM_HCENTER;
+    }
+    else if (strcmp(alignment, "ALIGN_TOP_RIGHT") == 0)
+    {
+        return Control::ALIGN_TOP_RIGHT;
+    }
+    else if (strcmp(alignment, "ALIGN_VCENTER_RIGHT") == 0)
+    {
+        return Control::ALIGN_VCENTER_RIGHT;
+    }
+    else if (strcmp(alignment, "ALIGN_BOTTOM_RIGHT") == 0)
+    {
+        return Control::ALIGN_BOTTOM_RIGHT;
+    }
+
+    // Default.
+    return Control::ALIGN_TOP_LEFT;
+}
+
 }
 }

+ 35 - 5
gameplay/src/Control.h

@@ -814,12 +814,41 @@ protected:
      * The Control's ID.
      * The Control's ID.
      */ 
      */ 
     std::string _id;
     std::string _id;
-    State _state;           // Determines overlay used during draw().
-    Rectangle _bounds;      // Position, relative to parent container's clipping window, and desired size.
-    Rectangle _clipBounds;  // The position and size of this control, relative to parent container's bounds, including border and padding, after clipping.
+
+    /**
+     * Determines overlay used during draw().
+     */
+    State _state;
+
+    /**
+     * Position, relative to parent container's clipping window, and desired size.
+     */
+    Rectangle _bounds;
+
+    /**
+     * Position, relative to parent container's clipping window, including border and padding, after clipping.
+     */
+    Rectangle _clipBounds;
+
+    /**
+     * Absolute bounds, including border and padding, before clipping.
+     */
     Rectangle _absoluteBounds;
     Rectangle _absoluteBounds;
+
+    /**
+     * Absolute bounds, including border and padding, after clipping.
+     */
+    Rectangle _absoluteClipBounds;
+
+    /**
+     * Absolute bounds of content area (i.e. without border and padding), before clipping.
+     */
     Rectangle _viewportBounds;
     Rectangle _viewportBounds;
-    Rectangle _clip;        // Clipping window of this control's content, after clipping.
+
+    /**
+     * Absolute bounds of content area (i.e. without border and padding), after clipping.
+     */
+    Rectangle _viewportClipBounds;
 
 
     bool _dirty;
     bool _dirty;
     
     
@@ -891,10 +920,11 @@ private:
      */
      */
     virtual void drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip);
     virtual void drawBorder(SpriteBatch* spriteBatch, const Rectangle& clip);
 
 
-    virtual void draw(SpriteBatch* spriteBatch, const Rectangle& clip);
+    virtual void draw(SpriteBatch* spriteBatch, const Rectangle& clip, bool needsClear, float targetHeight);
     
     
     bool _styleOverridden;
     bool _styleOverridden;
     Theme::Skin* _skin;
     Theme::Skin* _skin;
+    Rectangle _clearBounds;         // Previous frame's absolute clip bounds, to be cleared if necessary.
 };
 };
 
 
 }
 }

+ 345 - 288
gameplay/src/Form.cpp

@@ -11,386 +11,443 @@
 
 
 namespace gameplay
 namespace gameplay
 {
 {
-    static std::vector<Form*> __forms;
 
 
-    Form::Form() : _theme(NULL), _quad(NULL), _node(NULL), _frameBuffer(NULL), _spriteBatch(NULL)
+static std::vector<Form*> __forms;
+
+Form::Form() : _theme(NULL), _quad(NULL), _node(NULL), _frameBuffer(NULL), _spriteBatch(NULL)
+{
+}
+
+Form::Form(const Form& copy)
+{
+}
+
+Form::~Form()
+{
+    SAFE_RELEASE(_quad);
+    SAFE_RELEASE(_node);
+    SAFE_RELEASE(_frameBuffer);
+    SAFE_RELEASE(_theme);
+    SAFE_DELETE(_spriteBatch);
+
+    // Remove this Form from the global list.
+    std::vector<Form*>::iterator it = std::find(__forms.begin(), __forms.end(), this);
+    if (it != __forms.end())
     {
     {
+        __forms.erase(it);
     }
     }
+}
+
+Form* Form::create(const char* url)
+{
+    // Load Form from .form file.
+    assert(url);
+
+    Properties* properties = Properties::create(url);
+    assert(properties);
+    if (properties == NULL)
+        return NULL;
 
 
-    Form::Form(const Form& copy)
+    // Check if the Properties is valid and has a valid namespace.
+    Properties* formProperties = (strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace();
+    assert(formProperties);
+    if (!formProperties || !(strcmp(formProperties->getNamespace(), "form") == 0))
     {
     {
+        SAFE_DELETE(properties);
+        return NULL;
     }
     }
 
 
-    Form::~Form()
+    // Create new form with given ID, theme and layout.
+    const char* themeFile = formProperties->getString("theme");
+    const char* layoutString = formProperties->getString("layout");
+        
+    Layout* layout;
+    switch (getLayoutType(layoutString))
     {
     {
-        SAFE_RELEASE(_quad);
-        SAFE_RELEASE(_node);
-        SAFE_RELEASE(_frameBuffer);
-        SAFE_RELEASE(_theme);
-
-        // Remove this Form from the global list.
-        std::vector<Form*>::iterator it = std::find(__forms.begin(), __forms.end(), this);
-        if (it != __forms.end())
-        {
-            __forms.erase(it);
-        }
+    case Layout::LAYOUT_ABSOLUTE:
+        layout = AbsoluteLayout::create();
+        break;
+    case Layout::LAYOUT_FLOW:
+        break;
+    case Layout::LAYOUT_VERTICAL:
+        layout = VerticalLayout::create();
+        break;
     }
     }
 
 
-    Form* Form::create(const char* url)
-    {
-        // Load Form from .form file.
-        assert(url);
-
-        Properties* properties = Properties::create(url);
-        assert(properties);
-        if (properties == NULL)
-            return NULL;
-
-        // Check if the Properties is valid and has a valid namespace.
-        Properties* formProperties = (strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace();
-        assert(formProperties);
-        if (!formProperties || !(strcmp(formProperties->getNamespace(), "form") == 0))
-        {
-            SAFE_DELETE(properties);
-            return NULL;
-        }
+    assert(themeFile);
+    Theme* theme = Theme::create(themeFile);
+    assert(theme);
 
 
-        // Create new form with given ID, theme and layout.
-        const char* themeFile = formProperties->getString("theme");
-        const char* layoutString = formProperties->getString("layout");
-        
-        Layout* layout;
-        switch (getLayoutType(layoutString))
-        {
-        case Layout::LAYOUT_ABSOLUTE:
-            layout = AbsoluteLayout::create();
-            break;
-        case Layout::LAYOUT_FLOW:
-            break;
-        case Layout::LAYOUT_VERTICAL:
-            layout = VerticalLayout::create();
-            break;
-        }
+    Form* form = new Form();
+    form->_layout = layout;
+    form->_theme = theme;
 
 
-        assert(themeFile);
-        Theme* theme = Theme::create(themeFile);
-        assert(theme);
+    //Theme* theme = form->_theme;
+    const char* styleName = formProperties->getString("style");
+    form->initialize(theme->getStyle(styleName), formProperties);
 
 
-        Form* form = new Form();
-        form->_layout = layout;
-        form->_theme = theme;
+    if (form->_autoWidth)
+    {
+        form->_bounds.width = Game::getInstance()->getWidth();
+    }
 
 
-        //Theme* theme = form->_theme;
-        const char* styleName = formProperties->getString("style");
-        form->initialize(theme->getStyle(styleName), formProperties);
+    if (form->_autoHeight)
+    {
+        form->_bounds.height = Game::getInstance()->getHeight();
+    }
 
 
-        if (form->_autoWidth)
-        {
-            form->_bounds.width = Game::getInstance()->getWidth();
-        }
+    // Add all the controls to the form.
+    form->addControls(theme, formProperties);
 
 
-        if (form->_autoHeight)
-        {
-            form->_bounds.height = Game::getInstance()->getHeight();
-        }
+        
+    // Width and height must be powers of two to create a texture.
+    int w = (int)form->_bounds.width;
+    int h = (int)form->_bounds.height;
 
 
-        // Add all the controls to the form.
-        form->addControls(theme, formProperties);
+    if (!((w & (w - 1)) == 0))
+    {
+        w = nextHighestPowerOfTwo(w);
+    }
 
 
-        // Create the frame buffer.
-        form->_frameBuffer = FrameBuffer::create(form->_id.c_str());
-        RenderTarget* rt = RenderTarget::create(form->_id.c_str(), form->_bounds.width, form->_bounds.height);
-        form->_frameBuffer->setRenderTarget(rt);
-        SAFE_RELEASE(rt);
+    if (!((h & (h - 1)) == 0))
+    {
+        h = nextHighestPowerOfTwo(h);
+    }
 
 
-        Matrix::createOrthographicOffCenter(0, form->_bounds.width, form->_bounds.height, 0, 0, 1, &form->_projectionMatrix);
-        form->_theme->setProjectionMatrix(form->_projectionMatrix);
+    form->_u2 = form->_bounds.width / (float)w;
+    form->_v1 = form->_bounds.height / (float)h;
 
 
-        SAFE_DELETE(properties);
+    // Create the frame buffer.
+    form->_frameBuffer = FrameBuffer::create(form->_id.c_str());
+    RenderTarget* rt = RenderTarget::create(form->_id.c_str(), w, h);
+    form->_frameBuffer->setRenderTarget(rt);
+    SAFE_RELEASE(rt);
 
 
-        __forms.push_back(form);
+    Matrix::createOrthographicOffCenter(0, form->_bounds.width, form->_bounds.height, 0, 0, 1, &form->_projectionMatrix);
+    Game* game = Game::getInstance();
+    Matrix::createOrthographicOffCenter(0, game->getWidth(), game->getHeight(), 0, 0, 1, &form->_defaultProjectionMatrix);
 
 
-        return form;
-    }
+    SAFE_DELETE(properties);
+
+    __forms.push_back(form);
 
 
-    Form* Form::getForm(const char* id)
+    return form;
+}
+
+Form* Form::getForm(const char* id)
+{
+    std::vector<Form*>::const_iterator it;
+    for (it = __forms.begin(); it < __forms.end(); it++)
     {
     {
-        std::vector<Form*>::const_iterator it;
-        for (it = __forms.begin(); it < __forms.end(); it++)
+        Form* f = *it;
+        if (strcmp(id, f->getID()) == 0)
         {
         {
-            Form* f = *it;
-            if (strcmp(id, f->getID()) == 0)
-            {
-                return f;
-            }
+            return f;
         }
         }
-        
-        return NULL;
     }
     }
+        
+    return NULL;
+}
 
 
-    void Form::setQuad(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& p4)
-    {
-        Mesh* mesh = Mesh::createQuad(p1, p2, p3, p4);
-        initializeQuad(mesh);
-        SAFE_RELEASE(mesh);
-    }
+void Form::setQuad(const Vector3& p1, const Vector3& p2, const Vector3& p3, const Vector3& p4)
+{
+    Mesh* mesh = Mesh::createQuad(p1, p2, p3, p4);
+
+    initializeQuad(mesh);
+    SAFE_RELEASE(mesh);
+}
 
 
-    void Form::setQuad(float x, float y, float width, float height)
+void Form::setQuad(float x, float y, float width, float height)
+{
+    float x2 = x + width;
+    float y2 = y + height;
+
+    float vertices[] =
     {
     {
-        Mesh* mesh = Mesh::createQuad(x, y, width, height);
-        initializeQuad(mesh);
-        SAFE_RELEASE(mesh);
-    }
+        x, y2, 0,   0, _v1,
+        x, y, 0,    0, 0,
+        x2, y2, 0,  _u2, _v1,
+        x2, y, 0,   _u2, 0
+    };
 
 
-    void Form::setNode(Node* node)
+    VertexFormat::Element elements[] =
     {
     {
-        _node = node;
+        VertexFormat::Element(VertexFormat::POSITION, 3),
+        VertexFormat::Element(VertexFormat::TEXCOORD0, 2)
+    };
+    Mesh* mesh = Mesh::createMesh(VertexFormat(elements, 2), 4, false);
+    assert(mesh);
+
+    mesh->setPrimitiveType(Mesh::TRIANGLE_STRIP);
+    mesh->setVertexData(vertices, 0, 4);
+
+    initializeQuad(mesh);
+    SAFE_RELEASE(mesh);
+}
+
+void Form::setNode(Node* node)
+{
+    _node = node;
         
         
-        if (_node)
-        {
-            // Set this Form up to be 3D by initializing a quad.
-            setQuad(0.0f, 0.0f, _bounds.width, _bounds.height);
-            _node->setModel(_quad);
-        }
+    if (_node)
+    {
+        // Set this Form up to be 3D by initializing a quad.
+        setQuad(0.0f, 0.0f, _bounds.width, _bounds.height);
+        _node->setModel(_quad);
     }
     }
+}
 
 
-    void Form::update()
+void Form::update()
+{
+    if (isDirty())
     {
     {
-        if (isDirty())
-        {
-            Container::update(Rectangle(0, 0, _bounds.width, _bounds.height), Vector2::zero());
-        }
+        Container::update(Rectangle(0, 0, _bounds.width, _bounds.height), Vector2::zero());
     }
     }
+}
 
 
-    void Form::draw()
-    {
-        // If this form has a node then it's a 3D form.  The contents will be rendered
-        // into a framebuffer which will be used to texture a quad.  The quad will be
-        // given the same dimensions as the form and must be transformed appropriately
-        // by the user, unless they call setQuad() themselves.
+void Form::draw()
+{
+    // The first time a form is drawn, its contents are rendered into a framebuffer.
+    // The framebuffer will only be 
 
 
-        // On the other hand, if this form has not been set on a node it will render
-        // directly to the display.
+    // If this form has a node then it's a 3D form.  The contents will be rendered
+    // into a framebuffer which will be used to texture a quad.  The quad will be
+    // given the same dimensions as the form and must be transformed appropriately
+    // by the user, unless they call setQuad() themselves.
 
 
-        //
+    // On the other hand, if this form has not been set on a node it will render
+    // directly to the display.
 
 
-        // Check whether this form has changed since the last call to draw()
-        // and if so, render into the framebuffer.
-        if (isDirty())
-        {
-            _frameBuffer->bind();
+    // Check whether this form has changed since the last call to draw()
+    // and if so, render into the framebuffer.
+    if (isDirty())
+    {
+        _frameBuffer->bind();
 
 
-            Game* game = Game::getInstance();
-            Rectangle prevViewport = game->getViewport();
-            game->setViewport(Rectangle(_bounds.x, _bounds.y, _bounds.width, _bounds.height));
-            //game->clear(Game::CLEAR_COLOR_DEPTH, Vector4(0, 0, 0, 0), 1, 0);
+        Game* game = Game::getInstance();
+        Rectangle prevViewport = game->getViewport();
+        game->setViewport(Rectangle(_bounds.x, _bounds.y, _bounds.width, _bounds.height));
 
 
-            draw(_theme->getSpriteBatch(), _clip);
+        _theme->setProjectionMatrix(_projectionMatrix);
+        draw(_theme->getSpriteBatch(), _viewportClipBounds);
+        _theme->setProjectionMatrix(_defaultProjectionMatrix);
 
 
-            // Rebind the default framebuffer and game viewport.
-            FrameBuffer::bindDefault();
+        // Rebind the default framebuffer and game viewport.
+        FrameBuffer::bindDefault();
 
 
-            // restore the previous game viewport
-            game->setViewport(prevViewport);
-        }
+        // restore the previous game viewport
+        game->setViewport(prevViewport);
+    }
 
 
-        if (_node)
+    if (_node)
+    {
+        _quad->draw();
+    }
+    else
+    {
+        if (!_spriteBatch)
         {
         {
-            _quad->draw();
+            _spriteBatch = SpriteBatch::create(_frameBuffer->getRenderTarget()->getTexture());
         }
         }
-        else
-        {
-            if (!_spriteBatch)
-            {
-                _spriteBatch = SpriteBatch::create(_frameBuffer->getRenderTarget()->getTexture());
-                _spriteBatch->setProjectionMatrix(_projectionMatrix);
-            }
 
 
-            _spriteBatch->begin();
-            _spriteBatch->draw(_bounds.x, _bounds.y, 0, _bounds.width, _bounds.height, 0, 1, 1, 0, Vector4::one());
-            _spriteBatch->end();
-        }
+        _spriteBatch->begin();
+        _spriteBatch->draw(_bounds.x, _bounds.y, 0, _bounds.width, _bounds.height, 0, _v1, _u2, 0, Vector4::one());
+        _spriteBatch->end();
     }
     }
+}
 
 
-    void Form::draw(SpriteBatch* spriteBatch, const Rectangle& clip)
-    {
-        std::vector<Control*>::const_iterator it;
+void Form::draw(SpriteBatch* spriteBatch, const Rectangle& clip)
+{
+    std::vector<Control*>::const_iterator it;
 
 
-        // Batch each font individually.
-        std::set<Font*>::const_iterator fontIter;
-        for (fontIter = _theme->_fonts.begin(); fontIter != _theme->_fonts.end(); fontIter++)
+    // Batch each font individually.
+    std::set<Font*>::const_iterator fontIter;
+    for (fontIter = _theme->_fonts.begin(); fontIter != _theme->_fonts.end(); fontIter++)
+    {
+        Font* font = *fontIter;
+        if (font)
         {
         {
-            Font* font = *fontIter;
-            if (font)
-            {
-                font->begin();
-            }
+            font->begin();
         }
         }
+    }
 
 
-        // Batch for all themed border and background sprites.
-        spriteBatch->begin();
+    // Batch for all themed border and background sprites.
+    spriteBatch->begin();
 
 
-        // Draw the form's border and background.
-        // We don't pass the form's position to itself or it will be applied twice!
-        Control::drawBorder(spriteBatch, Rectangle(0, 0, _bounds.width, _bounds.height));
+    // Draw the form's border and background.
+    // We don't pass the form's position to itself or it will be applied twice!
+    Control::drawBorder(spriteBatch, Rectangle(0, 0, _bounds.width, _bounds.height));
 
 
-        for (it = _controls.begin(); it < _controls.end(); it++)
-        {
-            Control* control = *it;
+    Rectangle boundsUnion = Rectangle::empty();
+    for (it = _controls.begin(); it < _controls.end(); it++)
+    {
+        Control* control = *it;
 
 
-            //if (control->isDirty())
-            {
-                control->draw(spriteBatch, clip);
-            }
+        if (_skin || control->isDirty() || control->_clearBounds.intersects(boundsUnion))
+        {
+            control->draw(spriteBatch, clip, _skin == NULL, _bounds.height);
+            Rectangle::combine(control->_clearBounds, boundsUnion, &boundsUnion);
         }
         }
+    }
 
 
-        // Done all batching.
-        spriteBatch->end();
+    // Done all batching.
+    spriteBatch->end();
 
 
-        for (fontIter = _theme->_fonts.begin(); fontIter != _theme->_fonts.end(); fontIter++)
+    for (fontIter = _theme->_fonts.begin(); fontIter != _theme->_fonts.end(); fontIter++)
+    {
+        Font* font = *fontIter;
+        if (font)
         {
         {
-            Font* font = *fontIter;
-            if (font)
-            {
-                font->end();
-            }
+            font->end();
         }
         }
-
-        _dirty = false;
     }
     }
 
 
-    void Form::initializeQuad(Mesh* mesh)
-    {
-        // Release current model.
-        SAFE_RELEASE(_quad);
+    _dirty = false;
+}
+
+void Form::initializeQuad(Mesh* mesh)
+{
+    // Release current model.
+    SAFE_RELEASE(_quad);
 
 
-        // Create the model
-        _quad = Model::create(mesh);
+    // Create the model
+    _quad = Model::create(mesh);
 
 
-        // Create the material
-        Material* material = _quad->setMaterial("res/shaders/textured.vsh", "res/shaders/textured.fsh");
+    // Create the material
+    Material* material = _quad->setMaterial("res/shaders/textured.vsh", "res/shaders/textured.fsh");
 
 
-        // Set the common render state block for the material
-        RenderState::StateBlock* stateBlock = _theme->getSpriteBatch()->getStateBlock();
-        stateBlock->setDepthWrite(true);
-        material->setStateBlock(stateBlock);
+    // Set the common render state block for the material
+    RenderState::StateBlock* stateBlock = _theme->getSpriteBatch()->getStateBlock();
+    stateBlock->setDepthWrite(true);
+    material->setStateBlock(stateBlock);
 
 
-        // Bind the WorldViewProjection matrix
-        material->setParameterAutoBinding("u_worldViewProjectionMatrix", RenderState::WORLD_VIEW_PROJECTION_MATRIX);
+    // Bind the WorldViewProjection matrix
+    material->setParameterAutoBinding("u_worldViewProjectionMatrix", RenderState::WORLD_VIEW_PROJECTION_MATRIX);
 
 
-        Texture::Sampler* sampler = Texture::Sampler::create(_frameBuffer->getRenderTarget()->getTexture());
-        sampler->setWrapMode(Texture::CLAMP, Texture::CLAMP);
-        material->getParameter("u_texture")->setValue(sampler);
-        material->getParameter("u_textureRepeat")->setValue(Vector2::one());
-        material->getParameter("u_textureTransform")->setValue(Vector2::zero());
+    Texture::Sampler* sampler = Texture::Sampler::create(_frameBuffer->getRenderTarget()->getTexture());
+    sampler->setWrapMode(Texture::CLAMP, Texture::CLAMP);
+    material->getParameter("u_diffuseTexture")->setValue(sampler);
+    material->getParameter("u_diffuseColor")->setValue(Vector4::one());
 
 
-        SAFE_RELEASE(sampler);
-    }
+    SAFE_RELEASE(sampler);
+}
 
 
-    bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+bool Form::touchEventInternal(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+{
+    // Check for a collision with each Form in __forms.
+    // Pass the event on.
+    std::vector<Form*>::const_iterator it;
+    for (it = __forms.begin(); it < __forms.end(); it++)
     {
     {
-        // Check for a collision with each Form in __forms.
-        // Pass the event on.
-        std::vector<Form*>::const_iterator it;
-        for (it = __forms.begin(); it < __forms.end(); it++)
-        {
-            Form* form = *it;
+        Form* form = *it;
 
 
-            if (form->isEnabled())
+        if (form->isEnabled())
+        {
+            Node* node = form->_node;
+            if (node)
             {
             {
-                Node* node = form->_node;
-                if (node)
-                {
-                    Scene* scene = node->getScene();
-                    Camera* camera = scene->getActiveCamera();
+                Scene* scene = node->getScene();
+                Camera* camera = scene->getActiveCamera();
 
 
-                    if (camera)
+                if (camera)
+                {
+                    // Get info about the form's position.
+                    Matrix m = node->getMatrix();
+                    Vector3 min(0, 0, 0);
+                    m.transformPoint(&min);
+
+                    // Unproject point into world space.
+                    Ray ray;
+                    camera->pickRay(Game::getInstance()->getViewport(), x, y, &ray);
+
+                    // Find the quad's plane.
+                    // We know its normal is the quad's forward vector.
+                    Vector3 normal = node->getForwardVectorWorld();
+
+                    // To get the plane's distance from the origin,
+                    // we'll find the distance from the plane defined
+                    // by the quad's forward vector and one of its points
+                    // to the plane defined by the same vector and the origin.
+                    const float& a = normal.x; const float& b = normal.y; const float& c = normal.z;
+                    const float d = -(a*min.x) - (b*min.y) - (c*min.z);
+                    const float distance = abs(d) /  sqrt(a*a + b*b + c*c);
+                    Plane plane(normal, -distance);
+
+                    // Check for collision with plane.
+                    float collisionDistance = ray.intersects(plane);
+                    if (collisionDistance != Ray::INTERSECTS_NONE)
                     {
                     {
-                        // Get info about the form's position.
-                        Matrix m = node->getMatrix();
-                        Vector3 min(0, 0, 0);
-                        m.transformPoint(&min);
-
-                        // Unproject point into world space.
-                        Ray ray;
-                        camera->pickRay(Game::getInstance()->getViewport(), x, y, &ray);
-
-                        // Find the quad's plane.
-                        // We know its normal is the quad's forward vector.
-                        Vector3 normal = node->getForwardVectorWorld();
-
-                        // To get the plane's distance from the origin,
-                        // we'll find the distance from the plane defined
-                        // by the quad's forward vector and one of its points
-                        // to the plane defined by the same vector and the origin.
-                        const float& a = normal.x; const float& b = normal.y; const float& c = normal.z;
-                        const float d = -(a*min.x) - (b*min.y) - (c*min.z);
-                        const float distance = abs(d) /  sqrt(a*a + b*b + c*c);
-                        Plane plane(normal, -distance);
-
-                        // Check for collision with plane.
-                        float collisionDistance = ray.intersects(plane);
-                        if (collisionDistance != Ray::INTERSECTS_NONE)
+                        // Multiply the ray's direction vector by collision distance
+                        // and add that to the ray's origin.
+                        Vector3 point = ray.getOrigin() + collisionDistance*ray.getDirection();
+
+                        // Project this point into the plane.
+                        m.invert();
+                        m.transformPoint(&point);
+
+                        // Pass the touch event on.
+                        const Rectangle& bounds = form->getBounds();
+                        if (form->getState() == Control::FOCUS ||
+                            (evt == Touch::TOUCH_PRESS &&
+                                point.x >= bounds.x &&
+                                point.x <= bounds.x + bounds.width &&
+                                point.y >= bounds.y &&
+                                point.y <= bounds.y + bounds.height))
                         {
                         {
-                            // Multiply the ray's direction vector by collision distance
-                            // and add that to the ray's origin.
-                            Vector3 point = ray.getOrigin() + collisionDistance*ray.getDirection();
-
-                            // Project this point into the plane.
-                            m.invert();
-                            m.transformPoint(&point);
-
-                            // Pass the touch event on.
-                            const Rectangle& bounds = form->getBounds();
-                            if (form->getState() == Control::FOCUS ||
-                                (evt == Touch::TOUCH_PRESS &&
-                                 point.x >= bounds.x &&
-                                 point.x <= bounds.x + bounds.width &&
-                                 point.y >= bounds.y &&
-                                 point.y <= bounds.y + bounds.height))
+                            if (form->touchEvent(evt, point.x - bounds.x, bounds.height - point.y - bounds.y, contactIndex))
                             {
                             {
-                               if (form->touchEvent(evt, point.x - bounds.x, bounds.height - point.y - bounds.y, contactIndex))
-                               {
-                                   return true;
-                               }
+                                return true;
                             }
                             }
                         }
                         }
                     }
                     }
                 }
                 }
-                else
+            }
+            else
+            {
+                // Simply compare with the form's bounds.
+                const Rectangle& bounds = form->getBounds();
+                if (form->getState() == Control::FOCUS ||
+                    (evt == Touch::TOUCH_PRESS &&
+                        x >= bounds.x &&
+                        x <= bounds.x + bounds.width &&
+                        y >= bounds.y &&
+                        y <= bounds.y + bounds.height))
                 {
                 {
-                    // Simply compare with the form's bounds.
-                    const Rectangle& bounds = form->getBounds();
-                    if (form->getState() == Control::FOCUS ||
-                        (evt == Touch::TOUCH_PRESS &&
-                         x >= bounds.x &&
-                         x <= bounds.x + bounds.width &&
-                         y >= bounds.y &&
-                         y <= bounds.y + bounds.height))
+                    // Pass on the event's position relative to the form.
+                    if (form->touchEvent(evt, x - bounds.x, y - bounds.y, contactIndex))
                     {
                     {
-                        // Pass on the event's position relative to the form.
-                        if (form->touchEvent(evt, x - bounds.x, y - bounds.y, contactIndex))
-                        {
-                            return true;
-                        }
+                        return true;
                     }
                     }
                 }
                 }
             }
             }
         }
         }
-
-        return false;
     }
     }
 
 
-    void Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
+    return false;
+}
+
+void Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
+{
+    std::vector<Form*>::const_iterator it;
+    for (it = __forms.begin(); it < __forms.end(); it++)
     {
     {
-        std::vector<Form*>::const_iterator it;
-        for (it = __forms.begin(); it < __forms.end(); it++)
+        Form* form = *it;
+        if (form->isEnabled())
         {
         {
-            Form* form = *it;
-            if (form->isEnabled())
-            {
-                form->keyEvent(evt, key);
-            }
+            form->keyEvent(evt, key);
         }
         }
     }
     }
-}
+}
+
+int Form::nextHighestPowerOfTwo(int x)
+{
+    x--;
+    x |= x >> 1;
+    x |= x >> 2;
+    x |= x >> 4;
+    x |= x >> 8;
+    x |= x >> 16;
+    return x + 1;
+}
+
+}

+ 6 - 0
gameplay/src/Form.h

@@ -157,12 +157,18 @@ private:
      */
      */
     static void keyEventInternal(Keyboard::KeyEvent evt, int key);
     static void keyEventInternal(Keyboard::KeyEvent evt, int key);
 
 
+    static int nextHighestPowerOfTwo(int x);
+
     Theme* _theme;              // The Theme applied to this Form.
     Theme* _theme;              // The Theme applied to this Form.
     Model* _quad;               // Quad for rendering this Form in world-space.
     Model* _quad;               // Quad for rendering this Form in world-space.
     Node* _node;                // Node for transforming this Form in world-space.
     Node* _node;                // Node for transforming this Form in world-space.
     FrameBuffer* _frameBuffer;  // FBO the Form is rendered into for texturing the quad.
     FrameBuffer* _frameBuffer;  // FBO the Form is rendered into for texturing the quad.
     Matrix _projectionMatrix;   // Orthographic projection matrix to be set on SpriteBatch objects when rendering into the FBO.
     Matrix _projectionMatrix;   // Orthographic projection matrix to be set on SpriteBatch objects when rendering into the FBO.
+    Matrix _defaultProjectionMatrix;
     SpriteBatch* _spriteBatch;
     SpriteBatch* _spriteBatch;
+
+    float _u2;
+    float _v1;
 };
 };
 
 
 }
 }

+ 68 - 66
gameplay/src/Label.cpp

@@ -3,92 +3,94 @@
 
 
 namespace gameplay
 namespace gameplay
 {
 {
-    Label::Label() : _text(""), _font(NULL)
-    {
-    }
 
 
-    Label::Label(const Label& copy)
-    {
-    }
+Label::Label() : _text(""), _font(NULL)
+{
+}
 
 
-    Label::~Label()
-    {
-    }
+Label::Label(const Label& copy)
+{
+}
 
 
-    Label* Label::create(Theme::Style* style, Properties* properties)
-    {
-        Label* label = new Label();
-        label->initialize(style, properties);
-        label->_consumeTouchEvents = false;
+Label::~Label()
+{
+}
 
 
-        return label;
-    }
+Label* Label::create(Theme::Style* style, Properties* properties)
+{
+    Label* label = new Label();
+    label->initialize(style, properties);
+    label->_consumeTouchEvents = false;
 
 
-    void Label::initialize(Theme::Style* style, Properties* properties)
-    {
-        Control::initialize(style, properties);
+    return label;
+}
 
 
-        const char* text = properties->getString("text");
-        if (text)
-        {
-            _text = text;
-        }
+void Label::initialize(Theme::Style* style, Properties* properties)
+{
+    Control::initialize(style, properties);
+
+    const char* text = properties->getString("text");
+    if (text)
+    {
+        _text = text;
     }
     }
+}
 
 
-    void Label::addListener(Control::Listener* listener, int eventFlags)
+void Label::addListener(Control::Listener* listener, int eventFlags)
+{
+    if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
     {
     {
-        if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
-        {
-            assert("TEXT_CHANGED event is not applicable to this control.");
-            eventFlags &= ~Listener::TEXT_CHANGED;
-        }
+        assert("TEXT_CHANGED event is not applicable to this control.");
+        eventFlags &= ~Listener::TEXT_CHANGED;
+    }
 
 
-        if ((eventFlags & Listener::VALUE_CHANGED) == Listener::VALUE_CHANGED)
-        {
-            assert("VALUE_CHANGED event is not applicable to this control.");
-            eventFlags &= ~Listener::VALUE_CHANGED;
-        }
+    if ((eventFlags & Listener::VALUE_CHANGED) == Listener::VALUE_CHANGED)
+    {
+        assert("VALUE_CHANGED event is not applicable to this control.");
+        eventFlags &= ~Listener::VALUE_CHANGED;
+    }
 
 
-        _consumeTouchEvents = true;
+    _consumeTouchEvents = true;
 
 
-        Control::addListener(listener, eventFlags);
-    }
+    Control::addListener(listener, eventFlags);
+}
     
     
-    void Label::setText(const char* text)
-    {
-        assert(text);
+void Label::setText(const char* text)
+{
+    assert(text);
 
 
-        _text = text;
-        _dirty = true;
-    }
+    _text = text;
+    _dirty = true;
+}
 
 
-    const char* Label::getText()
-    {
-        return _text.c_str();
-    }
+const char* Label::getText()
+{
+    return _text.c_str();
+}
 
 
-    void Label::update(const Rectangle& clip, const Vector2& offset)
-    {
-        Control::update(clip, offset);
+void Label::update(const Rectangle& clip, const Vector2& offset)
+{
+    Control::update(clip, offset);
 
 
-        _textBounds.set(_viewportBounds);
+    _textBounds.set(_viewportBounds);
 
 
-        _font = getFont(_state);
-        _textColor = getTextColor(_state);
-        _textColor.w *= getOpacity(_state);
-    }
+    _font = getFont(_state);
+    _textColor = getTextColor(_state);
+    _textColor.w *= getOpacity(_state);
+}
 
 
-    void Label::drawText(const Rectangle& clip)
+void Label::drawText(const Rectangle& clip)
+{
+    if (_text.size() <= 0)
+        return;
+
+    // Draw the text.
+    if (_font)
     {
     {
-        if (_text.size() <= 0)
-            return;
+        _font->drawText(_text.c_str(), _textBounds, _textColor, getFontSize(_state), getTextAlignment(_state), true, getTextRightToLeft(_state), &_viewportClipBounds);
+    }
 
 
-        // Draw the text.
-        if (_font)
-        {
-            _font->drawText(_text.c_str(), _textBounds, _textColor, getFontSize(_state), getTextAlignment(_state), true, getTextRightToLeft(_state), &_clip);
-        }
+    _dirty = false;
+}
 
 
-        _dirty = false;
-    }
 }
 }

+ 49 - 46
gameplay/src/Layout.cpp

@@ -5,55 +5,58 @@
 
 
 namespace gameplay
 namespace gameplay
 {
 {
-    void Layout::align(Control* control, const Container* container)
+
+void Layout::align(Control* control, const Container* container)
+{
+    if (control->_alignment != Control::ALIGN_TOP_LEFT ||
+        control->_autoWidth || control->_autoHeight)
     {
     {
-        if (control->_alignment != Control::ALIGN_TOP_LEFT ||
-            control->_autoWidth || control->_autoHeight)
+        Rectangle controlBounds = control->getBounds();
+        const Theme::Margin& controlMargin = control->getMargin();
+        const Rectangle& containerBounds = container->getBounds();
+        const Theme::Border& containerBorder = container->getBorder(container->getState());
+        const Theme::Padding& containerPadding = container->getPadding();
+
+        float clipWidth = containerBounds.width - containerBorder.left - containerBorder.right - containerPadding.left - containerPadding.right;
+        float clipHeight = containerBounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom;
+
+        if (control->_autoWidth)
         {
         {
-            Rectangle controlBounds = control->getBounds();
-            const Rectangle& containerBounds = container->getBounds();
-            const Theme::Border& containerBorder = container->getBorder(container->getState());
-            const Theme::Padding& containerPadding = container->getPadding();
-
-            float clipWidth = containerBounds.width - containerBorder.left - containerBorder.right - containerPadding.left - containerPadding.right;
-            float clipHeight = containerBounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom;
-
-            if (control->_autoWidth)
-            {
-                controlBounds.width = clipWidth;
-            }
-
-            if (control->_autoHeight)
-            {
-                controlBounds.height = clipHeight;
-            }
-
-            // Vertical alignment
-            if ((control->_alignment & Control::ALIGN_BOTTOM) == Control::ALIGN_BOTTOM)
-            {
-                controlBounds.y = clipHeight - controlBounds.height;
-            }
-            else if ((control->_alignment & Control::ALIGN_VCENTER) == Control::ALIGN_VCENTER)
-            {
-                controlBounds.y = clipHeight * 0.5f - controlBounds.height * 0.5f;
-            }
-
-            // Horizontal alignment
-            if ((control->_alignment & Control::ALIGN_RIGHT) == Control::ALIGN_RIGHT)
-            {
-                controlBounds.x = clipWidth - controlBounds.width;
-            }
-            else if ((control->_alignment & Control::ALIGN_HCENTER) == Control::ALIGN_HCENTER)
-            {
-                controlBounds.x = clipWidth * 0.5f - controlBounds.width * 0.5f;
-            }
-
-            control->setBounds(controlBounds);
+            controlBounds.width = clipWidth;
         }
         }
-    }
 
 
-    bool Layout::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
-    {
-        return false;
+        if (control->_autoHeight)
+        {
+            controlBounds.height = clipHeight;
+        }
+
+        // Vertical alignment
+        if ((control->_alignment & Control::ALIGN_BOTTOM) == Control::ALIGN_BOTTOM)
+        {
+            controlBounds.y = clipHeight - controlBounds.height;
+        }
+        else if ((control->_alignment & Control::ALIGN_VCENTER) == Control::ALIGN_VCENTER)
+        {
+            controlBounds.y = clipHeight * 0.5f - controlBounds.height * 0.5f;
+        }
+
+        // Horizontal alignment
+        if ((control->_alignment & Control::ALIGN_RIGHT) == Control::ALIGN_RIGHT)
+        {
+            controlBounds.x = clipWidth - controlBounds.width - controlMargin.right;
+        }
+        else if ((control->_alignment & Control::ALIGN_HCENTER) == Control::ALIGN_HCENTER)
+        {
+            controlBounds.x = clipWidth * 0.5f - controlBounds.width * 0.5f;
+        }
+
+        control->setBounds(controlBounds);
     }
     }
+}
+
+bool Layout::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
+{
+    return false;
+}
+
 }
 }

+ 1 - 1
gameplay/src/RadioButton.cpp

@@ -178,7 +178,7 @@ void RadioButton::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
 
 
     Vector2 pos(_viewportBounds.x, _viewportBounds.y + _viewportBounds.height * 0.5f - size.y * 0.5f);
     Vector2 pos(_viewportBounds.x, _viewportBounds.y + _viewportBounds.height * 0.5f - size.y * 0.5f);
 
 
-    spriteBatch->draw(pos.x, pos.y, size.x, size.y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _clip);
+    spriteBatch->draw(pos.x, pos.y, size.x, size.y, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
 }
 }
 
 
 }
 }

+ 4 - 4
gameplay/src/Slider.cpp

@@ -183,21 +183,21 @@ void Slider::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
     // Draw order: track, caps, marker.
     // Draw order: track, caps, marker.
     float midY = _viewportBounds.y + (_viewportBounds.height) * 0.5f;
     float midY = _viewportBounds.y + (_viewportBounds.height) * 0.5f;
     Vector2 pos(_viewportBounds.x, midY - trackRegion.height * 0.5f);
     Vector2 pos(_viewportBounds.x, midY - trackRegion.height * 0.5f);
-    spriteBatch->draw(pos.x, pos.y, _viewportBounds.width, trackRegion.height, track.u1, track.v1, track.u2, track.v2, trackColor, _clip);
+    spriteBatch->draw(pos.x, pos.y, _viewportBounds.width, trackRegion.height, track.u1, track.v1, track.u2, track.v2, trackColor, _viewportClipBounds);
 
 
     pos.y = midY - minCapRegion.height * 0.5f;
     pos.y = midY - minCapRegion.height * 0.5f;
     pos.x -= minCapRegion.width * 0.5f;
     pos.x -= minCapRegion.width * 0.5f;
-    spriteBatch->draw(pos.x, pos.y, minCapRegion.width, minCapRegion.height, minCap.u1, minCap.v1, minCap.u2, minCap.v2, minCapColor, _clip);
+    spriteBatch->draw(pos.x, pos.y, minCapRegion.width, minCapRegion.height, minCap.u1, minCap.v1, minCap.u2, minCap.v2, minCapColor, _viewportClipBounds);
         
         
     pos.x = _viewportBounds.x + _viewportBounds.width - maxCapRegion.width * 0.5f;
     pos.x = _viewportBounds.x + _viewportBounds.width - maxCapRegion.width * 0.5f;
-    spriteBatch->draw(pos.x, pos.y, maxCapRegion.width, maxCapRegion.height, maxCap.u1, maxCap.v1, maxCap.u2, maxCap.v2, maxCapColor, _clip);
+    spriteBatch->draw(pos.x, pos.y, maxCapRegion.width, maxCapRegion.height, maxCap.u1, maxCap.v1, maxCap.u2, maxCap.v2, maxCapColor, _viewportClipBounds);
 
 
     // Percent across.
     // Percent across.
     float markerPosition = (_value - _min) / (_max - _min);
     float markerPosition = (_value - _min) / (_max - _min);
     markerPosition *= _viewportBounds.width - minCapRegion.width * 0.5f - maxCapRegion.width * 0.5f - markerRegion.width;
     markerPosition *= _viewportBounds.width - minCapRegion.width * 0.5f - maxCapRegion.width * 0.5f - markerRegion.width;
     pos.x = _viewportBounds.x + minCapRegion.width * 0.5f + markerPosition;
     pos.x = _viewportBounds.x + minCapRegion.width * 0.5f + markerPosition;
     pos.y = midY - markerRegion.height / 2.0f;
     pos.y = midY - markerRegion.height / 2.0f;
-    spriteBatch->draw(pos.x, pos.y, markerRegion.width, markerRegion.height, marker.u1, marker.v1, marker.u2, marker.v2, markerColor, _clip);
+    spriteBatch->draw(pos.x, pos.y, markerRegion.width, markerRegion.height, marker.u1, marker.v1, marker.u2, marker.v2, markerColor, _viewportClipBounds);
 }
 }
 
 
 }
 }

+ 2 - 2
gameplay/src/TextBox.cpp

@@ -119,7 +119,7 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
                         // TODO: Move cursor to beginning of line.
                         // TODO: Move cursor to beginning of line.
                         // This only works for left alignment...
                         // This only works for left alignment...
                         
                         
-                        //_caretLocation.x = _clip.x;
+                        //_caretLocation.x = _viewportClipBounds.x;
                         //_dirty = true;
                         //_dirty = true;
                         break;
                         break;
                     }
                     }
@@ -306,7 +306,7 @@ void TextBox::drawImages(SpriteBatch* spriteBatch, const Rectangle& clip)
             Vector4 color = _caretImage->getColor();
             Vector4 color = _caretImage->getColor();
             color.w *= _opacity;
             color.w *= _opacity;
 
 
-            spriteBatch->draw(_caretLocation.x - (region.width / 2.0f), _caretLocation.y, region.width, _fontSize, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _clip);
+            spriteBatch->draw(_caretLocation.x - (region.width / 2.0f), _caretLocation.y, region.width, _fontSize, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color, _viewportClipBounds);
         }
         }
     }
     }
 
 

+ 618 - 616
gameplay/src/Theme.cpp

@@ -4,767 +4,769 @@
 
 
 namespace gameplay
 namespace gameplay
 {
 {
-    static std::vector<Theme*> __themeCache;
 
 
-    Theme::Theme()
+static std::vector<Theme*> __themeCache;
+
+Theme::Theme()
+{
+}
+
+Theme::Theme(const Theme& theme)
+{
+}
+
+Theme::~Theme()
+{
+    // Destroy all the cursors, styles and , fonts.
+    for (unsigned int i = 0, count = _styles.size(); i < count; ++i)
     {
     {
+        Style* style = _styles[i];
+        SAFE_DELETE(style);
     }
     }
 
 
-    Theme::Theme(const Theme& theme)
+    for (unsigned int i = 0, count = _images.size(); i < count; ++i)
     {
     {
+        ThemeImage* image = _images[i];
+        SAFE_RELEASE(image);
     }
     }
 
 
-    Theme::~Theme()
+    for (unsigned int i = 0, count = _imageLists.size(); i < count; ++i)
     {
     {
-        // Destroy all the cursors, styles and , fonts.
-        for (unsigned int i = 0, count = _styles.size(); i < count; ++i)
-        {
-            Style* style = _styles[i];
-            SAFE_DELETE(style);
-        }
+        ImageList* imageList = _imageLists[i];
+        SAFE_RELEASE(imageList);
+    }
 
 
-        for (unsigned int i = 0, count = _images.size(); i < count; ++i)
-        {
-            ThemeImage* image = _images[i];
-            SAFE_RELEASE(image);
-        }
+    for (unsigned int i = 0, count = _skins.size(); i < count; ++i)
+    {
+        Skin* skin = _skins[i];
+        SAFE_RELEASE(skin);
+    }
 
 
-        for (unsigned int i = 0, count = _imageLists.size(); i < count; ++i)
-        {
-            ImageList* imageList = _imageLists[i];
-            SAFE_RELEASE(imageList);
-        }
+    SAFE_DELETE(_spriteBatch);
+    SAFE_RELEASE(_texture);
 
 
-        for (unsigned int i = 0, count = _skins.size(); i < count; ++i)
-        {
-            Skin* skin = _skins[i];
-            SAFE_RELEASE(skin);
-        }
+    // Remove ourself from the theme cache.
+    std::vector<Theme*>::iterator itr = std::find(__themeCache.begin(), __themeCache.end(), this);
+    if (itr != __themeCache.end())
+    {
+        __themeCache.erase(itr);
+    }
+}
 
 
-        SAFE_DELETE(_spriteBatch);
-        SAFE_RELEASE(_texture);
+Theme* Theme::create(const char* url)
+{
+    assert(url);
 
 
-        // Remove ourself from the theme cache.
-        std::vector<Theme*>::iterator itr = std::find(__themeCache.begin(), __themeCache.end(), this);
-        if (itr != __themeCache.end())
+    // Search theme cache first.
+    for (unsigned int i = 0, count = __themeCache.size(); i < count; ++i)
+    {
+        Theme* t = __themeCache[i];
+        if (t->_url == url)
         {
         {
-            __themeCache.erase(itr);
+            // Found a match.
+            t->addRef();
+
+            return t;
         }
         }
     }
     }
 
 
-    Theme* Theme::create(const char* url)
+    // Load theme properties from file path.
+    Properties* properties = Properties::create(url);
+    assert(properties);
+    if (properties == NULL)
     {
     {
-        assert(url);
+        return NULL;
+    }
 
 
-        // Search theme cache first.
-        for (unsigned int i = 0, count = __themeCache.size(); i < count; ++i)
-        {
-            Theme* t = __themeCache[i];
-            if (t->_url == url)
-            {
-                // Found a match.
-                t->addRef();
+    // Check if the Properties is valid and has a valid namespace.
+    Properties* themeProperties = (strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace();
+    assert(themeProperties);
+    if (!themeProperties || !(strcmp(themeProperties->getNamespace(), "theme") == 0))
+    {
+        SAFE_DELETE(properties);
+        return NULL;
+    }
 
 
-                return t;
-            }
-        }
+    // Create a new theme.
+    Theme* theme = new Theme();
+    theme->_url = url;
+        
+    // Parse the Properties object and set up the theme.
+    const char* textureFile = themeProperties->getString("texture");
+    theme->_texture = Texture::create(textureFile, false);
+    theme->_spriteBatch = SpriteBatch::create(theme->_texture);
+
+    float tw = 1.0f / theme->_texture->getWidth();
+    float th = 1.0f / theme->_texture->getHeight();
 
 
-        // Load theme properties from file path.
-        Properties* properties = Properties::create(url);
-        assert(properties);
-        if (properties == NULL)
+    Properties* space = themeProperties->getNextNamespace();
+    while (space != NULL)
+    {
+        // First load all cursors, checkboxes etc. that can be referred to by styles.
+        const char* spacename = space->getNamespace();
+            
+        if (strcmp(spacename, "image") == 0)
         {
         {
-            return NULL;
+            theme->_images.push_back(ThemeImage::create(tw, th, space, Vector4::one()));
         }
         }
-
-        // Check if the Properties is valid and has a valid namespace.
-        Properties* themeProperties = (strlen(properties->getNamespace()) > 0) ? properties : properties->getNextNamespace();
-        assert(themeProperties);
-        if (!themeProperties || !(strcmp(themeProperties->getNamespace(), "theme") == 0))
+        else if (strcmp(spacename, "imageList") == 0)
         {
         {
-            SAFE_DELETE(properties);
-            return NULL;
+            theme->_imageLists.push_back(ImageList::create(tw, th, space));
         }
         }
-
-        // Create a new theme.
-        Theme* theme = new Theme();
-        theme->_url = url;
-        
-        // Parse the Properties object and set up the theme.
-        const char* textureFile = themeProperties->getString("texture");
-        theme->_texture = Texture::create(textureFile, false);
-        theme->_spriteBatch = SpriteBatch::create(theme->_texture);
-
-        float tw = 1.0f / theme->_texture->getWidth();
-        float th = 1.0f / theme->_texture->getHeight();
-
-        Properties* space = themeProperties->getNextNamespace();
-        while (space != NULL)
+        else if (strcmp(spacename, "skin") == 0)
         {
         {
-            // First load all cursors, checkboxes etc. that can be referred to by styles.
-            const char* spacename = space->getNamespace();
-            
-            if (strcmp(spacename, "image") == 0)
+            Theme::Border border;
+            Properties* innerSpace = space->getNextNamespace();
+            if (innerSpace)
             {
             {
-                theme->_images.push_back(ThemeImage::create(tw, th, space, Vector4::one()));
+                const char* innerSpacename = innerSpace->getNamespace();
+                if (strcmp(innerSpacename, "border") == 0)
+                {
+                    border.top = innerSpace->getFloat("top");
+                    border.bottom = innerSpace->getFloat("bottom");
+                    border.left = innerSpace->getFloat("left");
+                    border.right = innerSpace->getFloat("right");
+                }
             }
             }
-            else if (strcmp(spacename, "imageList") == 0)
+
+            Vector4 regionVector;
+            space->getVector4("region", &regionVector);
+            const Rectangle region(regionVector.x, regionVector.y, regionVector.z, regionVector.w);
+
+            Vector4 color(1, 1, 1, 1);
+            if (space->exists("color"))
             {
             {
-                theme->_imageLists.push_back(ImageList::create(tw, th, space));
+                space->getColor("color", &color);
             }
             }
-            else if (strcmp(spacename, "skin") == 0)
+
+            Skin* skin = Skin::create(space->getId(), tw, th, region, border, color);
+            theme->_skins.push_back(skin);
+        }
+
+        space = themeProperties->getNextNamespace();
+    }
+
+    themeProperties->rewind();
+    space = themeProperties->getNextNamespace();
+    while (space != NULL)
+    {
+        const char* spacename = space->getNamespace();
+        if (strcmp(spacename, "style") == 0)
+        {
+            // Each style contains up to MAX_OVERLAYS overlays,
+            // as well as Border and Padding namespaces.
+            Theme::Margin margin;
+            Theme::Padding padding;
+            Theme::Style::Overlay* normal = NULL;
+            Theme::Style::Overlay* focus = NULL;
+            Theme::Style::Overlay* active = NULL;
+            Theme::Style::Overlay* disabled = NULL;
+
+            // Need to load OVERLAY_NORMAL first so that the other overlays can inherit from it.
+            Properties* innerSpace = space->getNextNamespace();
+            while (innerSpace != NULL)
             {
             {
-                Theme::Border border;
-                Properties* innerSpace = space->getNextNamespace();
-                if (innerSpace)
+                const char* innerSpacename = innerSpace->getNamespace();
+                if (strcmp(innerSpacename, "stateNormal") == 0)
                 {
                 {
-                    const char* innerSpacename = innerSpace->getNamespace();
-                    if (strcmp(innerSpacename, "border") == 0)
+                    Vector4 textColor(0, 0, 0, 1);
+                    if (innerSpace->exists("textColor"))
                     {
                     {
-                        border.top = innerSpace->getFloat("top");
-                        border.bottom = innerSpace->getFloat("bottom");
-                        border.left = innerSpace->getFloat("left");
-                        border.right = innerSpace->getFloat("right");
+                        innerSpace->getColor("textColor", &textColor);
                     }
                     }
-                }
 
 
-                Vector4 regionVector;
-                space->getVector4("region", &regionVector);
-                const Rectangle region(regionVector.x, regionVector.y, regionVector.z, regionVector.w);
+                    const char* fontPath = innerSpace->getString("font");
+                    Font* font = NULL;
+                    if (fontPath)
+                    {
+                        font = Font::create(fontPath);
+                    }
+                    unsigned int fontSize = innerSpace->getInt("fontSize");
+                    const char* textAlignmentString = innerSpace->getString("textAlignment");
+                    Font::Justify textAlignment = Font::ALIGN_TOP_LEFT;
+                    if (textAlignmentString)
+                    {
+                        textAlignment = Font::getJustify(textAlignmentString);
+                    }
+                    bool rightToLeft = innerSpace->getBool("rightToLeft");
 
 
-                Vector4 color(1, 1, 1, 1);
-                if (space->exists("color"))
-                {
-                    space->getColor("color", &color);
+                    float opacity = 1.0f;
+                    if (innerSpace->exists("opacity"))
+                    {
+                        opacity = innerSpace->getFloat("opacity");
+                    }
+
+                    ImageList* imageList = NULL;
+                    ThemeImage* cursor = NULL;
+                    Skin* skin = NULL;
+                    theme->lookUpSprites(innerSpace, &imageList, &cursor, &skin);
+
+                    normal = Theme::Style::Overlay::create();
+                    normal->setSkin(skin);
+                    normal->setCursor(cursor);
+                    normal->setImageList(imageList);
+                    normal->setTextColor(textColor);
+                    normal->setFont(font);
+                    normal->setFontSize(fontSize);
+                    normal->setTextAlignment(textAlignment);
+                    normal->setTextRightToLeft(rightToLeft);
+                    normal->setOpacity(opacity);
+
+                    theme->_fonts.insert(font);
+
+                    if (font) font->release();
+
+                    // Done with this pass.
+                    break;
                 }
                 }
 
 
-                Skin* skin = Skin::create(space->getId(), tw, th, region, border, color);
-                theme->_skins.push_back(skin);
+                innerSpace = space->getNextNamespace();
             }
             }
 
 
-            space = themeProperties->getNextNamespace();
-        }
+            // At least the OVERLAY_NORMAL is required.
+            assert(normal);
 
 
-        themeProperties->rewind();
-        space = themeProperties->getNextNamespace();
-        while (space != NULL)
-        {
-            const char* spacename = space->getNamespace();
-            if (strcmp(spacename, "style") == 0)
+            space->rewind();
+            innerSpace = space->getNextNamespace();
+            while (innerSpace != NULL)
             {
             {
-                // Each style contains up to MAX_OVERLAYS overlays,
-                // as well as Border and Padding namespaces.
-                Theme::Margin margin;
-                Theme::Padding padding;
-                Theme::Style::Overlay* normal = NULL;
-                Theme::Style::Overlay* focus = NULL;
-                Theme::Style::Overlay* active = NULL;
-                Theme::Style::Overlay* disabled = NULL;
-
-                // Need to load OVERLAY_NORMAL first so that the other overlays can inherit from it.
-                Properties* innerSpace = space->getNextNamespace();
-                while (innerSpace != NULL)
+                const char* innerSpacename = innerSpace->getNamespace();
+                if (strcmp(innerSpacename, "margin") == 0)
+                {
+                    margin.top = innerSpace->getFloat("top");
+                    margin.bottom = innerSpace->getFloat("bottom");
+                    margin.left = innerSpace->getFloat("left");
+                    margin.right = innerSpace->getFloat("right");
+                }
+                else if (strcmp(innerSpacename, "padding") == 0)
+                {
+                    padding.top = innerSpace->getFloat("top");
+                    padding.bottom = innerSpace->getFloat("bottom");
+                    padding.left = innerSpace->getFloat("left");
+                    padding.right = innerSpace->getFloat("right");
+                }
+                else if (strcmp(innerSpacename, "stateNormal") != 0)
                 {
                 {
-                    const char* innerSpacename = innerSpace->getNamespace();
-                    if (strcmp(innerSpacename, "stateNormal") == 0)
+                    // Either OVERLAY_FOCUS or OVERLAY_ACTIVE.
+                    // If a property isn't specified, it inherits from OVERLAY_NORMAL.
+                    Vector4 textColor;
+                    if (!innerSpace->getColor("textColor", &textColor))
                     {
                     {
-                        Vector4 textColor(0, 0, 0, 1);
-                        if (innerSpace->exists("textColor"))
-                        {
-                            innerSpace->getColor("textColor", &textColor);
-                        }
-
-                        const char* fontPath = innerSpace->getString("font");
-                        Font* font = NULL;
-                        if (fontPath)
-                        {
-                            font = Font::create(fontPath);
-                        }
-                        unsigned int fontSize = innerSpace->getInt("fontSize");
-                        const char* textAlignmentString = innerSpace->getString("textAlignment");
-                        Font::Justify textAlignment = Font::ALIGN_TOP_LEFT;
-                        if (textAlignmentString)
-                        {
-                            textAlignment = Font::getJustify(textAlignmentString);
-                        }
-                        bool rightToLeft = innerSpace->getBool("rightToLeft");
-
-                        float opacity = 1.0f;
-                        if (innerSpace->exists("opacity"))
-                        {
-                            opacity = innerSpace->getFloat("opacity");
-                        }
-
-                        ImageList* imageList = NULL;
-                        ThemeImage* cursor = NULL;
-                        Skin* skin = NULL;
-                        theme->lookUpSprites(innerSpace, &imageList, &cursor, &skin);
-
-                        normal = Theme::Style::Overlay::create();
-                        normal->setSkin(skin);
-                        normal->setCursor(cursor);
-                        normal->setImageList(imageList);
-                        normal->setTextColor(textColor);
-                        normal->setFont(font);
-                        normal->setFontSize(fontSize);
-                        normal->setTextAlignment(textAlignment);
-                        normal->setTextRightToLeft(rightToLeft);
-                        normal->setOpacity(opacity);
-
-                        theme->_fonts.insert(font);
+                        textColor.set(normal->getTextColor());
+                    }
 
 
-                        if (font) font->release();
+                    const char* fontPath = innerSpace->getString("font");
+                    Font* font = NULL;
+                    if (fontPath)
+                    {
+                        font = Font::create(fontPath);
+                    }
+                    if (!font)
+                    {
+                        font = normal->getFont();
+                    }
 
 
-                        // Done with this pass.
-                        break;
+                    unsigned int fontSize;
+                    if (innerSpace->exists("fontSize"))
+                    {
+                        fontSize = innerSpace->getInt("fontSize");
+                    }
+                    else
+                    {
+                        fontSize = normal->getFontSize();
                     }
                     }
 
 
-                    innerSpace = space->getNextNamespace();
-                }
+                    const char* textAlignmentString = innerSpace->getString("textAlignment");
+                    Font::Justify textAlignment;
+                    if (textAlignmentString)
+                    {
+                        textAlignment = Font::getJustify(textAlignmentString);
+                    }
+                    else
+                    {
+                        textAlignment = normal->getTextAlignment();
+                    }
 
 
-                // At least the OVERLAY_NORMAL is required.
-                assert(normal);
+                    bool rightToLeft;
+                    if (innerSpace->exists("rightToLeft"))
+                    {
+                        rightToLeft = innerSpace->getBool("rightToLeft");
+                    }
+                    else
+                    {
+                        rightToLeft = normal->getTextRightToLeft();
+                    }
 
 
-                space->rewind();
-                innerSpace = space->getNextNamespace();
-                while (innerSpace != NULL)
-                {
-                    const char* innerSpacename = innerSpace->getNamespace();
-                    if (strcmp(innerSpacename, "margin") == 0)
+                    float opacity;
+                    if (innerSpace->exists("opacity"))
+                    {
+                        opacity = innerSpace->getFloat("opacity");
+                    }
+                    else
                     {
                     {
-                        margin.top = innerSpace->getFloat("top");
-                        margin.bottom = innerSpace->getFloat("bottom");
-                        margin.left = innerSpace->getFloat("left");
-                        margin.right = innerSpace->getFloat("right");
+                        opacity = normal->getOpacity();
                     }
                     }
-                    else if (strcmp(innerSpacename, "padding") == 0)
+
+                    ImageList* imageList = NULL;
+                    ThemeImage* cursor = NULL;
+                    Skin* skin = NULL;
+                    theme->lookUpSprites(innerSpace, &imageList, &cursor, &skin);
+
+                    if (!imageList)
                     {
                     {
-                        padding.top = innerSpace->getFloat("top");
-                        padding.bottom = innerSpace->getFloat("bottom");
-                        padding.left = innerSpace->getFloat("left");
-                        padding.right = innerSpace->getFloat("right");
+                        imageList = normal->getImageList();
                     }
                     }
-                    else if (strcmp(innerSpacename, "stateNormal") != 0)
+
+                    if (!cursor)
                     {
                     {
-                        // Either OVERLAY_FOCUS or OVERLAY_ACTIVE.
-                        // If a property isn't specified, it inherits from OVERLAY_NORMAL.
-                        Vector4 textColor;
-                        if (!innerSpace->getColor("textColor", &textColor))
-                        {
-                            textColor.set(normal->getTextColor());
-                        }
-
-                        const char* fontPath = innerSpace->getString("font");
-                        Font* font = NULL;
-                        if (fontPath)
-                        {
-                            font = Font::create(fontPath);
-                        }
-                        if (!font)
-                        {
-                            font = normal->getFont();
-                        }
-
-                        unsigned int fontSize;
-                        if (innerSpace->exists("fontSize"))
-                        {
-                            fontSize = innerSpace->getInt("fontSize");
-                        }
-                        else
-                        {
-                            fontSize = normal->getFontSize();
-                        }
-
-                        const char* textAlignmentString = innerSpace->getString("textAlignment");
-                        Font::Justify textAlignment;
-                        if (textAlignmentString)
-                        {
-                            textAlignment = Font::getJustify(textAlignmentString);
-                        }
-                        else
-                        {
-                            textAlignment = normal->getTextAlignment();
-                        }
-
-                        bool rightToLeft;
-                        if (innerSpace->exists("rightToLeft"))
-                        {
-                            rightToLeft = innerSpace->getBool("rightToLeft");
-                        }
-                        else
-                        {
-                            rightToLeft = normal->getTextRightToLeft();
-                        }
-
-                        float opacity;
-                        if (innerSpace->exists("opacity"))
-                        {
-                            opacity = innerSpace->getFloat("opacity");
-                        }
-                        else
-                        {
-                            opacity = normal->getOpacity();
-                        }
-
-                        ImageList* imageList = NULL;
-                        ThemeImage* cursor = NULL;
-                        Skin* skin = NULL;
-                        theme->lookUpSprites(innerSpace, &imageList, &cursor, &skin);
-
-                        if (!imageList)
-                        {
-                            imageList = normal->getImageList();
-                        }
-
-                        if (!cursor)
-                        {
-                            cursor = normal->getCursor();
-                        }
+                        cursor = normal->getCursor();
+                    }
                         
                         
-                        if (!skin)
-                        {
-                            skin = normal->getSkin();
-                        }
-
-                        if (strcmp(innerSpacename, "stateFocus") == 0)
-                        {
-                            focus = Theme::Style::Overlay::create();
-                            focus->setSkin(skin);
-                            focus->setCursor(cursor);
-                            focus->setImageList(imageList);
-                            focus->setTextColor(textColor);
-                            focus->setFont(font);
-                            focus->setFontSize(fontSize);
-                            focus->setTextAlignment(textAlignment);
-                            focus->setTextRightToLeft(rightToLeft);
-                            focus->setOpacity(opacity);
-
-                            theme->_fonts.insert(font);
-                        }
-                        else if (strcmp(innerSpacename, "stateActive") == 0)
-                        {
-                            active = Theme::Style::Overlay::create();
-                            active->setSkin(skin);
-                            active->setCursor(cursor);
-                            active->setImageList(imageList);
-                            active->setTextColor(textColor);
-                            active->setFont(font);
-                            active->setFontSize(fontSize);
-                            active->setTextAlignment(textAlignment);
-                            active->setTextRightToLeft(rightToLeft);
-                            active->setOpacity(opacity);
-
-                            theme->_fonts.insert(font);
-                        }
-                        else if (strcmp(innerSpacename, "stateDisabled") == 0)
-                        {
-                            disabled = Theme::Style::Overlay::create();
-                            disabled->setSkin(skin);
-                            disabled->setCursor(cursor);
-                            disabled->setImageList(imageList);
-                            disabled->setTextColor(textColor);
-                            disabled->setFont(font);
-                            disabled->setFontSize(fontSize);
-                            disabled->setTextAlignment(textAlignment);
-                            disabled->setTextRightToLeft(rightToLeft);
-                            disabled->setOpacity(opacity);
-
-                            theme->_fonts.insert(font);
-                        }
+                    if (!skin)
+                    {
+                        skin = normal->getSkin();
                     }
                     }
 
 
-                    innerSpace = space->getNextNamespace();
-                }
-                
-                if (!focus)
-                {
-                    focus = normal;
-                    focus->addRef();
-                }
+                    if (strcmp(innerSpacename, "stateFocus") == 0)
+                    {
+                        focus = Theme::Style::Overlay::create();
+                        focus->setSkin(skin);
+                        focus->setCursor(cursor);
+                        focus->setImageList(imageList);
+                        focus->setTextColor(textColor);
+                        focus->setFont(font);
+                        focus->setFontSize(fontSize);
+                        focus->setTextAlignment(textAlignment);
+                        focus->setTextRightToLeft(rightToLeft);
+                        focus->setOpacity(opacity);
 
 
-                if (!active)
-                {
-                    active = normal;
-                    active->addRef();
-                }
+                        theme->_fonts.insert(font);
+                    }
+                    else if (strcmp(innerSpacename, "stateActive") == 0)
+                    {
+                        active = Theme::Style::Overlay::create();
+                        active->setSkin(skin);
+                        active->setCursor(cursor);
+                        active->setImageList(imageList);
+                        active->setTextColor(textColor);
+                        active->setFont(font);
+                        active->setFontSize(fontSize);
+                        active->setTextAlignment(textAlignment);
+                        active->setTextRightToLeft(rightToLeft);
+                        active->setOpacity(opacity);
 
 
-                if (!disabled)
-                {
-                    disabled = normal;
-                    disabled->addRef();
+                        theme->_fonts.insert(font);
+                    }
+                    else if (strcmp(innerSpacename, "stateDisabled") == 0)
+                    {
+                        disabled = Theme::Style::Overlay::create();
+                        disabled->setSkin(skin);
+                        disabled->setCursor(cursor);
+                        disabled->setImageList(imageList);
+                        disabled->setTextColor(textColor);
+                        disabled->setFont(font);
+                        disabled->setFontSize(fontSize);
+                        disabled->setTextAlignment(textAlignment);
+                        disabled->setTextRightToLeft(rightToLeft);
+                        disabled->setOpacity(opacity);
+
+                        theme->_fonts.insert(font);
+                    }
                 }
                 }
 
 
-                Theme::Style* s = new Theme::Style(theme, space->getId(), tw, th, margin, padding, normal, focus, active, disabled);
-                theme->_styles.push_back(s);
+                innerSpace = space->getNextNamespace();
+            }
+                
+            if (!focus)
+            {
+                focus = normal;
+                focus->addRef();
             }
             }
 
 
-            space = themeProperties->getNextNamespace();
-        }
-
-        // Add this theme to the cache.
-        __themeCache.push_back(theme);
-
-        SAFE_DELETE(properties);
-
-        return theme;
-    }
+            if (!active)
+            {
+                active = normal;
+                active->addRef();
+            }
 
 
-    Theme::Style* Theme::getStyle(const char* name) const
-    {
-        for (unsigned int i = 0, count = _styles.size(); i < count; ++i)
-        {
-            if (strcmp(name, _styles[i]->getId()) == 0)
+            if (!disabled)
             {
             {
-                return _styles[i];
+                disabled = normal;
+                disabled->addRef();
             }
             }
+
+            Theme::Style* s = new Theme::Style(theme, space->getId(), tw, th, margin, padding, normal, focus, active, disabled);
+            theme->_styles.push_back(s);
         }
         }
 
 
-        return NULL;
+        space = themeProperties->getNextNamespace();
     }
     }
 
 
-    void Theme::setProjectionMatrix(const Matrix& matrix)
-    {
-        _spriteBatch->setProjectionMatrix(matrix);
+    // Add this theme to the cache.
+    __themeCache.push_back(theme);
 
 
-        // Set the matrix on each Font used by the style.
-        std::set<Font*>::const_iterator it;
-        for (it = _fonts.begin(); it != _fonts.end(); ++it)
-        {
-            Font* font = *it;
-            if (font)
-                font->getSpriteBatch()->setProjectionMatrix(matrix);
-        }
-    }
+    SAFE_DELETE(properties);
 
 
-    SpriteBatch* Theme::getSpriteBatch() const
-    {
-        return _spriteBatch;
-    }
+    return theme;
+}
 
 
-    /**************
-     * Theme::UVs *
-     **************/
-    Theme::UVs::UVs()
-        : u1(0), v1(0), u2(0), v2(0)
+Theme::Style* Theme::getStyle(const char* name) const
+{
+    for (unsigned int i = 0, count = _styles.size(); i < count; ++i)
     {
     {
+        if (strcmp(name, _styles[i]->getId()) == 0)
+        {
+            return _styles[i];
+        }
     }
     }
 
 
-    Theme::UVs::UVs(float u1, float v1, float u2, float v2)
-        : u1(u1), v1(v1), u2(u2), v2(v2)
-    {
-    }
+    return NULL;
+}
 
 
-    const Theme::UVs& Theme::UVs::empty()
-    {
-        static UVs empty(0, 0, 0, 0);
-        return empty;
-    }
+void Theme::setProjectionMatrix(const Matrix& matrix)
+{
+    _spriteBatch->setProjectionMatrix(matrix);
 
 
-    /**********************
-     * Theme::SideRegions *
-     **********************/
-    const Theme::SideRegions& Theme::SideRegions::empty()
+    // Set the matrix on each Font used by the style.
+    std::set<Font*>::const_iterator it;
+    for (it = _fonts.begin(); it != _fonts.end(); ++it)
     {
     {
-        static SideRegions empty;
-        return empty;
+        Font* font = *it;
+        if (font)
+            font->getSpriteBatch()->setProjectionMatrix(matrix);
     }
     }
+}
 
 
-    /****************
-     * Theme::ThemeImage *
-     ****************/
-    Theme::ThemeImage::ThemeImage(float tw, float th, const Rectangle& region, const Vector4& color)
-        : _region(region), _color(color)
-    {
-        generateUVs(tw, th, region.x, region.y, region.width, region.height, &_uvs);
-    }
+SpriteBatch* Theme::getSpriteBatch() const
+{
+    return _spriteBatch;
+}
 
 
-    Theme::ThemeImage::~ThemeImage()
-    {
-    }
+/**************
+    * Theme::UVs *
+    **************/
+Theme::UVs::UVs()
+    : u1(0), v1(0), u2(0), v2(0)
+{
+}
 
 
-    Theme::ThemeImage* Theme::ThemeImage::create(float tw, float th, Properties* properties, const Vector4& defaultColor)
-    {
-        Vector4 regionVector;                
-        properties->getVector4("region", &regionVector);
-        const Rectangle region(regionVector.x, regionVector.y, regionVector.z, regionVector.w);
+Theme::UVs::UVs(float u1, float v1, float u2, float v2)
+    : u1(u1), v1(v1), u2(u2), v2(v2)
+{
+}
 
 
-        Vector4 color;
-        if (properties->exists("color"))
-        {
-            properties->getColor("color", &color);
-        }
-        else
-        {
-            color.set(defaultColor);
-        }
+const Theme::UVs& Theme::UVs::empty()
+{
+    static UVs empty(0, 0, 0, 0);
+    return empty;
+}
 
 
-        ThemeImage* image = new ThemeImage(tw, th, region, color);
-        const char* id = properties->getId();
-        if (id)
-        {
-            image->_id = id;
-        }
+/**********************
+    * Theme::SideRegions *
+    **********************/
+const Theme::SideRegions& Theme::SideRegions::empty()
+{
+    static SideRegions empty;
+    return empty;
+}
 
 
-        return image;
-    }
+/****************
+    * Theme::ThemeImage *
+    ****************/
+Theme::ThemeImage::ThemeImage(float tw, float th, const Rectangle& region, const Vector4& color)
+    : _region(region), _color(color)
+{
+    generateUVs(tw, th, region.x, region.y, region.width, region.height, &_uvs);
+}
 
 
-    const char* Theme::ThemeImage::getId() const
-    {
-        return _id.c_str();
-    }
+Theme::ThemeImage::~ThemeImage()
+{
+}
 
 
-    const Theme::UVs& Theme::ThemeImage::getUVs() const
-    {
-        return _uvs;
-    }
+Theme::ThemeImage* Theme::ThemeImage::create(float tw, float th, Properties* properties, const Vector4& defaultColor)
+{
+    Vector4 regionVector;                
+    properties->getVector4("region", &regionVector);
+    const Rectangle region(regionVector.x, regionVector.y, regionVector.z, regionVector.w);
 
 
-    const Rectangle& Theme::ThemeImage::getRegion() const
+    Vector4 color;
+    if (properties->exists("color"))
     {
     {
-        return _region;
+        properties->getColor("color", &color);
     }
     }
-
-    const Vector4& Theme::ThemeImage::getColor() const
+    else
     {
     {
-        return _color;
+        color.set(defaultColor);
     }
     }
 
 
-    /********************
-     * Theme::ImageList *
-     ********************/
-    Theme::ImageList::ImageList(const Vector4& color) : _color(color)
+    ThemeImage* image = new ThemeImage(tw, th, region, color);
+    const char* id = properties->getId();
+    if (id)
     {
     {
+        image->_id = id;
     }
     }
 
 
-    Theme::ImageList::ImageList(const ImageList& copy)
-    {
-        _id = copy._id;
-        _color = copy._color;
-
-        std::vector<ThemeImage*>::const_iterator it;
-        for (it = copy._images.begin(); it != copy._images.end(); it++)
-        {
-            ThemeImage* image = *it;
-            _images.push_back(new ThemeImage(*image));
-        }
-    }
+    return image;
+}
 
 
-    Theme::ImageList::~ImageList()
-    {
-        std::vector<ThemeImage*>::const_iterator it;
-        for (it = _images.begin(); it != _images.end(); it++)
-        {
-            ThemeImage* image = *it;
-            SAFE_RELEASE(image);
-        }
-    }
+const char* Theme::ThemeImage::getId() const
+{
+    return _id.c_str();
+}
 
 
-    Theme::ImageList* Theme::ImageList::create(float tw, float th, Properties* properties)
-    {
-        Vector4 color(1, 1, 1, 1);
-        if (properties->exists("color"))
-        {
-            properties->getColor("color", &color);
-        }
+const Theme::UVs& Theme::ThemeImage::getUVs() const
+{
+    return _uvs;
+}
 
 
-        ImageList* imageList = new ImageList(color);
+const Rectangle& Theme::ThemeImage::getRegion() const
+{
+    return _region;
+}
 
 
-        const char* id = properties->getId();
-        if (id)
-        {
-            imageList->_id = id;
-        }
+const Vector4& Theme::ThemeImage::getColor() const
+{
+    return _color;
+}
 
 
-        Properties* space = properties->getNextNamespace();
-        while (space != NULL)
-        {
-            ThemeImage* image = ThemeImage::create(tw, th, space, color);
-            imageList->_images.push_back(image);
-            space = properties->getNextNamespace();
-        }
+/********************
+    * Theme::ImageList *
+    ********************/
+Theme::ImageList::ImageList(const Vector4& color) : _color(color)
+{
+}
 
 
-        return imageList;
-    }
+Theme::ImageList::ImageList(const ImageList& copy)
+{
+    _id = copy._id;
+    _color = copy._color;
 
 
-    const char* Theme::ImageList::getId() const
+    std::vector<ThemeImage*>::const_iterator it;
+    for (it = copy._images.begin(); it != copy._images.end(); it++)
     {
     {
-        return _id.c_str();
+        ThemeImage* image = *it;
+        _images.push_back(new ThemeImage(*image));
     }
     }
+}
 
 
-    Theme::ThemeImage* Theme::ImageList::getImage(const char* imageId) const
+Theme::ImageList::~ImageList()
+{
+    std::vector<ThemeImage*>::const_iterator it;
+    for (it = _images.begin(); it != _images.end(); it++)
     {
     {
-        std::vector<ThemeImage*>::const_iterator it;
-        for (it = _images.begin(); it != _images.end(); it++)
-        {
-            ThemeImage* image = *it;
-            if (strcmp(image->getId(), imageId) == 0)
-            {
-                return image;
-            }
-        }
-
-        return NULL;
+        ThemeImage* image = *it;
+        SAFE_RELEASE(image);
     }
     }
+}
 
 
-    /***************
-     * Theme::Skin *
-     ***************/
-    Theme::Skin* Theme::Skin::create(const char* id, float tw, float th, const Rectangle& region, const Theme::Border& border, const Vector4& color)
+Theme::ImageList* Theme::ImageList::create(float tw, float th, Properties* properties)
+{
+    Vector4 color(1, 1, 1, 1);
+    if (properties->exists("color"))
     {
     {
-        Skin* skin = new Skin(tw, th, region, border, color);
-
-        if (id)
-        {
-            skin->_id = id;
-        }
-
-        return skin;
+        properties->getColor("color", &color);
     }
     }
 
 
-    Theme::Skin::Skin(float tw, float th, const Rectangle& region, const Theme::Border& border, const Vector4& color)
-        : _border(border), _color(color), _region(region)
-    {
-        setRegion(region, tw, th);
-    }
+    ImageList* imageList = new ImageList(color);
 
 
-    Theme::Skin::~Skin()
+    const char* id = properties->getId();
+    if (id)
     {
     {
+        imageList->_id = id;
     }
     }
 
 
-    const char* Theme::Skin::getId() const
+    Properties* space = properties->getNextNamespace();
+    while (space != NULL)
     {
     {
-        return _id.c_str();
+        ThemeImage* image = ThemeImage::create(tw, th, space, color);
+        imageList->_images.push_back(image);
+        space = properties->getNextNamespace();
     }
     }
 
 
-    const Theme::Border& Theme::Skin::getBorder() const
-    {
-        return _border;
-    }
+    return imageList;
+}
 
 
-    const Rectangle& Theme::Skin::getRegion() const
-    {
-        return _region;
-    }
+const char* Theme::ImageList::getId() const
+{
+    return _id.c_str();
+}
 
 
-    void Theme::Skin::setRegion(const Rectangle& region, float tw, float th)
+Theme::ThemeImage* Theme::ImageList::getImage(const char* imageId) const
+{
+    std::vector<ThemeImage*>::const_iterator it;
+    for (it = _images.begin(); it != _images.end(); it++)
     {
     {
-        // Can calculate all measurements in advance.
-        float leftEdge = region.x * tw;
-        float rightEdge = (region.x + region.width) * tw;
-        float leftBorder = (region.x + _border.left) * tw;
-        float rightBorder = (region.x + region.width - _border.right) * tw;
-
-        float topEdge = 1.0f - (region.y * th);
-        float bottomEdge = 1.0f - ((region.y + region.height) * th);
-        float topBorder = 1.0f - ((region.y + _border.top) * th);
-        float bottomBorder = 1.0f - ((region.y + region.height - _border.bottom) * th);
-
-        // There are 9 sets of UVs to set.
-        _uvs[TOP_LEFT].u1 = leftEdge;
-        _uvs[TOP_LEFT].v1 = topEdge;
-        _uvs[TOP_LEFT].u2 = leftBorder;
-        _uvs[TOP_LEFT].v2 = topBorder;
-
-        _uvs[TOP].u1 = leftBorder;
-        _uvs[TOP].v1 = topEdge;
-        _uvs[TOP].u2 = rightBorder;
-        _uvs[TOP].v2 = topBorder;
-
-        _uvs[TOP_RIGHT].u1 = rightBorder;
-        _uvs[TOP_RIGHT].v1 = topEdge;
-        _uvs[TOP_RIGHT].u2 = rightEdge;
-        _uvs[TOP_RIGHT].v2 = topBorder;
-
-        _uvs[LEFT].u1 = leftEdge;
-        _uvs[LEFT].v1 = topBorder;
-        _uvs[LEFT].u2 = leftBorder;
-        _uvs[LEFT].v2 = bottomBorder;
-
-        _uvs[CENTER].u1 = leftBorder;
-        _uvs[CENTER].v1 = topBorder;
-        _uvs[CENTER].u2 = rightBorder;
-        _uvs[CENTER].v2 = bottomBorder;
-
-        _uvs[RIGHT].u1 = rightBorder;
-        _uvs[RIGHT].v1 = topBorder;
-        _uvs[RIGHT].u2 = rightEdge;
-        _uvs[RIGHT].v2 = bottomBorder;
-
-        _uvs[BOTTOM_LEFT].u1 = leftEdge;
-        _uvs[BOTTOM_LEFT].v1 = bottomBorder;
-        _uvs[BOTTOM_LEFT].u2 = leftBorder;
-        _uvs[BOTTOM_LEFT].v2 = bottomEdge;
-
-        _uvs[BOTTOM].u1 = leftBorder;
-        _uvs[BOTTOM].v1 = bottomBorder;
-        _uvs[BOTTOM].u2 = rightBorder;
-        _uvs[BOTTOM].v2 = bottomEdge;
-
-        _uvs[BOTTOM_RIGHT].u1 = rightBorder;
-        _uvs[BOTTOM_RIGHT].v1 = bottomBorder;
-        _uvs[BOTTOM_RIGHT].u2 = rightEdge;
-        _uvs[BOTTOM_RIGHT].v2 = bottomEdge;
+        ThemeImage* image = *it;
+        if (strcmp(image->getId(), imageId) == 0)
+        {
+            return image;
+        }
     }
     }
 
 
-    const Theme::UVs& Theme::Skin::getUVs(SkinArea area) const
-    {
-        return _uvs[area];
-    }
+    return NULL;
+}
+
+/***************
+    * Theme::Skin *
+    ***************/
+Theme::Skin* Theme::Skin::create(const char* id, float tw, float th, const Rectangle& region, const Theme::Border& border, const Vector4& color)
+{
+    Skin* skin = new Skin(tw, th, region, border, color);
 
 
-    const Vector4& Theme::Skin::getColor() const
+    if (id)
     {
     {
-        return _color;
+        skin->_id = id;
     }
     }
+
+    return skin;
+}
+
+Theme::Skin::Skin(float tw, float th, const Rectangle& region, const Theme::Border& border, const Vector4& color)
+    : _border(border), _color(color), _region(region)
+{
+    setRegion(region, tw, th);
+}
+
+Theme::Skin::~Skin()
+{
+}
+
+const char* Theme::Skin::getId() const
+{
+    return _id.c_str();
+}
+
+const Theme::Border& Theme::Skin::getBorder() const
+{
+    return _border;
+}
+
+const Rectangle& Theme::Skin::getRegion() const
+{
+    return _region;
+}
+
+void Theme::Skin::setRegion(const Rectangle& region, float tw, float th)
+{
+    // Can calculate all measurements in advance.
+    float leftEdge = region.x * tw;
+    float rightEdge = (region.x + region.width) * tw;
+    float leftBorder = (region.x + _border.left) * tw;
+    float rightBorder = (region.x + region.width - _border.right) * tw;
+
+    float topEdge = 1.0f - (region.y * th);
+    float bottomEdge = 1.0f - ((region.y + region.height) * th);
+    float topBorder = 1.0f - ((region.y + _border.top) * th);
+    float bottomBorder = 1.0f - ((region.y + region.height - _border.bottom) * th);
+
+    // There are 9 sets of UVs to set.
+    _uvs[TOP_LEFT].u1 = leftEdge;
+    _uvs[TOP_LEFT].v1 = topEdge;
+    _uvs[TOP_LEFT].u2 = leftBorder;
+    _uvs[TOP_LEFT].v2 = topBorder;
+
+    _uvs[TOP].u1 = leftBorder;
+    _uvs[TOP].v1 = topEdge;
+    _uvs[TOP].u2 = rightBorder;
+    _uvs[TOP].v2 = topBorder;
+
+    _uvs[TOP_RIGHT].u1 = rightBorder;
+    _uvs[TOP_RIGHT].v1 = topEdge;
+    _uvs[TOP_RIGHT].u2 = rightEdge;
+    _uvs[TOP_RIGHT].v2 = topBorder;
+
+    _uvs[LEFT].u1 = leftEdge;
+    _uvs[LEFT].v1 = topBorder;
+    _uvs[LEFT].u2 = leftBorder;
+    _uvs[LEFT].v2 = bottomBorder;
+
+    _uvs[CENTER].u1 = leftBorder;
+    _uvs[CENTER].v1 = topBorder;
+    _uvs[CENTER].u2 = rightBorder;
+    _uvs[CENTER].v2 = bottomBorder;
+
+    _uvs[RIGHT].u1 = rightBorder;
+    _uvs[RIGHT].v1 = topBorder;
+    _uvs[RIGHT].u2 = rightEdge;
+    _uvs[RIGHT].v2 = bottomBorder;
+
+    _uvs[BOTTOM_LEFT].u1 = leftEdge;
+    _uvs[BOTTOM_LEFT].v1 = bottomBorder;
+    _uvs[BOTTOM_LEFT].u2 = leftBorder;
+    _uvs[BOTTOM_LEFT].v2 = bottomEdge;
+
+    _uvs[BOTTOM].u1 = leftBorder;
+    _uvs[BOTTOM].v1 = bottomBorder;
+    _uvs[BOTTOM].u2 = rightBorder;
+    _uvs[BOTTOM].v2 = bottomEdge;
+
+    _uvs[BOTTOM_RIGHT].u1 = rightBorder;
+    _uvs[BOTTOM_RIGHT].v1 = bottomBorder;
+    _uvs[BOTTOM_RIGHT].u2 = rightEdge;
+    _uvs[BOTTOM_RIGHT].v2 = bottomEdge;
+}
+
+const Theme::UVs& Theme::Skin::getUVs(SkinArea area) const
+{
+    return _uvs[area];
+}
+
+const Vector4& Theme::Skin::getColor() const
+{
+    return _color;
+}
     
     
-    /**
-     * Theme utility methods.
-     */
-    void Theme::generateUVs(float tw, float th, float x, float y, float width, float height, UVs* uvs)
-    {
-        uvs->u1 = x * tw;
-        uvs->u2 = (x + width) * tw;
-        uvs->v1 = 1.0f - (y * th);
-        uvs->v2 = 1.0f - ((y + height) * th);
-    }
+/**
+    * Theme utility methods.
+    */
+void Theme::generateUVs(float tw, float th, float x, float y, float width, float height, UVs* uvs)
+{
+    uvs->u1 = x * tw;
+    uvs->u2 = (x + width) * tw;
+    uvs->v1 = 1.0f - (y * th);
+    uvs->v2 = 1.0f - ((y + height) * th);
+}
 
 
-    void Theme::lookUpSprites(const Properties* overlaySpace, ImageList** imageList, ThemeImage** cursor, Skin** Skin)
+void Theme::lookUpSprites(const Properties* overlaySpace, ImageList** imageList, ThemeImage** cursor, Skin** Skin)
+{
+    const char* imageListString = overlaySpace->getString("imageList");
+    if (imageListString)
     {
     {
-        const char* imageListString = overlaySpace->getString("imageList");
-        if (imageListString)
+        for (unsigned int i = 0; i < _imageLists.size(); ++i)
         {
         {
-            for (unsigned int i = 0; i < _imageLists.size(); ++i)
+            if (strcmp(_imageLists[i]->getId(), imageListString) == 0)
             {
             {
-                if (strcmp(_imageLists[i]->getId(), imageListString) == 0)
-                {
-                    *imageList = _imageLists[i];
-                    break;
-                }
+                *imageList = _imageLists[i];
+                break;
             }
             }
         }
         }
+    }
 
 
-        const char* cursorString = overlaySpace->getString("cursor");
-        if (cursorString)
+    const char* cursorString = overlaySpace->getString("cursor");
+    if (cursorString)
+    {
+        for (unsigned int i = 0; i < _images.size(); ++i)
         {
         {
-            for (unsigned int i = 0; i < _images.size(); ++i)
+            if (strcmp(_images[i]->getId(), cursorString) == 0)
             {
             {
-                if (strcmp(_images[i]->getId(), cursorString) == 0)
-                {
-                    *cursor = _images[i];
-                    break;
-                }
+                *cursor = _images[i];
+                break;
             }
             }
         }
         }
+    }
 
 
-        const char* skinString = overlaySpace->getString("skin");
-        if (skinString)
+    const char* skinString = overlaySpace->getString("skin");
+    if (skinString)
+    {
+        for (unsigned int i = 0; i < _skins.size(); ++i)
         {
         {
-            for (unsigned int i = 0; i < _skins.size(); ++i)
+            if (strcmp(_skins[i]->getId(), skinString) == 0)
             {
             {
-                if (strcmp(_skins[i]->getId(), skinString) == 0)
-                {
-                    *Skin = _skins[i];
-                    break;
-                }
+                *Skin = _skins[i];
+                break;
             }
             }
         }
         }
     }
     }
 }
 }
+
+}

+ 64 - 61
gameplay/src/VerticalLayout.cpp

@@ -3,88 +3,91 @@
 
 
 namespace gameplay
 namespace gameplay
 {
 {
-    static VerticalLayout* __instance;
 
 
-    VerticalLayout::VerticalLayout() : _bottomToTop(false)
-    {
-    }
+static VerticalLayout* __instance;
 
 
-    VerticalLayout::VerticalLayout(const VerticalLayout& copy)
+VerticalLayout::VerticalLayout() : _bottomToTop(false)
+{
+}
+
+VerticalLayout::VerticalLayout(const VerticalLayout& copy)
+{
+}
+
+VerticalLayout::~VerticalLayout()
+{
+    __instance = NULL;
+}
+
+VerticalLayout* VerticalLayout::create()
+{
+    if (!__instance)
     {
     {
+        __instance = new VerticalLayout();
     }
     }
-
-    VerticalLayout::~VerticalLayout()
+    else
     {
     {
+        __instance->addRef();
     }
     }
 
 
-    VerticalLayout* VerticalLayout::create()
-    {
-        if (!__instance)
-        {
-            __instance = new VerticalLayout();
-        }
-        else
-        {
-            __instance->addRef();
-        }
+    return __instance;
+}
 
 
-        return __instance;
-    }
+void VerticalLayout::setBottomToTop(bool bottomToTop)
+{
+    _bottomToTop = bottomToTop;
+}
 
 
-    void VerticalLayout::setBottomToTop(bool bottomToTop)
+Layout::Type VerticalLayout::getType()
+{
+    return Layout::LAYOUT_VERTICAL;
+}
+
+void VerticalLayout::update(const Container* container)
+{
+    // Need border, padding.
+    Theme::Border border = container->getBorder(container->getState());
+    Theme::Padding padding = container->getPadding();
+
+    float yPosition = 0;
+
+    std::vector<Control*> controls = container->getControls();
+
+    unsigned int i, end, iter;
+    if (_bottomToTop)
     {
     {
-        _bottomToTop = bottomToTop;
+        i = controls.size() - 1;
+        end = -1;
+        iter = -1;
     }
     }
-
-    Layout::Type VerticalLayout::getType()
+    else
     {
     {
-        return Layout::LAYOUT_VERTICAL;
+        i = 0;
+        end = controls.size();
+        iter = 1;
     }
     }
 
 
-    void VerticalLayout::update(const Container* container)
+    while (i != end)
     {
     {
-        // Need border, padding.
-        Theme::Border border = container->getBorder(container->getState());
-        Theme::Padding padding = container->getPadding();
+        Control* control = controls.at(i);
+            
+        align(control, container);
 
 
-        float yPosition = 0;
+        const Rectangle& bounds = control->getBounds();
+        const Theme::Margin& margin = control->getMargin();
 
 
-        std::vector<Control*> controls = container->getControls();
+        yPosition += margin.top;
 
 
-        unsigned int i, end, iter;
-        if (_bottomToTop)
-        {
-            i = controls.size() - 1;
-            end = -1;
-            iter = -1;
-        }
-        else
+        //if (control->isDirty() || control->isContainer())
         {
         {
-            i = 0;
-            end = controls.size();
-            iter = 1;
+            control->setPosition(0, yPosition);
+            control->update(container->getClip(), Vector2::zero());
         }
         }
 
 
-        while (i != end)
-        {
-            Control* control = controls.at(i);
-            
-            align(control, container);
-
-            const Rectangle& bounds = control->getBounds();
-            const Theme::Margin& margin = control->getMargin();
-
-            yPosition += margin.top;
+        yPosition += bounds.height + margin.bottom;
 
 
-            if (control->isDirty() || control->isContainer())
-            {
-                control->setPosition(0, yPosition);
-                control->update(container->getClip(), Vector2::zero());
-            }
-
-            yPosition += bounds.height + margin.bottom;
-
-            i += iter;
-        }
+        i += iter;
     }
     }
+}
+
 }
 }