Просмотр исходного кода

Merge pull request #1428 from sgrenier/next

Fixed issue with multi-touch on virtual gamepad and UI
Steve Grenier 12 лет назад
Родитель
Сommit
2e75971356
6 измененных файлов с 213 добавлено и 157 удалено
  1. 8 7
      gameplay/src/Container.cpp
  2. 14 23
      gameplay/src/Control.cpp
  3. 5 5
      gameplay/src/Control.h
  4. 165 109
      gameplay/src/Form.cpp
  5. 16 13
      gameplay/src/Form.h
  6. 5 0
      gameplay/src/Touch.h

+ 8 - 7
gameplay/src/Container.cpp

@@ -463,7 +463,7 @@ void Container::setScrollWheelRequiresFocus(bool required)
 bool Container::setFocus()
 bool Container::setFocus()
 {
 {
     // If this container (or one of its children) already has focus, do nothing
     // If this container (or one of its children) already has focus, do nothing
-    if (Form::_focusControl && (Form::_focusControl == this || Form::_focusControl->isChild(this)))
+    if (Form::getFocusControl() && (Form::getFocusControl() == this || Form::getFocusControl()->isChild(this)))
         return true;
         return true;
 
 
     // First try to set focus to our active control
     // First try to set focus to our active control
@@ -496,7 +496,7 @@ void Container::setActiveControl(Control* control)
         _activeControl = control;
         _activeControl = control;
 
 
         // If a control within this container currently has focus, switch focus to the new active control
         // If a control within this container currently has focus, switch focus to the new active control
-        if (Form::_focusControl && Form::_focusControl != control && Form::_focusControl->isChild(this))
+        if (Form::getFocusControl() && Form::getFocusControl() != control && Form::getFocusControl()->isChild(this))
             Form::setFocusControl(control);
             Form::setFocusControl(control);
     }
     }
 }
 }
