Explorar o código

Working on the TextBox control and getting close to having 3D forms working.

Adam Blake %!s(int64=14) %!d(string=hai) anos
pai
achega
bfe6907dbf

+ 47 - 9
gameplay/src/Font.cpp

@@ -999,6 +999,18 @@ void Font::measureText(const char* text, const Rectangle& viewport, unsigned int
 
 unsigned int Font::getIndexAtLocation(const char* text, const Rectangle& area, unsigned int size, const Vector2& inLocation, Vector2* outLocation,
                                       Justify justify, bool wrap, bool rightToLeft)
+{
+    return getIndexOrLocation(text, area, size, inLocation, outLocation, -1, justify, wrap, rightToLeft);
+}
+
+void Font::getLocationAtIndex(const char* text, const Rectangle& clip, unsigned int size, Vector2* outLocation, const unsigned int destIndex,
+                              Justify justify, bool wrap, bool rightToLeft)
+{
+    getIndexOrLocation(text, clip, size, *outLocation, outLocation, destIndex, justify, wrap, rightToLeft);
+}
+
+unsigned int Font::getIndexOrLocation(const char* text, const Rectangle& area, unsigned int size, const Vector2& inLocation, Vector2* outLocation,
+                                      const int destIndex, Justify justify, bool wrap, bool rightToLeft)
 {
     unsigned int charIndex = 0;
 
@@ -1211,8 +1223,16 @@ unsigned int Font::getIndexAtLocation(const char* text, const Rectangle& area, u
     {
         // Handle delimiters until next token.
         unsigned int delimLength = 0;
-        int result = handleDelimiters(&token, size, iteration, area.x, &xPos, &yPos, &delimLength, &xPositionsIt, xPositions.end(), &inLocation);
-        charIndex += delimLength;
+        int result;
+        if (destIndex == -1)
+        {
+            result = handleDelimiters(&token, size, iteration, area.x, &xPos, &yPos, &delimLength, &xPositionsIt, xPositions.end(), &charIndex, &inLocation);
+        }
+        else
+        {
+            result = handleDelimiters(&token, size, iteration, area.x, &xPos, &yPos, &delimLength, &xPositionsIt, xPositions.end(), &charIndex, NULL, charIndex, destIndex);
+        }
+
         currentLineLength += delimLength;
         if (result == 0)
         {
@@ -1225,8 +1245,10 @@ unsigned int Font::getIndexAtLocation(const char* text, const Rectangle& area, u
             return charIndex;
         }
 
-        if (inLocation.x >= xPos && inLocation.x < xPos + (size>>3) &&
-            inLocation.y >= yPos && inLocation.y < yPos + size)
+        if (destIndex == charIndex ||
+            (destIndex == -1 &&
+             inLocation.x >= xPos && inLocation.x < xPos + (size>>3) &&
+             inLocation.y >= yPos && inLocation.y < yPos + size))
         {
             outLocation->x = xPos;
             outLocation->y = yPos;
@@ -1296,8 +1318,10 @@ unsigned int Font::getIndexAtLocation(const char* text, const Rectangle& area, u
                 }
 
                 // Check against inLocation.
-                if (inLocation.x >= xPos && inLocation.x < xPos + g.width*scale + (size>>3) &&
-                    inLocation.y >= yPos && inLocation.y < yPos + size)
+                if (destIndex == charIndex ||
+                    (destIndex == -1 &&
+                    inLocation.x >= xPos && inLocation.x < xPos + g.width*scale + (size>>3) &&
+                    inLocation.y >= yPos && inLocation.y < yPos + size))
                 {
                     outLocation->x = xPos;
                     outLocation->y = yPos;
@@ -1431,7 +1455,8 @@ unsigned int Font::getReversedTokenLength(const char* token, const char* bufStar
 }
 
 int Font::handleDelimiters(const char** token, const unsigned int size, const int iteration, const int areaX, int* xPos, int* yPos, unsigned int* lineLength,
-                      std::vector<int>::const_iterator* xPositionsIt, std::vector<int>::const_iterator xPositionsEnd, const Vector2* stopAtPosition)
+                          std::vector<int>::const_iterator* xPositionsIt, std::vector<int>::const_iterator xPositionsEnd, unsigned int* charIndex,
+                          const Vector2* stopAtPosition, const int currentIndex, const int destIndex)
 {
     char delimiter = *token[0];
     bool nextLine = true;
@@ -1441,9 +1466,10 @@ int Font::handleDelimiters(const char** token, const unsigned int size, const in
             delimiter == '\n' ||
             delimiter == 0)
     {
-        if (stopAtPosition &&
+        if ((stopAtPosition &&
             stopAtPosition->x >= *xPos && stopAtPosition->x < *xPos + (size>>1) &&
-            stopAtPosition->y >= *yPos && stopAtPosition->y < *yPos + size)
+            stopAtPosition->y >= *yPos && stopAtPosition->y < *yPos + size) ||
+            (currentIndex >= 0 && destIndex >= 0 && currentIndex + *lineLength == destIndex))
         {
             // Success + stopAtPosition was reached.
             return 2;
@@ -1454,6 +1480,10 @@ int Font::handleDelimiters(const char** token, const unsigned int size, const in
             case ' ':
                 *xPos += size>>1;
                 (*lineLength)++;
+                if (charIndex)
+                {
+                    (*charIndex)++;
+                }
                 break;
             case '\r':
             case '\n':
@@ -1473,11 +1503,19 @@ int Font::handleDelimiters(const char** token, const unsigned int size, const in
                     }
                     nextLine = false;
                     *lineLength = 0;
+                    if (charIndex)
+                    {
+                        (*charIndex)++;
+                    }
                 }
                 break;
             case '\t':
                 *xPos += (size>>1)*4;
                 (*lineLength)++;
+                if (charIndex)
+                {
+                    (*charIndex)++;
+                }
                 break;
             case 0:
                 // EOF reached.

+ 11 - 1
gameplay/src/Font.h

@@ -12,6 +12,7 @@ namespace gameplay
 class Font : public Ref
 {
     friend class Package;
+    friend class TextBox;
 
 public:
 
@@ -179,6 +180,10 @@ public:
     unsigned int getIndexAtLocation(const char* text, const Rectangle& clip, unsigned int size, const Vector2& inLocation, Vector2* outLocation,
                                     Justify justify = ALIGN_TOP_LEFT, bool wrap = true, bool rightToLeft = false);
 
+    // Get the location of the character at the given index.
+    void getLocationAtIndex(const char* text, const Rectangle& clip, unsigned int size, Vector2* outLocation, const unsigned int destIndex,
+                            Justify justify = ALIGN_TOP_LEFT, bool wrap = true, bool rightToLeft = false);
+
     SpriteBatch* getSpriteBatch();
 
     static Justify getJustifyFromString(const char* justify);
@@ -201,13 +206,18 @@ private:
      */
     ~Font();
 
+    // Used by both getIndexAtLocation and getLocationAtIndex.
+    unsigned int getIndexOrLocation(const char* text, const Rectangle& clip, unsigned int size, const Vector2& inLocation, Vector2* outLocation,
+                                    const int destIndex = -1, Justify justify = ALIGN_TOP_LEFT, bool wrap = true, bool rightToLeft = false);
+
     // Utilities
     unsigned int getTokenWidth(const char* token, unsigned int length, unsigned int size, float scale);
     unsigned int getReversedTokenLength(const char* token, const char* bufStart);
 
     // Returns 0 if EOF was reached, 1 if delimiters were handles correctly, and 2 if the stopAtPosition was reached while handling delimiters.
     int handleDelimiters(const char** token, const unsigned int size, const int iteration, const int areaX, int* xPos, int* yPos, unsigned int* lineLength,
-                          std::vector<int>::const_iterator* xPositionsIt, std::vector<int>::const_iterator xPositionsEnd, const Vector2* stopAtPosition = NULL);
+                          std::vector<int>::const_iterator* xPositionsIt, std::vector<int>::const_iterator xPositionsEnd, unsigned int* charIndex = NULL,
+                          const Vector2* stopAtPosition = NULL, const int currentIndex = -1, const int destIndex = -1);
     void addLineInfo(const Rectangle& area, int lineWidth, int lineLength, Justify hAlign,
                      std::vector<int>* xPositions, std::vector<unsigned int>* lineLengths, bool rightToLeft);
 

+ 70 - 14
gameplay/src/Form.cpp

@@ -7,6 +7,7 @@
 #include "Label.h"
 #include "Button.h"
 #include "CheckBox.h"
+#include "Scene.h"
 
 namespace gameplay
 {
@@ -150,17 +151,18 @@ namespace gameplay
 
     void Form::setNode(Node* node)
     {
+        // Set this Form up to be 3D by initializing a quad, projection matrix and viewport.
+        setQuad(0.0f, 0.0f, _size.x, _size.y);
+        Matrix::createOrthographicOffCenter(0, _size.x, _size.y, 0, 0, 1, &_projectionMatrix);
+        _theme->setProjectionMatrix(_projectionMatrix);
+        _viewport = new Viewport(0, 0, _size.x, _size.y);
+
         // Connect the new node.
         _node = node;
         if (_node)
         {
             _node->setModel(_quad);
         }
-
-        // Set this Form up to be 3D by initializing a quad, projection matrix and viewport.
-        setQuad(0.0f, 0.0f, _size.x, _size.y);
-        Matrix::createOrthographicOffCenter(0, _size.x, _size.y, 0, 0, 1, &_projectionMatrix);
-        _viewport = new Viewport(0, 0, _size.x, _size.y);
     }
 
     void Form::update()
@@ -186,7 +188,6 @@ namespace gameplay
         {
             if (isDirty())
             {
-                _theme->getSpriteBatch()->setProjectionMatrix(_projectionMatrix);
                 _frameBuffer->bind();
                 _viewport->bind();
 
@@ -210,7 +211,6 @@ namespace gameplay
         }
     }
 
-    //void Form::draw(Theme* theme, const Vector2& position)
     void Form::draw(SpriteBatch* spriteBatch, const Vector2& position)
     {
         std::vector<Control*>::const_iterator it;
@@ -227,7 +227,7 @@ namespace gameplay
         {
             Control* control = *it;
 
-            //if ((*it)->isDirty())
+            //if (!_node || (*it)->isDirty())
             {
                 control->drawBorder(spriteBatch, position);
 
@@ -242,7 +242,7 @@ namespace gameplay
         {
             Control* control = *it;
 
-            //if ((*it)->isDirty())
+            //if (!_node || (*it)->isDirty())
             {
                 control->drawText(position);
             }
@@ -263,7 +263,10 @@ namespace gameplay
         Material* material = _quad->setMaterial("res/shaders/textured.vsh", "res/shaders/textured.fsh");
 
         // Set the common render state block for the material
-        material->setStateBlock(_theme->getSpriteBatch()->getStateBlock());
+        RenderState::StateBlock* stateBlock = _theme->getSpriteBatch()->getStateBlock();
+        stateBlock->setDepthWrite(true);
+        //material->setStateBlock(_theme->getSpriteBatch()->getStateBlock());
+        material->setStateBlock(stateBlock);
 
         // Bind the WorldViewProjection matrix
         material->setParameterAutoBinding("u_worldViewProjectionMatrix", RenderState::WORLD_VIEW_PROJECTION_MATRIX);
@@ -295,13 +298,66 @@ namespace gameplay
         {
             Form* form = *it;
 
-            if (form->_node)
+            Node* node = form->_node;
+            if (node)
             {
-                // Project point into world space.
+                // Work in progress: Picking within 3D forms.
 
-                // Check for collision with form.
+                /*
+                Scene* scene = node->getScene();
+                Camera* camera = scene->getActiveCamera();
 
-                // Unproject point into form's space.
+                if (camera)
+                {
+                    // Get info about the form's position.
+                    Matrix m = node->getMatrix();
+                    Vector2 size = form->getSize();
+                    Vector3 min(0, 0, 0);
+                    Vector3 max(size.x, size.y, 0);
+                    m.transformPoint(&min);
+                    m.transformPoint(&max);
+
+                    // Unproject point into world space.
+                    Ray ray;
+                    camera->pickRay(NULL, 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 to the plane defined
+                    // by the quad's upVector and one of its points
+                    // from the plane defined by the same vector
+                    // and the origin.
+                    float a = normal.x; float b = normal.y; float c = normal.z;
+                    float d = -(a*min.x) - (b*min.y) - (c*min.z);
+                    float distance = abs(d) /  sqrt(a*a + b*b + c*c);
+                    Plane plane(normal, distance);
+
+                    // Check for collision with plane.
+                    float collides = ray.intersects(plane);
+                    if (collides != Ray::INTERSECTS_NONE)
+                    {
+                        // Check for collision with form.
+                        // Multiply the ray's direction vector by collision distance
+                        // and add that to the ray's origin.
+                        Vector3 rayOrigin = ray.getOrigin();
+                        Vector3 rayDirection = ray.getDirection();
+
+                        float alpha = (distance - normal.dot(rayOrigin)) / normal.dot(rayDirection);
+                        Vector3 point = rayOrigin + alpha*rayDirection;
+
+                        // If the resulting point lies within the quad,
+                        // project it into the form's space.
+
+
+                        // Projection from point (C) on plane with normal n containing point P.
+                        Vector3 cp(point, min);
+
+                    }
+                }
+                */
             }
             else
             {

+ 8 - 10
gameplay/src/PlatformWin32.cpp

@@ -57,20 +57,18 @@ static gameplay::Keyboard::Key getKey(WPARAM win32KeyCode, bool shiftDown)
         return gameplay::Keyboard::KEY_ALT;
     case VK_APPS:
         return gameplay::Keyboard::KEY_MENU;
-    case VK_SHIFT:
-        return gameplay::Keyboard::KEY_SHIFT;
     case VK_LSHIFT:
-        return gameplay::Keyboard::KEY_LEFT_SHIFT;
+        return gameplay::Keyboard::KEY_SHIFT;
     case VK_RSHIFT:
-        return gameplay::Keyboard::KEY_RIGHT_SHIFT;
+        return gameplay::Keyboard::KEY_SHIFT;
     case VK_LCONTROL:
-        return gameplay::Keyboard::KEY_LEFT_CTRL;
+        return gameplay::Keyboard::KEY_CTRL;
     case VK_RCONTROL:
-        return gameplay::Keyboard::KEY_RIGHT_CTRL;
+        return gameplay::Keyboard::KEY_CTRL;
     case VK_LMENU:
-        return gameplay::Keyboard::KEY_LEFT_ALT;
+        return gameplay::Keyboard::KEY_ALT;
     case VK_RMENU:
-        return gameplay::Keyboard::KEY_RIGHT_ALT;
+        return gameplay::Keyboard::KEY_ALT;
     case VK_LWIN:
     case VK_RWIN:
         return gameplay::Keyboard::KEY_HYPER;
@@ -388,13 +386,13 @@ LRESULT CALLBACK __WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
     case WM_CHAR:
         // Suppress key repeats
         if ((lParam & 0x40000000) == 0)
-            gameplay::Game::getInstance()->keyEvent(gameplay::Keyboard::KEY_CHAR, wParam);
+            gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, wParam);
         break;
 
     case WM_UNICHAR:
         // Suppress key repeats
         if ((lParam & 0x40000000) == 0)
-            gameplay::Game::getInstance()->keyEvent(gameplay::Keyboard::KEY_CHAR, wParam);
+            gameplay::Platform::keyEventInternal(gameplay::Keyboard::KEY_CHAR, wParam);
         break;
 
     case WM_SETFOCUS:

+ 123 - 54
gameplay/src/TextBox.cpp

@@ -45,7 +45,7 @@ TextBox* TextBox::getTextBox(const char* id)
     return NULL;
 }
 
-void TextBox::setTouchLocation(int x, int y)
+void TextBox::setCursorLocation(int x, int y)
 {
     Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
     Theme::ContainerRegion* containerRegion = overlay->getContainerRegion();
@@ -56,7 +56,7 @@ void TextBox::setTouchLocation(int x, int y)
     }
     Theme::Padding padding = _style->getPadding();
 
-    _touchLocation.set(x - border.left - padding.left + _viewport.x,
+    _cursorLocation.set(x - border.left - padding.left + _viewport.x,
                        y - border.top - padding.top + _viewport.y);
 }
 
@@ -77,7 +77,7 @@ void TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int conta
                 x > 0 && x <= _size.x &&
                 y > 0 && y <= _size.y)
             {
-                setTouchLocation(x, y);
+                setCursorLocation(x, y);
                 _dirty = true;
             }
             break;
@@ -85,7 +85,7 @@ void TextBox::touchEvent(Touch::TouchEvent evt, int x, int y, unsigned int conta
             if (x > 0 && x <= _size.x &&
                 y > 0 && y <= _size.y)
             {
-                setTouchLocation(x, y);
+                setCursorLocation(x, y);
                 _state = STATE_FOCUS;
                 _dirty = true;
             }
@@ -104,62 +104,131 @@ void TextBox::keyEvent(Keyboard::KeyEvent evt, int key)
     {
         switch (evt)
         {
-        case Keyboard::KEY_PRESS:
-            break;
-        case Keyboard::KEY_RELEASE:
-            Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
-            Font* font = overlay->getFont();
-
-            // _text.insert / replace / remove depending on key.
-            switch (key)
+            case Keyboard::KEY_PRESS:
             {
-            case Keyboard::KEY_BACKSPACE:
-                break;
-            case Keyboard::KEY_DELETE:
-                break;
-            //case Keyboard::KEY_TAB:
-                // May be handled by default?
-                // May want to insert 4 spaces instead of \t.
-                // If this were the web we'd want to switch focus to the next Control...
-                //break;
-            case Keyboard::KEY_HOME:
-                // Move cursor to beginning of line.
-                break;
-            case Keyboard::KEY_END:
-                // Move cursor to end of line.
-                break;
-            case Keyboard::KEY_PG_DOWN:
-                break;
-            case Keyboard::KEY_PG_UP:
+                switch (key)
+                {
+                    case Keyboard::KEY_HOME:
+                    {
+                        // TODO: Move cursor to beginning of line.
+                        // This only works for left alignment...
+                        
+                        //_cursorLocation.x = _viewport.x;
+                        //_dirty = true;
+                        break;
+                    }
+                    case Keyboard::KEY_END:
+                    {
+                        // TODO: Move cursor to end of line.
+                        break;
+                    }
+                    case Keyboard::KEY_DELETE:
+                    {
+                        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
+                        Font* font = overlay->getFont();
+                        unsigned int fontSize = overlay->getFontSize();
+                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _viewport, fontSize, _cursorLocation, &_cursorLocation,
+                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+
+                        _text.erase(textIndex, 1);
+                        font->getLocationAtIndex(_text.c_str(), _viewport, fontSize, &_cursorLocation, textIndex,
+                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                        _dirty = true;
+                        break;
+                    }
+                    case Keyboard::KEY_LEFT_ARROW:
+                    {
+                        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
+                        Font* font = overlay->getFont();
+                        unsigned int fontSize = overlay->getFontSize();
+                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _viewport, fontSize, _cursorLocation, &_cursorLocation,
+                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+
+                        font->getLocationAtIndex(_text.c_str(), _viewport, fontSize, &_cursorLocation, textIndex - 1,
+                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                        _dirty = true;
+                        break;
+                    }
+                    case Keyboard::KEY_RIGHT_ARROW:
+                    {
+                        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
+                        Font* font = overlay->getFont();
+                        unsigned int fontSize = overlay->getFontSize();
+                        unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _viewport, fontSize, _cursorLocation, &_cursorLocation,
+                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+
+                        font->getLocationAtIndex(_text.c_str(), _viewport, fontSize, &_cursorLocation, textIndex + 1,
+                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                        _dirty = true;
+                        break;
+                    }
+                    case Keyboard::KEY_UP_ARROW:
+                    {
+                        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
+                        Font* font = overlay->getFont();
+                        unsigned int fontSize = overlay->getFontSize();
+
+                        _cursorLocation.y -= fontSize;
+                        font->getIndexAtLocation(_text.c_str(), _viewport, fontSize, _cursorLocation, &_cursorLocation,
+                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                        _dirty = true;
+                        break;
+                    }
+                    case Keyboard::KEY_DOWN_ARROW:
+                    {
+                        Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
+                        Font* font = overlay->getFont();
+                        unsigned int fontSize = overlay->getFontSize();
+
+                        _cursorLocation.y += fontSize;
+                        font->getIndexAtLocation(_text.c_str(), _viewport, fontSize, _cursorLocation, &_cursorLocation,
+                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                        _dirty = true;
+                        break;
+                    }
+                }
                 break;
-            default:
-                // Insert character into string.
-                _textIndex = font->getIndexAtLocation(_text.c_str(), _viewport, overlay->getFontSize(), _touchLocation, &_touchLocation,
+            }
+
+            case Keyboard::KEY_CHAR:
+            {
+                Theme::Style::Overlay* overlay = _style->getOverlay(getOverlayType());
+                Font* font = overlay->getFont();
+                unsigned int fontSize = overlay->getFontSize();
+                unsigned int textIndex = font->getIndexAtLocation(_text.c_str(), _viewport, fontSize, _cursorLocation, &_cursorLocation,
                     overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
 
-                _text.insert(_textIndex, 1, (char)key);
-                
-                // Move cursor forward.
-                unsigned int w, h;
-                font->measureText((char*)&key, overlay->getFontSize(), &w, &h);
-                ++_textIndex;
-                _touchLocation.x += w;
-                //_cursorLocation.x += w;
-                
-                // Wrap cursor if necessary.
-                if (_touchLocation.x >= _viewport.x + _viewport.width)
+                switch (key)
                 {
-                    //_cursorLocation.x = w;
-                    _touchLocation.x = w;
-                    //_cursorLocation.y += h;
-                    _touchLocation.x += h;
-                }
+                    case Keyboard::KEY_BACKSPACE:
+                    {
+                        if (textIndex > 0)
+                        {
+                            --textIndex;
+                            _text.erase(textIndex, 1);
+                            font->getLocationAtIndex(_text.c_str(), _viewport, fontSize, &_cursorLocation, textIndex,
+                                overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
 
-                _dirty = true;
+                            _dirty = true;
+                        }
+                        break;
+                    }
+                    default:
+                    {
+                        // Insert character into string.
+                        _text.insert(textIndex, 1, (char)key);
 
-                break;
+                        // Get new location of cursor.
+                        font->getLocationAtIndex(_text.c_str(), _viewport, fontSize, &_cursorLocation, textIndex + 1,
+                            overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
+                
+                        _dirty = true;
+                        break;
+                    }
+            
+                    break;
+                }
             }
-            break;
         }
     }
 }
@@ -186,7 +255,7 @@ void TextBox::update(const Vector2& position)
     // Get index into string and cursor location from the last recorded touch location.
     if (_state == STATE_FOCUS)
     {
-        _textIndex = font->getIndexAtLocation(_text.c_str(), _viewport, overlay->getFontSize(), _touchLocation, &_touchLocation,
+        font->getIndexAtLocation(_text.c_str(), _viewport, overlay->getFontSize(), _cursorLocation, &_cursorLocation,
             overlay->getTextAlignment(), true, overlay->getTextRightToLeft());
     }
 
@@ -214,7 +283,7 @@ void TextBox::drawSprites(SpriteBatch* spriteBatch, const Vector2& position)
             const Theme::UVs uvs = cursor->getUVs();
             unsigned int fontSize = overlay->getFontSize();
 
-            spriteBatch->draw(_touchLocation.x - (size.x / 2.0f), _touchLocation.y, size.x, fontSize, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color);
+            spriteBatch->draw(_cursorLocation.x - (size.x / 2.0f), _cursorLocation.y, size.x, fontSize, uvs.u1, uvs.v1, uvs.u2, uvs.v2, color);
         }
     }
 }

+ 2 - 3
gameplay/src/TextBox.h

@@ -29,11 +29,10 @@ private:
     TextBox(const TextBox& copy);
     ~TextBox();
 
-    void setTouchLocation(int x, int y);
+    void setCursorLocation(int x, int y);
 
-    Vector2 _touchLocation;
     Vector2 _cursorLocation;
-    unsigned int _textIndex;
+    unsigned int textIndex;
 };
 
 }

+ 16 - 2
gameplay/src/Theme.cpp

@@ -274,6 +274,8 @@ namespace gameplay
                         normal->setTextAlignment(alignment);
                         normal->setTextRightToLeft(rightToLeft);
 
+                        theme->_fonts.insert(font);
+
                         if (font) font->release();
 
                         // Done with this pass.
@@ -413,7 +415,7 @@ namespace gameplay
                             focus->setTextAlignment(alignment);
                             focus->setTextRightToLeft(rightToLeft);
 
-                            //if (font && font == normal->getFont()) font->release();
+                            theme->_fonts.insert(font);
                         }
                         else if (strcmp(innerSpacename, "active") == 0)
                         {
@@ -430,7 +432,7 @@ namespace gameplay
                             active->setTextAlignment(alignment);
                             active->setTextRightToLeft(rightToLeft);
 
-                            //if (font && font == normal->getFont()) font->release();
+                            theme->_fonts.insert(font);
                         }
                     }
 
@@ -477,6 +479,18 @@ namespace gameplay
         return NULL;
     }
 
+    void Theme::setProjectionMatrix(const Matrix& matrix)
+    {
+        _spriteBatch->setProjectionMatrix(matrix);
+
+        // Set the matrix on each Font used by the style.
+        std::set<Font*>::const_iterator it;
+        for (it = _fonts.begin(); it != _fonts.end(); ++it)
+        {
+            (*it)->getSpriteBatch()->setProjectionMatrix(matrix);
+        }
+    }
+
     SpriteBatch* Theme::getSpriteBatch() const
     {
         return _spriteBatch;

+ 3 - 0
gameplay/src/Theme.h

@@ -195,6 +195,8 @@ public:
      */
     Theme::Style* getStyle(const char* id) const;
 
+    void setProjectionMatrix(const Matrix& matrix);
+
     SpriteBatch* getSpriteBatch() const;
     
     /**
@@ -363,6 +365,7 @@ private:
     std::vector<Icon*> _icons;
     std::vector<SliderIcon*> _sliders;
     std::vector<ContainerRegion*> _containers;
+    std::set<Font*> _fonts;
 };
 
 }