Преглед изворни кода

More UI focus improvements.

Steve Grenier пре 12 година
родитељ
комит
e7b34766fa
4 измењених фајлова са 118 додато и 29 уклоњено
  1. 107 18
      gameplay/src/Container.cpp
  2. 2 1
      gameplay/src/Container.h
  3. 2 2
      gameplay/src/Control.cpp
  4. 7 8
      gameplay/src/Form.cpp

+ 107 - 18
gameplay/src/Container.cpp

@@ -791,7 +791,7 @@ bool Container::isDirty()
 
 static bool canReceiveFocus(Control* control)
 {
-    if (!(control->isEnabled() && control->isVisible()))
+    if (control->getFocusIndex() < 0 || !(control->isEnabled() && control->isVisible()))
         return false;
 
     if (control->canFocus())
@@ -812,18 +812,25 @@ static bool canReceiveFocus(Control* control)
 
 bool Container::moveFocus(Direction direction)
 {
-    switch (direction)
-    {
-    case UP:
-        return moveFocus(Vector2(0, -1));
-    case DOWN:
-        return moveFocus(Vector2(0, 1));
-    case LEFT:
-        return moveFocus(Vector2(-1, 0));
-    case RIGHT:
-        return moveFocus(Vector2(1, 0));
-    }
+	switch (direction)
+	{
+	case NEXT:
+	case PREVIOUS:
+		return moveFocusNextPrevious(direction);
+
+	case UP:
+	case DOWN:
+	case LEFT:
+	case RIGHT:
+		return moveFocusDirectional(direction);
+
+	default:
+		return false;
+	}
+}
 
+bool Container::moveFocusNextPrevious(Direction direction)
+{
     // Get the current control that has focus (either directly or indirectly) within this container
     Control* current = NULL;
     if (Form::_focusControl && Form::_focusControl->isChild(this))
@@ -860,7 +867,7 @@ bool Container::moveFocus(Direction direction)
         for (size_t i = 0, count = _controls.size(); i < count; ++i)
         {
             Control* ctrl = _controls[i];
-            if (ctrl->_focusIndex < 0 || !canReceiveFocus(ctrl))
+            if (!canReceiveFocus(ctrl))
                 continue;
 
             if ((direction == NEXT && ctrl->_focusIndex > current->_focusIndex && ctrl->_focusIndex < nextIndex) ||
@@ -882,7 +889,7 @@ bool Container::moveFocus(Direction direction)
         }
 
         // Search up into our parent container for a focus move
-        if (_parent && _parent->isContainer() && static_cast<Container*>(_parent)->moveFocus(direction))
+        if (_parent && _parent->moveFocus(direction))
             return true;
 
         // We didn't find a control to move to, so we must be the first or last focusable control in our parent.
@@ -899,13 +906,12 @@ bool Container::moveFocus(Direction direction)
 
     if (moveFirst)
     {
-
         nextIndex = direction == NEXT ? INT_MAX : INT_MIN;
         nextCtrl = NULL;
         for (size_t i = 0, count = _controls.size(); i < count; ++i)
         {
             Control* ctrl = _controls[i];
-            if (ctrl->_focusIndex < 0 || !canReceiveFocus(ctrl))
+            if (!canReceiveFocus(ctrl))
                 continue;
             if ((direction == NEXT && ctrl->_focusIndex < nextIndex) ||
                 (direction == PREVIOUS && ctrl->_focusIndex > nextIndex))
@@ -927,9 +933,92 @@ bool Container::moveFocus(Direction direction)
     return false;
 }
 
-bool Container::moveFocus(const Vector2& direction)
+bool Container::moveFocusDirectional(Direction direction)
 {
-    // TODO
+	Control* startControl = Form::_focusControl;
+	if (startControl == NULL)
+		return false;
+
+	const Rectangle& startBounds = startControl->_absoluteBounds;
+
+	Control* next = NULL;
+	Vector2 vStart, vNext;
+	float distance = FLT_MAX;
+
+	switch (direction)
+	{
+	case UP:
+		vStart.set(startBounds.x + startBounds.width * 0.5f, startBounds.y);
+		break;
+	case DOWN:
+		vStart.set(startBounds.x + startBounds.width * 0.5f, startBounds.bottom());
+		break;
+	case LEFT:
+		vStart.set(startBounds.x, startBounds.y + startBounds.height * 0.5f);
+		break;
+	case RIGHT:
+		vStart.set(startBounds.right(), startBounds.y + startBounds.height * 0.5f);
+		break;
+	}
+
+	for (size_t i = 0, count = _controls.size(); i < count; ++i)
+	{
+		Control* ctrl = _controls[i];
+		if (!canReceiveFocus(ctrl))
+			continue;
+
+		const Rectangle& nextBounds = ctrl->getAbsoluteBounds();
+		switch (direction)
+		{
+		case UP:
+			vNext.set(nextBounds.x + nextBounds.width * 0.5f, nextBounds.bottom());
+			if (vNext.y > vStart.y)
+				continue;
+			break;
+		case DOWN:
+			vNext.set(nextBounds.x + nextBounds.width * 0.5f, nextBounds.y);
+			if (vNext.y < vStart.y)
+				continue;
+			break;
+		case LEFT:
+			vNext.set(nextBounds.right(), nextBounds.y + nextBounds.height * 0.5f);
+			if (vNext.x > vStart.x)
+				continue;
+			break;
+		case RIGHT:
+			vNext.set(nextBounds.x, nextBounds.y + nextBounds.height * 0.5f);
+			if (vNext.x < vStart.x)
+				continue;
+			break;
+		}
+
+		float nextDistance = vStart.distance(vNext);
+		if (std::fabs(nextDistance) < distance)
+		{
+			distance = nextDistance;
+			next = ctrl;
+		}
+	}
+
+	if (next)
+	{
+		// If this control is a container, try to move focus to the first control within it
+		if (next->isContainer())
+		{
+			if (static_cast<Container*>(next)->moveFocusDirectional(direction))
+				return true;
+		}
+
+		if (next->setFocus())
+			return true;
+	}
+	else
+	{
+		// If no control was found, try searching in our parent container
+		if (_parent && _parent->moveFocusDirectional(direction))
+			return true;
+	}
+
     return false;
 }
 

+ 2 - 1
gameplay/src/Container.h

@@ -582,7 +582,8 @@ private:
     // in which case scrolling can be initiated.
     bool moveFocus(Direction direction);
 
-    bool moveFocus(const Vector2& direction);
+	bool moveFocusNextPrevious(Direction direction);
+	bool moveFocusDirectional(Direction direction);
 
     // Starts scrolling at the given horizontal and vertical speeds.
     void startScrolling(float x, float y, bool resetTime = true);

+ 2 - 2
gameplay/src/Control.cpp

@@ -896,9 +896,9 @@ void Control::setZIndex(int zIndex)
         _zIndex = zIndex;
         _dirty = true;
 
-        if (_parent && _parent->isContainer())
+        if (_parent)
         {
-            static_cast<Container*>(_parent)->sortControls();
+			_parent->sortControls();
         }
     }
 }

+ 7 - 8
gameplay/src/Form.cpp

@@ -601,8 +601,7 @@ Control* Form::handlePointerPressRelease(int* x, int* y, bool pressed)
             // originally pressed, fire a click event
             if (active->_absoluteClipBounds.contains(newX, newY))
             {
-                Control* parent = active->getParent();
-                if (!parent || (parent->isContainer() && !static_cast<Container*>(parent)->isScrolling()))
+				if (!active->_parent || !active->_parent->isScrolling())
                 {
                     active->notifyListeners(Control::Listener::CLICK);
                 }
@@ -844,9 +843,9 @@ bool Form::keyEventInternal(Keyboard::KeyEvent evt, int key)
             switch (key)
             {
             case Keyboard::KEY_TAB:
-                if (_focusControl->_parent && _focusControl->_parent->isContainer())
+                if (_focusControl->_parent)
                 {
-                    if (static_cast<Container*>(_focusControl->_parent)->moveFocus(_shiftKeyDown ? Container::PREVIOUS : Container::NEXT))
+                    if (_focusControl->_parent->moveFocus(_shiftKeyDown ? Container::PREVIOUS : Container::NEXT))
                         return true;
                 }
                 break;
@@ -897,8 +896,8 @@ bool Form::pollGamepad(Gamepad* gamepad)
 
     // Get parent container
     Container* parentContainer = NULL;
-    if (_focusControl->_parent && _focusControl->_parent->isContainer())
-        parentContainer = static_cast<Container*>(_focusControl->_parent);
+    if (_focusControl->_parent)
+        parentContainer = _focusControl->_parent;
 
     // Get scroll container
     Container* scrollContainer = NULL;
@@ -1164,9 +1163,9 @@ void Form::setFocusControl(Control* control)
 
         // Set the activeControl property of the control's parent container
         Container* parent = NULL;
-        if (_focusControl->_parent && _focusControl->_parent->isContainer())
+        if (_focusControl->_parent)
         {
-            parent = static_cast<Container*>(_focusControl->_parent);
+            parent = _focusControl->_parent;
             parent->_activeControl = _focusControl;
         }