@@ -788,20 +788,21 @@ bool Container::moveFocus(Direction direction)
 bool Container::moveFocusNextPrevious(Direction direction)
 bool Container::moveFocusNextPrevious(Direction direction)
 {
 {
     // Get the current control that has focus (either directly or indirectly) within this container
     // Get the current control that has focus (either directly or indirectly) within this container
+    Control* currentFocus = Form::getFocusControl();
     Control* current = NULL;
     Control* current = NULL;
-    if (Form::_focusControl && Form::_focusControl->isChild(this))
+    if (currentFocus && currentFocus->isChild(this))
     {
     {
-        if (Form::_focusControl->_parent == this)
+        if (currentFocus->_parent == this)
         {
         {
             // Currently focused control is a direct child of us
             // Currently focused control is a direct child of us
-            current = Form::_focusControl;
+            current = currentFocus;
         }
         }
         else
         else
         {
         {
             // Currently focused control is a child of one of our child containers
             // Currently focused control is a child of one of our child containers
             for (size_t i = 0, count = _controls.size(); i < count; ++i)
             for (size_t i = 0, count = _controls.size(); i < count; ++i)
             {
             {
-                if (Form::_focusControl->isChild(_controls[i]))
+                if (currentFocus->isChild(_controls[i]))
                 {
                 {
                     current = _controls[i];
                     current = _controls[i];
                     break;
                     break;
@@ -891,7 +892,7 @@ bool Container::moveFocusNextPrevious(Direction direction)
 
 
 bool Container::moveFocusDirectional(Direction direction)
 bool Container::moveFocusDirectional(Direction direction)
 {
 {
-	Control* startControl = Form::_focusControl;
+	Control* startControl = Form::getFocusControl();
 	if (startControl == NULL)
 	if (startControl == NULL)
 		return false;
 		return false;
 
 

+ 14 - 23
gameplay/src/Control.cpp

@@ -46,9 +46,9 @@ static bool parseCoordPair(const char* s, float* v1, float* v2, bool* v1Percenta
 }
 }
 
 
 Control::Control()
 Control::Control()
-    : _id(""), _enabled(true), _boundsBits(0), _dirtyBits(DIRTY_BOUNDS | DIRTY_STATE), _consumeInputEvents(true), _alignment(ALIGN_TOP_LEFT),
+    : _id(""), _boundsBits(0), _dirtyBits(DIRTY_BOUNDS | DIRTY_STATE), _consumeInputEvents(true), _alignment(ALIGN_TOP_LEFT),
     _autoSize(AUTO_SIZE_BOTH), _style(NULL), _listeners(NULL), _visible(true), _zIndex(-1),
     _autoSize(AUTO_SIZE_BOTH), _style(NULL), _listeners(NULL), _visible(true), _zIndex(-1),
-    _contactIndex(INVALID_CONTACT_INDEX), _focusIndex(-1), _canFocus(false), _parent(NULL), _styleOverridden(false), _skin(NULL)
+    _contactIndex(INVALID_CONTACT_INDEX), _focusIndex(-1), _canFocus(false), _state(NORMAL), _parent(NULL), _styleOverridden(false), _skin(NULL)
 {
 {
     addScriptEvent("controlEvent", "<Control>[Control::Listener::EventType]");
     addScriptEvent("controlEvent", "<Control>[Control::Listener::EventType]");
 }
 }
@@ -535,12 +535,12 @@ void Control::setCanFocus(bool acceptsFocus)
 
 
 bool Control::hasFocus() const
 bool Control::hasFocus() const
 {
 {
-    return (Form::_focusControl == this);
+    return (Form::getFocusControl() == this);
 }
 }
 
 
 bool Control::setFocus()
 bool Control::setFocus()
 {
 {
-    if (Form::_focusControl != this && canFocus())
+    if (Form::getFocusControl() != this && canFocus())
     {
     {
         Form::setFocusControl(this);
         Form::setFocusControl(this);
         return true;
         return true;
@@ -571,25 +571,25 @@ float Control::getOpacity(State state) const
 
 
 void Control::setEnabled(bool enabled)
 void Control::setEnabled(bool enabled)
 {
 {
-    if (_enabled != enabled)
+    if (enabled != isEnabled())
     {
     {
-        _enabled = enabled;
-
-        if (!_enabled)
+        if (!enabled)
             Form::controlDisabled(this);
             Form::controlDisabled(this);
 
 
+        _state = enabled ? NORMAL : DISABLED;
+
         setDirty(DIRTY_STATE);
         setDirty(DIRTY_STATE);
     }
     }
 }
 }
 
 
 bool Control::isEnabled() const
 bool Control::isEnabled() const
 {
 {
-    return _enabled;
+    return (_state != DISABLED);
 }
 }
 
 
 bool Control::isEnabledInHierarchy() const
 bool Control::isEnabledInHierarchy() const
 {
 {
-    if (!_enabled)
+    if (!isEnabled())
         return false;
         return false;
 
 
     if (_parent)
     if (_parent)
@@ -909,22 +909,13 @@ Theme* Control::getTheme() const
 
 
 Control::State Control::getState() const
 Control::State Control::getState() const
 {
 {
-    if (!_enabled)
-        return DISABLED;
-
-    if (Form::_activeControl == this)
+    if (_state == HOVER)
     {
     {
-        if (Form::_activeControlState == ACTIVE)
-            return ACTIVE;
-        if (Form::_focusControl == this)
-            return FOCUS;
-        return Form::_activeControlState;
+        // Focus state takes priority over hover
+        return (Form::getFocusControl() == this ? FOCUS : HOVER);
     }
     }
 
 
-    if (Form::_focusControl == this)
-        return FOCUS;
-
-    return NORMAL;
+    return _state;
 }
 }
 
 
 Theme::Style::OverlayType Control::getOverlayType() const
 Theme::Style::OverlayType Control::getOverlayType() const

+ 5 - 5
gameplay/src/Control.h

@@ -1291,11 +1291,6 @@ protected:
      */ 
      */ 
     std::string _id;
     std::string _id;
 
 
-    /**
-     * Whether the control is enabled.
-     */
-    bool _enabled;
-
     /**
     /**
      * Bits indicating whether bounds values are absolute values or percentages.
      * Bits indicating whether bounds values are absolute values or percentages.
      */
      */
@@ -1396,6 +1391,11 @@ protected:
      */
      */
     bool _canFocus;
     bool _canFocus;
 
 
+    /**
+     * This control's current state.
+     */
+    State _state;
+
     /**
     /**
      * The control's parent container.
      * The control's parent container.
      */
      */

+ 165 - 109
gameplay/src/Form.cpp

@@ -25,10 +25,22 @@ namespace gameplay
 {
 {
 
 
 static std::vector<Form*> __forms;
 static std::vector<Form*> __forms;
-Control* Form::_focusControl = NULL;
-Control* Form::_activeControl = NULL;
-Control::State Form::_activeControlState = Control::NORMAL;
-static bool _shiftKeyDown = false;
+static Control* __focusControl = NULL;
+static Control* __activeControl[Touch::MAX_TOUCH_POINTS];
+static bool __shiftKeyDown = false;
+
+/**
+ * Static initializer for forms.
+ * @script{ignore}
+ */
+struct FormInit
+{
+    FormInit()
+    {
+        memset(__activeControl, 0, sizeof(__activeControl));
+    }
+};
+static FormInit __init;
 
 
 Form::Form() : _node(NULL), _batched(true)
 Form::Form() : _node(NULL), _batched(true)
 {
 {
@@ -140,14 +152,17 @@ Form* Form::getForm(const char* id)
     return NULL;
     return NULL;
 }
 }
 
 
-Control* Form::getActiveControl()
+Control* Form::getActiveControl(unsigned int touchPoint)
 {
 {
-    return _activeControl;
+    if (touchPoint >= Touch::MAX_TOUCH_POINTS)
+        return NULL;
+
+    return __activeControl[touchPoint];
 }
 }
 
 
 Control* Form::getFocusControl()
 Control* Form::getFocusControl()
 {
 {
-    return _focusControl;
+    return __focusControl;
 }
 }
 
 
 void Form::clearFocus()
 void Form::clearFocus()
@@ -323,7 +338,7 @@ bool Form::screenToForm(Control* ctrl, int* x, int* y)
     return false;
     return false;
 }
 }
 
 
-Control* Form::findInputControl(int* x, int* y, bool focus)
+Control* Form::findInputControl(int* x, int* y, bool focus, unsigned int contactIndex)
 {
 {
     for (int i = (int)__forms.size() - 1; i >= 0; --i)
     for (int i = (int)__forms.size() - 1; i >= 0; --i)
     {
     {
@@ -338,7 +353,7 @@ Control* Form::findInputControl(int* x, int* y, bool focus)
             continue;
             continue;
 
 
         // Search for an input control within this form
         // Search for an input control within this form
-        Control* ctrl = findInputControl(form, formX, formY, focus);
+        Control* ctrl = findInputControl(form, formX, formY, focus, contactIndex);
         if (ctrl)
         if (ctrl)
         {
         {
             *x = formX;
             *x = formX;
@@ -355,9 +370,9 @@ Control* Form::findInputControl(int* x, int* y, bool focus)
     return NULL;
     return NULL;
 }
 }
 
 
-Control* Form::findInputControl(Control* control, int x, int y, bool focus)
+Control* Form::findInputControl(Control* control, int x, int y, bool focus, unsigned int contactIndex)
 {
 {
-    if (!(control->_visible && control->_enabled))
+    if (!(control->_visible && control->isEnabled()))
         return NULL;
         return NULL;
 
 
     Control* result = NULL;
     Control* result = NULL;
@@ -377,7 +392,7 @@ Control* Form::findInputControl(Control* control, int x, int y, bool focus)
         Container* container = static_cast<Container*>(control);
         Container* container = static_cast<Container*>(control);
         for (unsigned int i = 0, childCount = container->getControlCount(); i < childCount; ++i)
         for (unsigned int i = 0, childCount = container->getControlCount(); i < childCount; ++i)
         {
         {
-            Control* ctrl = findInputControl(container->getControl(i), x, y, focus);
+            Control* ctrl = findInputControl(container->getControl(i), x, y, focus, contactIndex);
             if (ctrl)
             if (ctrl)
                 result = ctrl;
                 result = ctrl;
         }
         }
@@ -386,8 +401,11 @@ Control* Form::findInputControl(Control* control, int x, int y, bool focus)
     return result;
     return result;
 }
 }
 
 
-Control* Form::handlePointerPressRelease(int* x, int* y, bool pressed)
+Control* Form::handlePointerPressRelease(int* x, int* y, bool pressed, unsigned int contactIndex)
 {
 {
+    if (contactIndex >= Touch::MAX_TOUCH_POINTS)
+        return NULL;
+
     Control* ctrl = NULL;
     Control* ctrl = NULL;
 
 
     int newX = *x;
     int newX = *x;
@@ -396,16 +414,19 @@ Control* Form::handlePointerPressRelease(int* x, int* y, bool pressed)
     if (pressed)
     if (pressed)
     {
     {
         // Update active state changes
         // Update active state changes
-        if ((ctrl = findInputControl(&newX, &newY, false)) != NULL)
+        if ((ctrl = findInputControl(&newX, &newY, false, contactIndex)) != NULL)
         {
         {
-            if (_activeControl != ctrl || _activeControlState != Control::ACTIVE)
+            if (__activeControl[contactIndex] != ctrl || ctrl->_state != ACTIVE)
             {
             {
-                if (_activeControl)
-                    _activeControl->setDirty(Control::DIRTY_STATE);
+                if (__activeControl[contactIndex])
+                {
+                    __activeControl[contactIndex]->_state = NORMAL;
+                    __activeControl[contactIndex]->setDirty(DIRTY_STATE);
+                }
 
 
-                _activeControl = ctrl;
-                _activeControlState = Control::ACTIVE;
-                _activeControl->setDirty(Control::DIRTY_STATE);
+                __activeControl[contactIndex] = ctrl;
+                ctrl->_state = ACTIVE;
+                ctrl->setDirty(DIRTY_STATE);
             }
             }
 
 
             ctrl->notifyListeners(Control::Listener::PRESS);
             ctrl->notifyListeners(Control::Listener::PRESS);
@@ -413,49 +434,53 @@ Control* Form::handlePointerPressRelease(int* x, int* y, bool pressed)
     }
     }
     else // !pressed
     else // !pressed
     {
     {
-        Control* active = _activeControlState == Control::ACTIVE ? _activeControl : NULL;
+        Control* active = (__activeControl[contactIndex] && __activeControl[contactIndex]->_state == ACTIVE) ? __activeControl[contactIndex] : NULL;
 
 
         if (active)
         if (active)
         {
         {
             active->addRef(); // protect against event-hanlder evil
             active->addRef(); // protect against event-hanlder evil
 
 
-            // Release happened for the active control (that was pressed)
+            // Release happened for an active control (that was pressed)
             ctrl = active;
             ctrl = active;
 
 
             // Transform point to form-space
             // Transform point to form-space
             screenToForm(ctrl, &newX, &newY);
             screenToForm(ctrl, &newX, &newY);
 
 
             // No longer any active control
             // No longer any active control
-            _activeControl->setDirty(Control::DIRTY_STATE);
-            _activeControl = NULL;
-            _activeControlState = Control::NORMAL;
+            active->setDirty(DIRTY_STATE);
+            active->_state = NORMAL;
+            __activeControl[contactIndex] = NULL;
         }
         }
         else
         else
         {
         {
             // Update active and hover control state on release
             // Update active and hover control state on release
-            Control* inputControl = findInputControl(&newX, &newY, false);
+            Control* inputControl = findInputControl(&newX, &newY, false, contactIndex);
             if (inputControl)
             if (inputControl)
             {
             {
                 ctrl = inputControl;
                 ctrl = inputControl;
 
 
-                if (_activeControl != ctrl || _activeControlState != Control::HOVER)
+                if (__activeControl[contactIndex] != ctrl || ctrl->_state != HOVER)
                 {
                 {
-                    if (_activeControl)
-                        _activeControl->setDirty(Control::DIRTY_STATE);
+                    if (__activeControl[contactIndex])
+                    {
+                        __activeControl[contactIndex]->_state = NORMAL;
+                        __activeControl[contactIndex]->setDirty(Control::DIRTY_STATE);
+                    }
 
 
-                    _activeControl = ctrl;
-                    _activeControlState = Control::HOVER;
-                    _activeControl->setDirty(Control::DIRTY_STATE);
+                    __activeControl[contactIndex] = ctrl;
+                    ctrl->_state = HOVER;
+                    ctrl->setDirty(DIRTY_STATE);
                 }
                 }
             }
             }
             else
             else
             {
             {
-                // No longer any active control
-                if (_activeControl)
-                    _activeControl->setDirty(Control::DIRTY_STATE);
-
-                _activeControl = NULL;
-                _activeControlState = Control::NORMAL;
+                // Control no longer active
+                if (__activeControl[contactIndex])
+                {
+                    __activeControl[contactIndex]->setDirty(Control::DIRTY_STATE);
+                    __activeControl[contactIndex]->_state = NORMAL;
+                    __activeControl[contactIndex] = NULL;
+                }
             }
             }
         }
         }
 
 
@@ -484,41 +509,50 @@ Control* Form::handlePointerPressRelease(int* x, int* y, bool pressed)
     return ctrl;
     return ctrl;
 }
 }
 
 
-Control* Form::handlePointerMove(int* x, int* y)
+Control* Form::handlePointerMove(int* x, int* y, unsigned int contactIndex)
 {
 {
+    if (contactIndex >= Touch::MAX_TOUCH_POINTS)
+        return NULL;
+
     Control* ctrl = NULL;
     Control* ctrl = NULL;
 
 
     // Handle hover control changes on move, only if there is no currently active control
     // Handle hover control changes on move, only if there is no currently active control
     // (i.e. when the mouse or a finger is not down).
     // (i.e. when the mouse or a finger is not down).
-    if (_activeControl && (_activeControlState == Control::ACTIVE))
+    if (__activeControl[contactIndex] && __activeControl[contactIndex]->_state == ACTIVE)
     {
     {
-        ctrl = _activeControl;
+        // Active controls always continue receiving pointer events, even when the pointer
+        // is not on top of the control.
+        ctrl = __activeControl[contactIndex];
         screenToForm(ctrl, x, y);
         screenToForm(ctrl, x, y);
     }
     }
     else
     else
     {
     {
-        ctrl = findInputControl(x, y, false);
+        ctrl = findInputControl(x, y, false, contactIndex);
         if (ctrl)
         if (ctrl)
         {
         {
             // Update hover control
             // Update hover control
-            if (_activeControl != ctrl || _activeControlState != Control::HOVER)
+            if (__activeControl[contactIndex] != ctrl || ctrl->_state != HOVER)
             {
             {
-                if (_activeControl)
-                    _activeControl->setDirty(Control::DIRTY_STATE);
+                if (__activeControl[contactIndex])
+                {
+                    __activeControl[contactIndex]->_state = NORMAL;
+                    __activeControl[contactIndex]->setDirty(DIRTY_STATE);
+                }
 
 
-                _activeControl = ctrl;
-                _activeControlState = Control::HOVER;
-                _activeControl->setDirty(Control::DIRTY_STATE);
+                __activeControl[contactIndex] = ctrl;
+                ctrl->_state = HOVER;
+                ctrl->setDirty(DIRTY_STATE);
             }
             }
         }
         }
         else
         else
         {
         {
             // No active/hover control
             // No active/hover control
-            if (_activeControl)
-                _activeControl->setDirty(Control::DIRTY_STATE);
-
-            _activeControl = NULL;
-            _activeControlState = Control::NORMAL;
+            if (__activeControl[contactIndex])
+            {
+                __activeControl[contactIndex]->setDirty(DIRTY_STATE);
+                __activeControl[contactIndex]->_state = NORMAL;
+                __activeControl[contactIndex] = NULL;
+            }
         }
         }
     }
     }
 
 
@@ -527,13 +561,21 @@ Control* Form::handlePointerMove(int* x, int* y)
 
 
 void Form::verifyRemovedControlState(Control* control)
 void Form::verifyRemovedControlState(Control* control)
 {
 {
-    if (_focusControl == control)
-        _focusControl = NULL;
+    if (__focusControl == control)
+    {
+        __focusControl = NULL;
+    }
 
 
-    if (_activeControl == control)
+    if (control->_state == ACTIVE || control->_state == HOVER)
     {
     {
-        _activeControl = NULL;
-        _activeControlState = Control::NORMAL;
+        for (unsigned int i = 0; i < Touch::MAX_TOUCH_POINTS; ++i)
+        {
+            if (__activeControl[i] == control)
+            {
+                __activeControl[i] = NULL;
+            }
+        }
+        control->_state = NORMAL;
     }
     }
 }
 }
 
 
@@ -555,22 +597,20 @@ bool Form::pointerEventInternal(bool mouse, int evt, int x, int y, int param)
     Control* ctrl = NULL;
     Control* ctrl = NULL;
     int formX = x;
     int formX = x;
     int formY = y;
     int formY = y;
+    unsigned int contactIndex = mouse ? 0 : param;
 
 
-    if (mouse || (param == 0))
+    // Note: TOUCH_PRESS and TOUCH_RELEASE have same values as MOUSE_PRESS_LEFT_BUTTON and MOUSE_RELEASE_LEFT_BUTTON
+    if (evt == Touch::TOUCH_PRESS)
     {
     {
-        // Note: TOUCH_PRESS and TOUCH_RELEASE have same values as MOUSE_PRESS_LEFT_BUTTON and MOUSE_RELEASE_LEFT_BUTTON
-        if (evt == Touch::TOUCH_PRESS)
-        {
-            ctrl = handlePointerPressRelease(&formX, &formY, true);
-        }
-        else if (evt == Touch::TOUCH_RELEASE)
-        {
-            ctrl = handlePointerPressRelease(&formX, &formY, false);
-        }
-        else if ((mouse && evt == Mouse::MOUSE_MOVE) || (!mouse && evt == Touch::TOUCH_MOVE))
-        {
-            ctrl = handlePointerMove(&formX, &formY);
-        }
+        ctrl = handlePointerPressRelease(&formX, &formY, true, contactIndex);
+    }
+    else if (evt == Touch::TOUCH_RELEASE)
+    {
+        ctrl = handlePointerPressRelease(&formX, &formY, false, contactIndex);
+    }
+    else if ((mouse && evt == Mouse::MOUSE_MOVE) || (!mouse && evt == Touch::TOUCH_MOVE))
+    {
+        ctrl = handlePointerMove(&formX, &formY, contactIndex);
     }
     }
 
 
     // Dispatch input events to all controls that intersect this point
     // Dispatch input events to all controls that intersect this point
@@ -578,7 +618,7 @@ bool Form::pointerEventInternal(bool mouse, int evt, int x, int y, int param)
     {
     {
         formX = x;
         formX = x;
         formY = y;
         formY = y;
-        ctrl = findInputControl(&formX, &formY, false);
+        ctrl = findInputControl(&formX, &formY, false, contactIndex);
     }
     }
 
 
     if (ctrl)
     if (ctrl)
@@ -626,7 +666,7 @@ bool Form::pointerEventInternal(bool mouse, int evt, int x, int y, int param)
             }
             }
             else
             else
             {
             {
-                if (ctrl->touchEvent((Touch::TouchEvent)evt, localX, localY, param))
+                if (ctrl->touchEvent((Touch::TouchEvent)evt, localX, localY, contactIndex))
                     return true;
                     return true;
             }
             }
 
 
@@ -693,16 +733,16 @@ bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
 
 
     case Keyboard::KEY_SHIFT:
     case Keyboard::KEY_SHIFT:
         if (evt == Keyboard::KEY_PRESS)
         if (evt == Keyboard::KEY_PRESS)
-            _shiftKeyDown = true;
+            __shiftKeyDown = true;
         else if (evt == Keyboard::KEY_RELEASE)
         else if (evt == Keyboard::KEY_RELEASE)
-            _shiftKeyDown = false;
+            __shiftKeyDown = false;
         break;
         break;
     }
     }
     if (key == Keyboard::KEY_ESCAPE)
     if (key == Keyboard::KEY_ESCAPE)
         return false;
         return false;
 
 
     // Handle focus changing
     // Handle focus changing
-    if (_focusControl)
+    if (__focusControl)
     {
     {
         switch (evt)
         switch (evt)
         {
         {
@@ -710,9 +750,9 @@ bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
             switch (key)
             switch (key)
             {
             {
             case Keyboard::KEY_TAB:
             case Keyboard::KEY_TAB:
-                if (_focusControl->_parent)
+                if (__focusControl->_parent)
                 {
                 {
-                    if (_focusControl->_parent->moveFocus(_shiftKeyDown ? Container::PREVIOUS : Container::NEXT))
+                    if (__focusControl->_parent->moveFocus(__shiftKeyDown ? Container::PREVIOUS : Container::NEXT))
                         return true;
                         return true;
                 }
                 }
                 break;
                 break;
@@ -722,7 +762,7 @@ bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
     }
     }
 
 
     // Dispatch key events
     // Dispatch key events
-    Control* ctrl = _focusControl;
+    Control* ctrl = __focusControl;
     while (ctrl)
     while (ctrl)
     {
     {
         if (ctrl->isEnabled() && ctrl->isVisible())
         if (ctrl->isEnabled() && ctrl->isVisible())
@@ -758,19 +798,19 @@ void Form::pollGamepads()
 bool Form::pollGamepad(Gamepad* gamepad)
 bool Form::pollGamepad(Gamepad* gamepad)
 {
 {
     // Get the currently focused control's container for focus management and scrolling
     // Get the currently focused control's container for focus management and scrolling
-    if (!_focusControl)
+    if (!__focusControl)
         return false;
         return false;
 
 
     // Get parent container
     // Get parent container
     Container* parentContainer = NULL;
     Container* parentContainer = NULL;
-    if (_focusControl->_parent)
-        parentContainer = _focusControl->_parent;
+    if (__focusControl->_parent)
+        parentContainer = __focusControl->_parent;
 
 
     // Get scroll container
     // Get scroll container
     Container* scrollContainer = NULL;
     Container* scrollContainer = NULL;
-    if (_focusControl->isContainer())
+    if (__focusControl->isContainer())
     {
     {
-        scrollContainer = static_cast<Container*>(_focusControl);
+        scrollContainer = static_cast<Container*>(__focusControl);
         if (scrollContainer->_scroll == SCROLL_NONE)
         if (scrollContainer->_scroll == SCROLL_NONE)
             scrollContainer = NULL;
             scrollContainer = NULL;
     }
     }
@@ -867,7 +907,7 @@ bool Form::pollGamepad(Gamepad* gamepad)
 
 
 bool Form::gamepadEventInternal(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
 bool Form::gamepadEventInternal(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
 {
 {
-    if (!_focusControl)
+    if (!__focusControl)
         return false;
         return false;
 
 
     bool selectButtonPressed = gamepad->isButtonDown(Gamepad::BUTTON_A) || gamepad->isButtonDown(Gamepad::BUTTON_X);
     bool selectButtonPressed = gamepad->isButtonDown(Gamepad::BUTTON_A) || gamepad->isButtonDown(Gamepad::BUTTON_X);
@@ -876,25 +916,39 @@ bool Form::gamepadEventInternal(Gamepad::GamepadEvent evt, Gamepad* gamepad, uns
     switch (evt)
     switch (evt)
     {
     {
     case Gamepad::BUTTON_EVENT:
     case Gamepad::BUTTON_EVENT:
-        if (selectButtonPressed && (_activeControl != _focusControl || _activeControlState != Control::ACTIVE))
+        if (selectButtonPressed && __focusControl->_state != ACTIVE)
         {
         {
-            _activeControl = _focusControl;
-            _activeControlState = Control::ACTIVE;
-            _activeControl->notifyListeners(Control::Listener::PRESS);
+            if (__activeControl[0])
+                __activeControl[0]->setDirty(DIRTY_STATE);
+
+            __activeControl[0] = __focusControl;
+            __focusControl->_state = ACTIVE;
+            __focusControl->notifyListeners(Control::Listener::PRESS);
             return true;
             return true;
         }
         }
-        else if (!selectButtonPressed && _activeControl == _focusControl && _activeControlState == Control::ACTIVE)
+        else if (!selectButtonPressed && __focusControl->_state == ACTIVE)
         {
         {
-            _activeControlState = Control::NORMAL;
-            _activeControl->notifyListeners(Control::Listener::RELEASE);
-            _activeControl->notifyListeners(Control::Listener::CLICK);
+            if (__activeControl[0])
+                __activeControl[0]->setDirty(DIRTY_STATE);
+
+            for (unsigned int i = 0; i < Touch::MAX_TOUCH_POINTS; ++i)
+            {
+                if (__activeControl[i] == __focusControl)
+                {
+                    __activeControl[i] = NULL;
+                }
+            }
+
+            __focusControl->_state = NORMAL;
+            __focusControl->notifyListeners(Control::Listener::RELEASE);
+            __focusControl->notifyListeners(Control::Listener::CLICK);
             return true;
             return true;
         }
         }
         break;
         break;
     }
     }
 
 
     // Dispatch gamepad events to focused controls (or their parents)
     // Dispatch gamepad events to focused controls (or their parents)
-    Control * ctrl = _focusControl;
+    Control * ctrl = __focusControl;
     while (ctrl)
     while (ctrl)
     {
     {
         if (ctrl->isEnabled() && ctrl->isVisible())
         if (ctrl->isEnabled() && ctrl->isVisible())
@@ -968,26 +1022,28 @@ bool Form::projectPoint(int x, int y, Vector3* point)
 
 
 void Form::controlDisabled(Control* control)
 void Form::controlDisabled(Control* control)
 {
 {
-    if (Form::_focusControl && (Form::_focusControl == control || Form::_focusControl->isChild(control)))
+    if (__focusControl && (__focusControl == control || __focusControl->isChild(control)))
     {
     {
         setFocusControl(NULL);
         setFocusControl(NULL);
     }
     }
 
 
-    if (Form::_activeControl)
+    if (control->_state == ACTIVE || control->_state == HOVER)
     {
     {
-        if (Form::_activeControl == control || Form::_activeControl->isChild(control))
+        for (unsigned int i = 0; i < Touch::MAX_TOUCH_POINTS; ++i)
         {
         {
-            Form::_activeControl = NULL;
-            Form::_activeControlState = Control::NORMAL;
+            if (__activeControl[i] == control)
+            {
+                __activeControl[i] = NULL;
+            }
         }
         }
     }
     }
 }
 }
 
 
 void Form::setFocusControl(Control* control)
 void Form::setFocusControl(Control* control)
 {
 {
-    Control* oldFocus = _focusControl;
+    Control* oldFocus = __focusControl;
 
 
-    _focusControl = control;
+    __focusControl = control;
 
 
     // Deactivate the old focus control
     // Deactivate the old focus control
     if (oldFocus)
     if (oldFocus)
@@ -997,24 +1053,24 @@ void Form::setFocusControl(Control* control)
     }
     }
 
 
     // Activate the new focus control
     // Activate the new focus control
-    if (_focusControl)
+    if (__focusControl)
     {
     {
-        _focusControl->setDirty(Control::DIRTY_STATE);
-        _focusControl->notifyListeners(Control::Listener::FOCUS_GAINED);
+        __focusControl->setDirty(Control::DIRTY_STATE);
+        __focusControl->notifyListeners(Control::Listener::FOCUS_GAINED);
 
 
         // Set the activeControl property of the control's parent container
         // Set the activeControl property of the control's parent container
         Container* parent = NULL;
         Container* parent = NULL;
-        if (_focusControl->_parent)
+        if (__focusControl->_parent)
         {
         {
-            parent = _focusControl->_parent;
-            parent->_activeControl = _focusControl;
+            parent = __focusControl->_parent;
+            parent->_activeControl = __focusControl;
         }
         }
 
 
         // If this control is inside a scrollable container and is not fully visible,
         // If this control is inside a scrollable container and is not fully visible,
         // scroll the container so that it is.
         // scroll the container so that it is.
         if (parent && parent->_scroll != SCROLL_NONE && !parent->_viewportBounds.isEmpty())
         if (parent && parent->_scroll != SCROLL_NONE && !parent->_viewportBounds.isEmpty())
         {
         {
-            const Rectangle& bounds = _focusControl->getBounds();
+            const Rectangle& bounds = __focusControl->getBounds();
             if (bounds.x < parent->_scrollPosition.x)
             if (bounds.x < parent->_scrollPosition.x)
             {
             {
                 // Control is to the left of the scrolled viewport.
                 // Control is to the left of the scrolled viewport.

+ 16 - 13
gameplay/src/Form.h

@@ -69,14 +69,20 @@ public:
     static Form* getForm(const char* id);
     static Form* getForm(const char* id);
     
     
     /**
     /**
-    * Returns the single currently active control within the UI system.
-    *
-    * @return The currently active control, or NULL if no controls are currently active.
-    */
-    static Control* getActiveControl();
+     * Returns the currently active control within the UI system.
+     *
+     * An active control is a control that is currently pressed or hovered over. On a multi-touch
+     * system, it is possible for several controls to be active at once (one for each touch point).
+     * However, only a single control can have focus at once.
+     *
+     * @param touchIndex Optional touch point index to retrieve the active control for.
+     *
+     * @return The currently active control, or NULL if no controls are currently active.
+     */
+    static Control* getActiveControl(unsigned int touchIndex = 0);
 
 
     /**
     /**
-     * Returns the single current control that is in focus.
+     * Returns the current control that is in focus.
      *
      *
      * @return The current control in focus, or NULL if no controls are in focus.
      * @return The current control in focus, or NULL if no controls are in focus.
      */
      */
@@ -234,13 +240,13 @@ private:
 
 
     static bool pointerEventInternal(bool mouse, int evt, int x, int y, int param);
     static bool pointerEventInternal(bool mouse, int evt, int x, int y, int param);
 
 
-    static Control* findInputControl(int* x, int* y, bool focus);
+    static Control* findInputControl(int* x, int* y, bool focus, unsigned int contactIndex);
 
 
-    static Control* findInputControl(Control* control, int x, int y, bool focus);
+    static Control* findInputControl(Control* control, int x, int y, bool focus, unsigned int contactIndex);
 
 
-    static Control* handlePointerPressRelease(int* x, int* y, bool pressed);
+    static Control* handlePointerPressRelease(int* x, int* y, bool pressed, unsigned int contactIndex);
 
 
-    static Control* handlePointerMove(int* x, int* y);
+    static Control* handlePointerMove(int* x, int* y, unsigned int contactIndex);
 
 
     static bool screenToForm(Control* ctrl, int* x, int* y);
     static bool screenToForm(Control* ctrl, int* x, int* y);
 
 
@@ -258,9 +264,6 @@ private:
     Matrix _projectionMatrix;           // Projection matrix to be set on SpriteBatch objects when rendering the form
     Matrix _projectionMatrix;           // Projection matrix to be set on SpriteBatch objects when rendering the form
     std::vector<SpriteBatch*> _batches;
     std::vector<SpriteBatch*> _batches;
     bool _batched;
     bool _batched;
-    static Control* _focusControl;
-    static Control* _activeControl;
-    static Control::State _activeControlState;
 };
 };
 
 
 }
 }

+ 5 - 0
gameplay/src/Touch.h

@@ -11,6 +11,11 @@ class Touch
 {
 {
 public:
 public:
 
 
+    /**
+     * Maximum simultaneous touch points supported.
+     */
+    static const unsigned int MAX_TOUCH_POINTS = 10;
+
     /**
     /**
      * The touch event type.
      * The touch event type.
      */
      */