<commit_before>#include "Base.h"
#include "Joystick.h"

namespace gameplay
{

Joystick::Joystick() : _absolute(true)
{
}

Joystick::Joystick(const Joystick& copy)
{
}

Joystick::~Joystick()
{
}

Joystick* Joystick::create(const char* id, Theme::Style* style)
{
    GP_ASSERT(style);

    Joystick* joystick = new Joystick();
    if (id)
        joystick->_id = id;
    joystick->setStyle(style);

    return joystick;
}

Joystick* Joystick::create(Theme::Style* style, Properties* properties)
{
    Joystick* joystick = new Joystick();
    joystick->initialize(style, properties);
    joystick->_consumeInputEvents = false;

    return joystick;
}

void Joystick::initialize(Theme::Style* style, Properties* properties)
{
    GP_ASSERT(properties);

    Control::initialize(style, properties);

    if (!properties->exists("radius"))
    {
        GP_ERROR("Failed to load joystick; required attribute 'radius' is missing.");
        return;
    }
    _radius = properties->getFloat("radius");

    if (properties->exists("absolute"))
    {
        setAbsolute(properties->getBool("absolute"));
    }

    Vector4 v;
    if (properties->getVector4("region", &v))
    {
        _absolute = false;
        _region = _bounds;
        _bounds.x = v.x;
        _bounds.y = v.y;
        _bounds.width = v.z;
        _bounds.height = v.w;
    }
}

void Joystick::addListener(Control::Listener* listener, int eventFlags)
{
    if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
    {
        GP_ERROR("TEXT_CHANGED event is not applicable to this control.");
    }

    _consumeInputEvents = true;

    Control::addListener(listener, eventFlags);
}

bool Joystick::touchEvent(Touch::TouchEvent touchEvent, int x, int y, unsigned int contactIndex)
{
    switch (touchEvent)
    {
        case Touch::TOUCH_PRESS:
        {
            float dx = 0.0f;
            float dy = 0.0f;

            if (_absolute)
            {
                dx = x - _bounds.width * 0.5f;
                dy = _bounds.height * 0.5f - y;
            }
            else
            {
                _region.x = x + _bounds.x - _region.width * 0.5f;
                _region.y = y + _bounds.y - _region.height * 0.5f;
            }

            if ((dx >= -_radius && dx <= _radius) && (dy >= -_radius && dy <= _radius))
            {
                _contactIndex = (int) contactIndex;

                notifyListeners(Listener::PRESS);

                _displacement.set(0.0f, 0.0f);
                
                Vector2 value(0.0f, 0.0f);
                if (_value != value)
                {
                    _value.set(value);
                    _dirty = true;
                    notifyListeners(Control::Listener::VALUE_CHANGED);
                }

                _state = ACTIVE;

                return _consumeInputEvents;
            }
            else
            {
                _state = NORMAL;
            }
            break;
        }
        case Touch::TOUCH_MOVE:
        {
            float dx = x - ((!_absolute) ? _region.x - _bounds.x : 0.0f) - _region.width * 0.5f;
            float dy = -(y - ((!_absolute) ? _region.y - _bounds.y : 0.0f) - _region.height * 0.5f);
            if (((dx * dx) + (dy * dy)) <= (_radius * _radius))
            {
                GP_ASSERT(_radius);
                Vector2 value(dx, dy);
                value.scale(1.0f / _radius);
                if (_value != value)
                {
                    _value.set(value);
                    _dirty = true;
                    notifyListeners(Control::Listener::VALUE_CHANGED);
                }
            }
            else
            {
                Vector2 value(dx, dy);
                value.normalize();
                value.scale(_radius);
                value.normalize();
                if (_value != value)
                {
                    _value.set(value);
                    _dirty = true;
                    notifyListeners(Control::Listener::VALUE_CHANGED);
                }
            }

            _displacement.set(dx, dy);

            return _consumeInputEvents;
        }
        case Touch::TOUCH_RELEASE:
        {
            _contactIndex = INVALID_CONTACT_INDEX;

            // Reset displacement and direction vectors.
            _displacement.set(0.0f, 0.0f);

            Vector2 value(0.0f, 0.0f);
            if (_value != value)
            {
                _value.set(value);
                _dirty = true;
                notifyListeners(Control::Listener::VALUE_CHANGED);
            }

            _state = NORMAL;

            return _consumeInputEvents;
        }
    }

    return false;
}
<commit_msg>Control::Listener's on Joystick Control not being notified of RELEASE event when Joystick control is released. Fixed by notifying listeners of RELEASE event in Joystick::touchEvent(Touch::TouchEvent, int, int, unsigned int) handler.<commit_after>#include "Base.h"
#include "Joystick.h"

namespace gameplay
{

Joystick::Joystick() : _absolute(true)
{
}

Joystick::Joystick(const Joystick& copy)
{
}

Joystick::~Joystick()
{
}

Joystick* Joystick::create(const char* id, Theme::Style* style)
{
    GP_ASSERT(style);

    Joystick* joystick = new Joystick();
    if (id)
        joystick->_id = id;
    joystick->setStyle(style);

    return joystick;
}

Joystick* Joystick::create(Theme::Style* style, Properties* properties)
{
    Joystick* joystick = new Joystick();
    joystick->initialize(style, properties);
    joystick->_consumeInputEvents = false;

    return joystick;
}

void Joystick::initialize(Theme::Style* style, Properties* properties)
{
    GP_ASSERT(properties);

    Control::initialize(style, properties);

    if (!properties->exists("radius"))
    {
        GP_ERROR("Failed to load joystick; required attribute 'radius' is missing.");
        return;
    }
    _radius = properties->getFloat("radius");

    if (properties->exists("absolute"))
    {
        setAbsolute(properties->getBool("absolute"));
    }

    Vector4 v;
    if (properties->getVector4("region", &v))
    {
        _absolute = false;
        _region = _bounds;
        _bounds.x = v.x;
        _bounds.y = v.y;
        _bounds.width = v.z;
        _bounds.height = v.w;
    }
}

void Joystick::addListener(Control::Listener* listener, int eventFlags)
{
    if ((eventFlags & Listener::TEXT_CHANGED) == Listener::TEXT_CHANGED)
    {
        GP_ERROR("TEXT_CHANGED event is not applicable to this control.");
    }

    _consumeInputEvents = true;

    Control::addListener(listener, eventFlags);
}

bool Joystick::touchEvent(Touch::TouchEvent touchEvent, int x, int y, unsigned int contactIndex)
{
    switch (touchEvent)
    {
        case Touch::TOUCH_PRESS:
        {
            float dx = 0.0f;
            float dy = 0.0f;

            if (_absolute)
            {
                dx = x - _bounds.width * 0.5f;
                dy = _bounds.height * 0.5f - y;
            }
            else
            {
                _region.x = x + _bounds.x - _region.width * 0.5f;
                _region.y = y + _bounds.y - _region.height * 0.5f;
            }

            if ((dx >= -_radius && dx <= _radius) && (dy >= -_radius && dy <= _radius))
            {
                _contactIndex = (int) contactIndex;

                notifyListeners(Listener::PRESS);

                _displacement.set(0.0f, 0.0f);
                
                Vector2 value(0.0f, 0.0f);
                if (_value != value)
                {
                    _value.set(value);
                    _dirty = true;
                    notifyListeners(Listener::VALUE_CHANGED);
                }

                _state = ACTIVE;

                return _consumeInputEvents;
            }
            else
            {
                _state = NORMAL;
            }
            break;
        }
        case Touch::TOUCH_MOVE:
        {
            float dx = x - ((!_absolute) ? _region.x - _bounds.x : 0.0f) - _region.width * 0.5f;
            float dy = -(y - ((!_absolute) ? _region.y - _bounds.y : 0.0f) - _region.height * 0.5f);
            if (((dx * dx) + (dy * dy)) <= (_radius * _radius))
            {
                GP_ASSERT(_radius);
                Vector2 value(dx, dy);
                value.scale(1.0f / _radius);
                if (_value != value)
                {
                    _value.set(value);
                    _dirty = true;
                    notifyListeners(Listener::VALUE_CHANGED);
                }
            }
            else
            {
                Vector2 value(dx, dy);
                value.normalize();
                value.scale(_radius);
                value.normalize();
                if (_value != value)
                {
                    _value.set(value);
                    _dirty = true;
                    notifyListeners(Listener::VALUE_CHANGED);
                }
            }

            _displacement.set(dx, dy);

            return _consumeInputEvents;
        }
        case Touch::TOUCH_RELEASE:
        {
            _contactIndex = INVALID_CONTACT_INDEX;

            notifyListeners(Listener::RELEASE);

            // Reset displacement and direction vectors.
            _displacement.set(0.0f, 0.0f);

            Vector2 value(0.0f, 0.0f);
            if (_value != value)
            {
                _value.set(value);
                _dirty = true;
                notifyListeners(Listener::VALUE_CHANGED);
            }

            _state = NORMAL;

            return _consumeInputEvents;
        }
    }

    return false;
}

{'fraction_non_alphanumeric': 0.11620380037586135, 'fraction_numerical': 0.009187721862601795, 'mean_word_length': 1.5254416029528077, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6057269', 'n_tokens_mistral': 2924, 'n_tokens_neox': 2720, 'n_words': 563}