|
@@ -10,8 +10,8 @@
|
|
|
#include "RadioButton.h"
|
|
#include "RadioButton.h"
|
|
|
#include "Slider.h"
|
|
#include "Slider.h"
|
|
|
#include "TextBox.h"
|
|
#include "TextBox.h"
|
|
|
-#include "ImageControl.h"
|
|
|
|
|
#include "Joystick.h"
|
|
#include "Joystick.h"
|
|
|
|
|
+#include "ImageControl.h"
|
|
|
#include "Game.h"
|
|
#include "Game.h"
|
|
|
|
|
|
|
|
namespace gameplay
|
|
namespace gameplay
|
|
@@ -23,6 +23,12 @@ static const long SCROLL_INERTIA_DELAY = 100L;
|
|
|
static const float SCROLL_FRICTION_FACTOR = 5.0f;
|
|
static const float SCROLL_FRICTION_FACTOR = 5.0f;
|
|
|
// Distance that must be scrolled before isScrolling() will return true, used e.g. to cancel button-click events.
|
|
// Distance that must be scrolled before isScrolling() will return true, used e.g. to cancel button-click events.
|
|
|
static const float SCROLL_THRESHOLD = 10.0f;
|
|
static const float SCROLL_THRESHOLD = 10.0f;
|
|
|
|
|
+// Distance a joystick must be pushed in order to trigger focus-change and/or scrolling.
|
|
|
|
|
+static const float JOYSTICK_THRESHOLD = 0.75f;
|
|
|
|
|
+// Scroll speed when using a DPad -- max scroll speed when using a joystick.
|
|
|
|
|
+static const float GAMEPAD_SCROLL_SPEED = 500.0f;
|
|
|
|
|
+// If the DPad or joystick is held down, this is the initial delay in milliseconds between focus change events.
|
|
|
|
|
+static const float FOCUS_CHANGE_REPEAT_DELAY = 300.0f;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
* Sort function for use with _controls.sort(), based on Z-Order.
|
|
* Sort function for use with _controls.sort(), based on Z-Order.
|
|
@@ -43,7 +49,11 @@ Container::Container()
|
|
|
_scrollingVelocity(Vector2::zero()), _scrollingFriction(1.0f),
|
|
_scrollingVelocity(Vector2::zero()), _scrollingFriction(1.0f),
|
|
|
_scrollingRight(false), _scrollingDown(false),
|
|
_scrollingRight(false), _scrollingDown(false),
|
|
|
_scrollingMouseVertically(false), _scrollingMouseHorizontally(false),
|
|
_scrollingMouseVertically(false), _scrollingMouseHorizontally(false),
|
|
|
- _scrollBarOpacityClip(NULL), _zIndexDefault(0), _focusIndexDefault(0), _focusIndexMax(0), _totalWidth(0), _totalHeight(0),
|
|
|
|
|
|
|
+ _scrollBarOpacityClip(NULL), _zIndexDefault(0), _focusIndexDefault(0), _focusIndexMax(0),
|
|
|
|
|
+ _focusPressed(0), _selectButtonDown(false),
|
|
|
|
|
+ _lastFrameTime(0), _focusChangeRepeat(false),
|
|
|
|
|
+ _focusChangeStartTime(0), _focusChangeRepeatDelay(FOCUS_CHANGE_REPEAT_DELAY), _focusChangeCount(0),
|
|
|
|
|
+ _totalWidth(0), _totalHeight(0),
|
|
|
_contactIndices(0), _initializedWithScroll(false)
|
|
_contactIndices(0), _initializedWithScroll(false)
|
|
|
{
|
|
{
|
|
|
}
|
|
}
|
|
@@ -182,20 +192,6 @@ void Container::addControls(Theme* theme, Properties* properties)
|
|
|
{
|
|
{
|
|
|
addControl(control);
|
|
addControl(control);
|
|
|
control->release();
|
|
control->release();
|
|
|
-
|
|
|
|
|
- if (control->getZIndex() == -1)
|
|
|
|
|
- {
|
|
|
|
|
- control->setZIndex(_zIndexDefault++);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (control->getFocusIndex() == -1)
|
|
|
|
|
- {
|
|
|
|
|
- control->setFocusIndex(_focusIndexDefault++);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- int focusIndex = control->getFocusIndex();
|
|
|
|
|
- if (focusIndex > _focusIndexMax)
|
|
|
|
|
- _focusIndexMax = focusIndex;
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Get the next control.
|
|
// Get the next control.
|
|
@@ -203,7 +199,7 @@ void Container::addControls(Theme* theme, Properties* properties)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Sort controls by Z-Order.
|
|
// Sort controls by Z-Order.
|
|
|
- std::sort(_controls.begin(), _controls.end(), &sortControlsByZOrder);
|
|
|
|
|
|
|
+ sortControls();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
Layout* Container::getLayout()
|
|
Layout* Container::getLayout()
|
|
@@ -220,11 +216,26 @@ unsigned int Container::addControl(Control* control)
|
|
|
control->_parent->removeControl(control);
|
|
control->_parent->removeControl(control);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if (control->getZIndex() == -1)
|
|
|
|
|
+ {
|
|
|
|
|
+ control->setZIndex(_zIndexDefault++);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (control->getFocusIndex() == -1)
|
|
|
|
|
+ {
|
|
|
|
|
+ control->setFocusIndex(_focusIndexDefault++);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int focusIndex = control->getFocusIndex();
|
|
|
|
|
+ if (focusIndex > _focusIndexMax)
|
|
|
|
|
+ _focusIndexMax = focusIndex;
|
|
|
|
|
+
|
|
|
if (control->_parent != this)
|
|
if (control->_parent != this)
|
|
|
{
|
|
{
|
|
|
_controls.push_back(control);
|
|
_controls.push_back(control);
|
|
|
control->addRef();
|
|
control->addRef();
|
|
|
control->_parent = this;
|
|
control->_parent = this;
|
|
|
|
|
+ sortControls();
|
|
|
return (unsigned int)(_controls.size() - 1);
|
|
return (unsigned int)(_controls.size() - 1);
|
|
|
}
|
|
}
|
|
|
else
|
|
else
|
|
@@ -438,12 +449,6 @@ void Container::update(const Control* container, const Vector2& offset)
|
|
|
_viewportClipBounds.width -= _scrollBarVertical->getRegion().width;
|
|
_viewportClipBounds.width -= _scrollBarVertical->getRegion().width;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Sort controls by Z-Order.
|
|
|
|
|
- if (_layout->getType() == Layout::LAYOUT_ABSOLUTE)
|
|
|
|
|
- {
|
|
|
|
|
- std::sort(_controls.begin(), _controls.end(), &sortControlsByZOrder);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
GP_ASSERT(_layout);
|
|
GP_ASSERT(_layout);
|
|
|
if (_scroll != SCROLL_NONE)
|
|
if (_scroll != SCROLL_NONE)
|
|
|
{
|
|
{
|
|
@@ -623,40 +628,524 @@ bool Container::keyEvent(Keyboard::KeyEvent evt, int key)
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (control->getState() == Control::FOCUS)
|
|
|
|
|
|
|
+ if (control->getState() == Control::FOCUS && control->keyEvent(evt, key))
|
|
|
{
|
|
{
|
|
|
- if (control->keyEvent(evt, key))
|
|
|
|
|
|
|
+ release();
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // If we made it this far, no control handled the event.
|
|
|
|
|
+ if (evt == Keyboard::KEY_CHAR && key == Keyboard::KEY_TAB)
|
|
|
|
|
+ {
|
|
|
|
|
+ moveFocus(NEXT);
|
|
|
|
|
+ return _consumeInputEvents;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ release();
|
|
|
|
|
+ return false;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Container::guaranteeFocus(Control* inFocus)
|
|
|
|
|
+{
|
|
|
|
|
+ std::vector<Control*>::const_iterator it;
|
|
|
|
|
+ for (it = _controls.begin(); it < _controls.end(); it++)
|
|
|
|
|
+ {
|
|
|
|
|
+ Control* control = *it;
|
|
|
|
|
+ GP_ASSERT(control);
|
|
|
|
|
+ if (control == inFocus)
|
|
|
|
|
+ continue;
|
|
|
|
|
+
|
|
|
|
|
+ if (control->isContainer())
|
|
|
|
|
+ {
|
|
|
|
|
+ ((Container*)control)->guaranteeFocus(inFocus);
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (control->getState() == Control::FOCUS)
|
|
|
|
|
+ {
|
|
|
|
|
+ control->setState(NORMAL);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+bool Container::moveFocus(Direction direction, Control* outsideControl)
|
|
|
|
|
+{
|
|
|
|
|
+ _direction = direction;
|
|
|
|
|
+
|
|
|
|
|
+ Control* start = outsideControl;
|
|
|
|
|
+ if (!start)
|
|
|
|
|
+ {
|
|
|
|
|
+ std::vector<Control*>::const_iterator it;
|
|
|
|
|
+ for (it = _controls.begin(); it < _controls.end(); it++)
|
|
|
|
|
+ {
|
|
|
|
|
+ Control* control = *it;
|
|
|
|
|
+ GP_ASSERT(control);
|
|
|
|
|
+ if (control->getState() == Control::FOCUS)
|
|
|
{
|
|
{
|
|
|
- release();
|
|
|
|
|
|
|
+ start = control;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ int focusIndex = 0;
|
|
|
|
|
+ Control* next = NULL;
|
|
|
|
|
+ if (start)
|
|
|
|
|
+ {
|
|
|
|
|
+ const Rectangle& startBounds = start->getAbsoluteBounds();
|
|
|
|
|
+ Vector2 vStart, vNext;
|
|
|
|
|
+ float distance = FLT_MAX;
|
|
|
|
|
+ start->setState(Control::NORMAL);
|
|
|
|
|
+
|
|
|
|
|
+ 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;
|
|
|
|
|
+ case NEXT:
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (direction != NEXT)
|
|
|
|
|
+ {
|
|
|
|
|
+ std::vector<Control*>::const_iterator itt;
|
|
|
|
|
+ for (itt = _controls.begin(); itt < _controls.end(); itt++)
|
|
|
|
|
+ {
|
|
|
|
|
+ Control* nextControl = *itt;
|
|
|
|
|
+
|
|
|
|
|
+ if (nextControl == start || nextControl->getFocusIndex() < 0 ||
|
|
|
|
|
+ !nextControl->isEnabled() || !nextControl->isVisible())
|
|
|
|
|
+ {
|
|
|
|
|
+ // Control is not focusable.
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ const Rectangle& nextBounds = nextControl->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 (abs(nextDistance) < distance)
|
|
|
|
|
+ {
|
|
|
|
|
+ distance = nextDistance;
|
|
|
|
|
+ next = nextControl;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!next)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Check for controls in the given direction in our parent container.
|
|
|
|
|
+ if (!outsideControl && _parent && _parent->moveFocus(direction, start))
|
|
|
|
|
+ {
|
|
|
|
|
+ setState(NORMAL);
|
|
|
|
|
+ _focusChangeRepeat = false;
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
- else if (evt == Keyboard::KEY_CHAR && key == Keyboard::KEY_TAB)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // No control is in the given direction. Move to the next control in the focus order.
|
|
|
|
|
+ int focusDelta;
|
|
|
|
|
+ switch(direction)
|
|
|
|
|
+ {
|
|
|
|
|
+ case UP:
|
|
|
|
|
+ case LEFT:
|
|
|
|
|
+ focusDelta = -1;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case DOWN:
|
|
|
|
|
+ case RIGHT:
|
|
|
|
|
+ case NEXT:
|
|
|
|
|
+ focusDelta = 1;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Find the index to search for.
|
|
|
|
|
+ if (outsideControl)
|
|
|
|
|
+ {
|
|
|
|
|
+ focusIndex = outsideControl->_parent->getFocusIndex() + focusDelta;
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ focusIndex = start->getFocusIndex() + focusDelta;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (focusIndex > _focusIndexMax)
|
|
|
|
|
+ {
|
|
|
|
|
+ focusIndex = 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (focusIndex < 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ focusIndex = _focusIndexMax;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!next)
|
|
|
|
|
+ {
|
|
|
|
|
+ std::vector<Control*>::const_iterator itt;
|
|
|
|
|
+ for (itt = _controls.begin(); itt < _controls.end(); itt++)
|
|
|
|
|
+ {
|
|
|
|
|
+ Control* nextControl = *itt;
|
|
|
|
|
+ if (nextControl->getFocusIndex() == focusIndex)
|
|
|
|
|
+ {
|
|
|
|
|
+ next = nextControl;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // If we haven't found next by now, then there are no focusable controls in this container.
|
|
|
|
|
+ if (next)
|
|
|
|
|
+ {
|
|
|
|
|
+ next->setState(Control::FOCUS);
|
|
|
|
|
+ _dirty = true;
|
|
|
|
|
+
|
|
|
|
|
+ if (next->isContainer())
|
|
|
|
|
+ {
|
|
|
|
|
+ if (((Container*)next)->moveFocus(direction, start))
|
|
|
{
|
|
{
|
|
|
- // Shift focus to next control.
|
|
|
|
|
- int focusIndex = control->getFocusIndex() + 1; // Index to search for.
|
|
|
|
|
- if (focusIndex > _focusIndexMax)
|
|
|
|
|
|
|
+ _focusChangeRepeat = false;
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // If the next control is not fully visible, scroll the container so that it is.
|
|
|
|
|
+ const Rectangle& bounds = next->getBounds();
|
|
|
|
|
+ if (bounds.x < _scrollPosition.x)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Control is to the left of the scrolled viewport.
|
|
|
|
|
+ _scrollPosition.x = -bounds.x;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (bounds.x + bounds.width > _scrollPosition.x + _viewportBounds.width)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Control is off to the right.
|
|
|
|
|
+ _scrollPosition.x = -(bounds.x + bounds.width - _viewportBounds.width);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (bounds.y < _viewportBounds.y - _scrollPosition.y)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Control is above the viewport.
|
|
|
|
|
+ _scrollPosition.y = -bounds.y;
|
|
|
|
|
+ }
|
|
|
|
|
+ else if (bounds.y + bounds.height > _viewportBounds.height - _scrollPosition.y)
|
|
|
|
|
+ {
|
|
|
|
|
+ // Control is below the viewport.
|
|
|
|
|
+ _scrollPosition.y = -(bounds.y + bounds.height - _viewportBounds.height);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (outsideControl && outsideControl->_parent)
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusPressed = outsideControl->_parent->_focusPressed;
|
|
|
|
|
+ _focusChangeCount = outsideControl->_parent->_focusChangeCount;
|
|
|
|
|
+ _focusChangeRepeatDelay = outsideControl->_parent->_focusChangeRepeatDelay;
|
|
|
|
|
+ outsideControl->_parent->guaranteeFocus(next);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _focusChangeStartTime = Game::getAbsoluteTime();
|
|
|
|
|
+ _focusChangeRepeat = true;
|
|
|
|
|
+ addRef();
|
|
|
|
|
+ Game::getInstance()->schedule(_focusChangeRepeatDelay, this);
|
|
|
|
|
+
|
|
|
|
|
+ return true;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return false;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Container::timeEvent(long timeDiff, void* cookie)
|
|
|
|
|
+{
|
|
|
|
|
+ double time = Game::getAbsoluteTime();
|
|
|
|
|
+ if (_focusChangeRepeat && _state == FOCUS && _focusPressed &&
|
|
|
|
|
+ abs(time - timeDiff - _focusChangeRepeatDelay - _focusChangeStartTime) < 50)
|
|
|
|
|
+ {
|
|
|
|
|
+ ++_focusChangeCount;
|
|
|
|
|
+ if (_focusChangeCount == 5)
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusChangeRepeatDelay *= 0.5;
|
|
|
|
|
+ }
|
|
|
|
|
+ moveFocus(_direction);
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusChangeCount = 0;
|
|
|
|
|
+ _focusChangeRepeatDelay = FOCUS_CHANGE_REPEAT_DELAY;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ release();
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Container::startScrolling(float x, float y, bool resetTime)
|
|
|
|
|
+{
|
|
|
|
|
+ _scrollingVelocity.set(-x, y);
|
|
|
|
|
+ _scrolling = true;
|
|
|
|
|
+ _scrollBarOpacity = 1.0f;
|
|
|
|
|
+ _dirty = true;
|
|
|
|
|
+
|
|
|
|
|
+ if (_scrollBarOpacityClip && _scrollBarOpacityClip->isPlaying())
|
|
|
|
|
+ {
|
|
|
|
|
+ _scrollBarOpacityClip->stop();
|
|
|
|
|
+ _scrollBarOpacityClip = NULL;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (resetTime)
|
|
|
|
|
+ {
|
|
|
|
|
+ _lastFrameTime = Game::getGameTime();
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void Container::stopScrolling()
|
|
|
|
|
+{
|
|
|
|
|
+ _scrollingVelocity.set(0, 0);
|
|
|
|
|
+ _scrolling = false;
|
|
|
|
|
+ _dirty = true;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+bool Container::gamepadEvent(Gamepad::GamepadEvent evt, Gamepad* gamepad, unsigned int analogIndex)
|
|
|
|
|
+{
|
|
|
|
|
+ addRef();
|
|
|
|
|
+
|
|
|
|
|
+ bool eventConsumed = false;
|
|
|
|
|
+
|
|
|
|
|
+ // Pass the event to any control that is active or in focus.
|
|
|
|
|
+ std::vector<Control*>::const_iterator it;
|
|
|
|
|
+ for (it = _controls.begin(); it < _controls.end(); it++)
|
|
|
|
|
+ {
|
|
|
|
|
+ Control* control = *it;
|
|
|
|
|
+ GP_ASSERT(control);
|
|
|
|
|
+ if (control->getState() == Control::FOCUS || control->getState() == Control::ACTIVE)
|
|
|
|
|
+ {
|
|
|
|
|
+ eventConsumed |= control->gamepadEvent(evt, gamepad, analogIndex);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // First check if a selection button is down.
|
|
|
|
|
+ if (!_selectButtonDown)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (gamepad->isButtonDown(Gamepad::BUTTON_A) ||
|
|
|
|
|
+ gamepad->isButtonDown(Gamepad::BUTTON_X))
|
|
|
|
|
+ {
|
|
|
|
|
+ _selectButtonDown = true;
|
|
|
|
|
+ _focusChangeRepeat = false;
|
|
|
|
|
+ eventConsumed |= _consumeInputEvents;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ if (!gamepad->isButtonDown(Gamepad::BUTTON_A) &&
|
|
|
|
|
+ !gamepad->isButtonDown(Gamepad::BUTTON_X))
|
|
|
|
|
+ {
|
|
|
|
|
+ _selectButtonDown = false;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Vector2 joystick;
|
|
|
|
|
+ gamepad->getJoystickValues(analogIndex, &joystick);
|
|
|
|
|
+
|
|
|
|
|
+ // Don't allow focus changes or scrolling while a selection button is down.
|
|
|
|
|
+ if (!_selectButtonDown && !eventConsumed)
|
|
|
|
|
+ {
|
|
|
|
|
+ switch (evt)
|
|
|
|
|
+ {
|
|
|
|
|
+ case Gamepad::BUTTON_EVENT:
|
|
|
|
|
+ {
|
|
|
|
|
+ // Shift focus forward or backward when the DPad is used.
|
|
|
|
|
+ if (!(_focusPressed & DOWN) &&
|
|
|
|
|
+ gamepad->isButtonDown(Gamepad::BUTTON_DOWN))
|
|
|
{
|
|
{
|
|
|
- focusIndex = 0;
|
|
|
|
|
|
|
+ _focusPressed |= DOWN;
|
|
|
|
|
+ eventConsumed |= _consumeInputEvents;
|
|
|
|
|
+ if (moveFocus(DOWN))
|
|
|
|
|
+ break;
|
|
|
|
|
+ else
|
|
|
|
|
+ startScrolling(0, -GAMEPAD_SCROLL_SPEED);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!(_focusPressed & RIGHT) &&
|
|
|
|
|
+ gamepad->isButtonDown(Gamepad::BUTTON_RIGHT))
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusPressed |= RIGHT;
|
|
|
|
|
+ eventConsumed |= _consumeInputEvents;
|
|
|
|
|
+ if (moveFocus(RIGHT))
|
|
|
|
|
+ break;
|
|
|
|
|
+ else
|
|
|
|
|
+ startScrolling(GAMEPAD_SCROLL_SPEED, 0);
|
|
|
}
|
|
}
|
|
|
- control->setState(Control::NORMAL);
|
|
|
|
|
|
|
|
|
|
- std::vector<Control*>::const_iterator itt;
|
|
|
|
|
- for (itt = _controls.begin(); itt < _controls.end(); itt++)
|
|
|
|
|
|
|
+ if (!(_focusPressed & UP) &&
|
|
|
|
|
+ gamepad->isButtonDown(Gamepad::BUTTON_UP))
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusPressed |= UP;
|
|
|
|
|
+ eventConsumed |= _consumeInputEvents;
|
|
|
|
|
+ if (moveFocus(UP))
|
|
|
|
|
+ break;
|
|
|
|
|
+ else
|
|
|
|
|
+ startScrolling(0, GAMEPAD_SCROLL_SPEED);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!(_focusPressed & LEFT) &&
|
|
|
|
|
+ gamepad->isButtonDown(Gamepad::BUTTON_LEFT))
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusPressed |= LEFT;
|
|
|
|
|
+ eventConsumed |= _consumeInputEvents;
|
|
|
|
|
+ if (moveFocus(LEFT))
|
|
|
|
|
+ break;
|
|
|
|
|
+ else
|
|
|
|
|
+ startScrolling(-GAMEPAD_SCROLL_SPEED, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+ case Gamepad::JOYSTICK_EVENT:
|
|
|
|
|
+ {
|
|
|
|
|
+ switch (analogIndex)
|
|
|
{
|
|
{
|
|
|
- Control* nextControl = *itt;
|
|
|
|
|
- if (nextControl->getFocusIndex() == focusIndex)
|
|
|
|
|
|
|
+ case 0:
|
|
|
|
|
+ // The left analog stick can be used in the same way as the DPad.
|
|
|
|
|
+ eventConsumed |= _consumeInputEvents;
|
|
|
|
|
+ if (!(_focusPressed & RIGHT) &&
|
|
|
|
|
+ joystick.x > JOYSTICK_THRESHOLD)
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusPressed |= RIGHT;
|
|
|
|
|
+ if (moveFocus(RIGHT))
|
|
|
|
|
+ break;
|
|
|
|
|
+ else
|
|
|
|
|
+ startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!(_focusPressed & DOWN) &&
|
|
|
|
|
+ joystick.y < -JOYSTICK_THRESHOLD)
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusPressed |= DOWN;
|
|
|
|
|
+ if (moveFocus(DOWN))
|
|
|
|
|
+ break;
|
|
|
|
|
+ else
|
|
|
|
|
+ startScrolling(0, GAMEPAD_SCROLL_SPEED * joystick.y);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!(_focusPressed & LEFT) &&
|
|
|
|
|
+ joystick.x < -JOYSTICK_THRESHOLD)
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusPressed |= LEFT;
|
|
|
|
|
+ if (moveFocus(LEFT))
|
|
|
|
|
+ break;
|
|
|
|
|
+ else
|
|
|
|
|
+ startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, 0);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!(_focusPressed & UP) &&
|
|
|
|
|
+ joystick.y > JOYSTICK_THRESHOLD)
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusPressed |= UP;
|
|
|
|
|
+ if (moveFocus(UP))
|
|
|
|
|
+ break;
|
|
|
|
|
+ else
|
|
|
|
|
+ startScrolling(0, GAMEPAD_SCROLL_SPEED * joystick.y);
|
|
|
|
|
+ }
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case 1:
|
|
|
|
|
+ // The right analog stick can be used to scroll.
|
|
|
|
|
+ if (_scroll != SCROLL_NONE)
|
|
|
{
|
|
{
|
|
|
- nextControl->setState(Control::FOCUS);
|
|
|
|
|
|
|
+ if (_scrolling)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (joystick.isZero())
|
|
|
|
|
+ {
|
|
|
|
|
+ stopScrolling();
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, GAMEPAD_SCROLL_SPEED * joystick.y, false);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ else
|
|
|
|
|
+ {
|
|
|
|
|
+ startScrolling(GAMEPAD_SCROLL_SPEED * joystick.x, GAMEPAD_SCROLL_SPEED * joystick.y);
|
|
|
|
|
+ }
|
|
|
release();
|
|
release();
|
|
|
return _consumeInputEvents;
|
|
return _consumeInputEvents;
|
|
|
}
|
|
}
|
|
|
|
|
+ break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if ((evt == Gamepad::BUTTON_EVENT || evt == Gamepad::JOYSTICK_EVENT) &&
|
|
|
|
|
+ analogIndex == 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ if ((_focusPressed & DOWN) &&
|
|
|
|
|
+ !gamepad->isButtonDown(Gamepad::BUTTON_DOWN) &&
|
|
|
|
|
+ joystick.y > -JOYSTICK_THRESHOLD)
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusPressed &= ~DOWN;
|
|
|
|
|
+ eventConsumed |= _consumeInputEvents;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ((_focusPressed & RIGHT) &&
|
|
|
|
|
+ !gamepad->isButtonDown(Gamepad::BUTTON_RIGHT) &&
|
|
|
|
|
+ joystick.x < JOYSTICK_THRESHOLD)
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusPressed &= ~RIGHT;
|
|
|
|
|
+ eventConsumed |= _consumeInputEvents;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ((_focusPressed & UP) &&
|
|
|
|
|
+ !gamepad->isButtonDown(Gamepad::BUTTON_UP) &&
|
|
|
|
|
+ joystick.y < JOYSTICK_THRESHOLD)
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusPressed &= ~UP;
|
|
|
|
|
+ eventConsumed |= _consumeInputEvents;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if ((_focusPressed & LEFT) &&
|
|
|
|
|
+ !gamepad->isButtonDown(Gamepad::BUTTON_LEFT) &&
|
|
|
|
|
+ joystick.x > -JOYSTICK_THRESHOLD)
|
|
|
|
|
+ {
|
|
|
|
|
+ _focusPressed &= ~LEFT;
|
|
|
|
|
+ eventConsumed |= _consumeInputEvents;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if (!_focusPressed && _scrolling)
|
|
|
|
|
+ {
|
|
|
|
|
+ stopScrolling();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
release();
|
|
release();
|
|
|
- return false;
|
|
|
|
|
|
|
+ return eventConsumed;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
bool Container::isContainer() const
|
|
bool Container::isContainer() const
|
|
@@ -700,11 +1189,14 @@ void Container::updateScroll()
|
|
|
_layout->update(this, _scrollPosition);
|
|
_layout->update(this, _scrollPosition);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Update Time.
|
|
|
|
|
- static double lastFrameTime = Game::getGameTime();
|
|
|
|
|
|
|
+ // Update time.
|
|
|
|
|
+ if (!_lastFrameTime)
|
|
|
|
|
+ {
|
|
|
|
|
+ _lastFrameTime = Game::getGameTime();
|
|
|
|
|
+ }
|
|
|
double frameTime = Game::getGameTime();
|
|
double frameTime = Game::getGameTime();
|
|
|
- float elapsedTime = (float)(frameTime - lastFrameTime);
|
|
|
|
|
- lastFrameTime = frameTime;
|
|
|
|
|
|
|
+ float elapsedTime = (float)(frameTime - _lastFrameTime);
|
|
|
|
|
+ _lastFrameTime = frameTime;
|
|
|
|
|
|
|
|
const Theme::Border& containerBorder = getBorder(_state);
|
|
const Theme::Border& containerBorder = getBorder(_state);
|
|
|
const Theme::Padding& containerPadding = getPadding();
|
|
const Theme::Padding& containerPadding = getPadding();
|
|
@@ -737,7 +1229,7 @@ void Container::updateScroll()
|
|
|
float clipHeight = _bounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom - hHeight;
|
|
float clipHeight = _bounds.height - containerBorder.top - containerBorder.bottom - containerPadding.top - containerPadding.bottom - hHeight;
|
|
|
|
|
|
|
|
// Apply and dampen inertia.
|
|
// Apply and dampen inertia.
|
|
|
- if (!_scrolling && !_scrollingVelocity.isZero())
|
|
|
|
|
|
|
+ if (!_scrollingVelocity.isZero())
|
|
|
{
|
|
{
|
|
|
// Calculate the time passed since last update.
|
|
// Calculate the time passed since last update.
|
|
|
float elapsedSecs = (float)elapsedTime * 0.001f;
|
|
float elapsedSecs = (float)elapsedTime * 0.001f;
|
|
@@ -745,14 +1237,17 @@ void Container::updateScroll()
|
|
|
_scrollPosition.x += _scrollingVelocity.x * elapsedSecs;
|
|
_scrollPosition.x += _scrollingVelocity.x * elapsedSecs;
|
|
|
_scrollPosition.y += _scrollingVelocity.y * elapsedSecs;
|
|
_scrollPosition.y += _scrollingVelocity.y * elapsedSecs;
|
|
|
|
|
|
|
|
- float dampening = 1.0f - _scrollingFriction * SCROLL_FRICTION_FACTOR * elapsedSecs;
|
|
|
|
|
- _scrollingVelocity.x *= dampening;
|
|
|
|
|
- _scrollingVelocity.y *= dampening;
|
|
|
|
|
-
|
|
|
|
|
- if (fabs(_scrollingVelocity.x) < 100.0f)
|
|
|
|
|
- _scrollingVelocity.x = 0.0f;
|
|
|
|
|
- if (fabs(_scrollingVelocity.y) < 100.0f)
|
|
|
|
|
- _scrollingVelocity.y = 0.0f;
|
|
|
|
|
|
|
+ if (!_scrolling)
|
|
|
|
|
+ {
|
|
|
|
|
+ float dampening = 1.0f - _scrollingFriction * SCROLL_FRICTION_FACTOR * elapsedSecs;
|
|
|
|
|
+ _scrollingVelocity.x *= dampening;
|
|
|
|
|
+ _scrollingVelocity.y *= dampening;
|
|
|
|
|
+
|
|
|
|
|
+ if (fabs(_scrollingVelocity.x) < 100.0f)
|
|
|
|
|
+ _scrollingVelocity.x = 0.0f;
|
|
|
|
|
+ if (fabs(_scrollingVelocity.y) < 100.0f)
|
|
|
|
|
+ _scrollingVelocity.y = 0.0f;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Stop scrolling when the far edge is reached.
|
|
// Stop scrolling when the far edge is reached.
|
|
@@ -809,6 +1304,14 @@ void Container::updateScroll()
|
|
|
_layout->update(this, _scrollPosition);
|
|
_layout->update(this, _scrollPosition);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+void Container::sortControls()
|
|
|
|
|
+{
|
|
|
|
|
+ if (_layout->getType() == Layout::LAYOUT_ABSOLUTE)
|
|
|
|
|
+ {
|
|
|
|
|
+ std::sort(_controls.begin(), _controls.end(), &sortControlsByZOrder);
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
bool Container::touchEventScroll(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
|
|
bool Container::touchEventScroll(Touch::TouchEvent evt, int x, int y, unsigned int contactIndex)
|
|
|
{
|
|
{
|
|
|
switch(evt)
|
|
switch(evt)
|