<commit_before>//
// Created by sjm-kociskobd on 12/18/15.
//

#include "libgui/Input.h"

namespace libgui
{

Input::Input(const InputId& inputId)
    : _inputId(inputId)
{
    _isOverActiveControl = false;
    _isDown              = false;
    _activeControl       = nullptr;
    _ignoredByControl    = nullptr;

    // By default there is no simulation
    _simulationOffset = Point{0, 0};

    if (_inputId.IsPointer())
    {
        _inputType = InputType::Pointer;
    }
    else
    {
        _inputType = InputType::Touch;
    }
}

/*
 *
 * Core logic
 *
 *
 */

bool Input::NotifyNewPoint(Point point, Element* overElement)
{
    bool shouldUpdateScreen = false;

    if (_activeControl)
    {
        if (overElement == _activeControl)
        {
            if (ActiveControlMove(point))
            {
                shouldUpdateScreen = true;
            }
        }
        else
        {
            if (LeaveActiveControl(point))
            {
                shouldUpdateScreen = true;
            }
        }
    }
    else if (_ignoredByControl)
    {
        if (overElement != _ignoredByControl)
        {
            LeaveIgnoredControl();
        }
    }
    else
    {
        if (overElement)
        {
            Control* overControl = dynamic_cast<Control*>(overElement);
            if (overControl && overControl->GetIsEnabled())
            {
                if (EnterControl(point, overControl))
                {
                    shouldUpdateScreen = true;
                };
            }
        }
    }

    _point = point;

    return shouldUpdateScreen;
}

bool Input::NotifyDown()
{
    bool shouldUpdateScreen = false;

    _isDown = true;

    if (_activeControl)
    {
        shouldUpdateScreen = ActiveControlDown(_point);

        // Consider the input captured when it goes down on a control
        _isCapturedByActiveControl = true;
    }

    return shouldUpdateScreen;
}

bool Input::NotifyUp()
{
    bool shouldUpdateScreen = false;

    _isDown = false;

    if (_activeControl)
    {
        shouldUpdateScreen = ActiveControlUp(_point);

        if (_isCapturedByActiveControl)
        {
            _isCapturedByActiveControl = false;

            if (InputType::Pointer == _inputType)
            {
                // When we release a pointer, then the input might still be active
                // depending on whether the point is over the control still or not
                if (!_isOverActiveControl)
                {
                    _activeControl->SetHasActiveInput(false);
                    _activeControl = nullptr;
                }
            }
            else // Touch
            {
                // When we release a touch point, that's it.  Everything is done
                // for this input.
                _activeControl->SetHasActiveInput(false);
                _activeControl = nullptr;
            }
        }
    }

    return shouldUpdateScreen;
}

/*
 * Helper functions
 */

bool Input::LeaveActiveControl(Point point)<commit_msg>Multitouch support, first draft.  This commit fixes an issue with releasing a touch point<commit_after>//
// Created by sjm-kociskobd on 12/18/15.
//

#include "libgui/Input.h"

namespace libgui
{

Input::Input(const InputId& inputId)
    : _inputId(inputId)
{
    _isOverActiveControl = false;
    _isDown              = false;
    _activeControl       = nullptr;
    _ignoredByControl    = nullptr;

    // By default there is no simulation
    _simulationOffset = Point{0, 0};

    if (_inputId.IsPointer())
    {
        _inputType = InputType::Pointer;
    }
    else
    {
        _inputType = InputType::Touch;
    }
}

/*
 *
 * Core logic
 *
 *
 */

bool Input::NotifyNewPoint(Point point, Element* overElement)
{
    bool shouldUpdateScreen = false;

    if (_activeControl)
    {
        if (overElement == _activeControl)
        {
            if (ActiveControlMove(point))
            {
                shouldUpdateScreen = true;
            }
        }
        else
        {
            if (LeaveActiveControl(point))
            {
                shouldUpdateScreen = true;
            }
        }
    }
    else if (_ignoredByControl)
    {
        if (overElement != _ignoredByControl)
        {
            LeaveIgnoredControl();
        }
    }
    else
    {
        if (overElement)
        {
            Control* overControl = dynamic_cast<Control*>(overElement);
            if (overControl && overControl->GetIsEnabled())
            {
                if (EnterControl(point, overControl))
                {
                    shouldUpdateScreen = true;
                };
            }
        }
    }

    _point = point;

    return shouldUpdateScreen;
}

bool Input::NotifyDown()
{
    bool shouldUpdateScreen = false;

    _isDown = true;

    if (_activeControl)
    {
        shouldUpdateScreen = ActiveControlDown(_point);

        // Consider the input captured when it goes down on a control
        _isCapturedByActiveControl = true;
    }

    return shouldUpdateScreen;
}

bool Input::NotifyUp()
{
    bool shouldUpdateScreen = false;

    _isDown = false;

    if (_activeControl)
    {
        if (ActiveControlUp(_point))
        {
            shouldUpdateScreen = true;
        }

        if (_isCapturedByActiveControl)
        {
            _isCapturedByActiveControl = false;

            if (_isOverActiveControl)
            {
                if (InputType::Touch == _inputType)
                {
                    // The finger has released so we need to indicate that the control has been left
                    if (LeaveActiveControl(_point))
                    {
                        shouldUpdateScreen = true;
                    }
                }
                else
                {
                    // The Pointer hasn't left the control so we don't do anything here.
                }
            }
            else
            {
                // We're releasing outside the control.  Regardless of touch or pointer type,
                // in this case the control has already been notified of having left so we just need to clean up now.
                _activeControl->SetHasActiveInput(false);
                _activeControl = nullptr;
            }
        }
    }

    return shouldUpdateScreen;
}

/*
 * Helper functions
 */

bool Input::LeaveActiveControl(Point point)
{'fraction_non_alphanumeric': 0.0821831869510665, 'fraction_numerical': 0.002509410288582183, 'mean_word_length': 1.514589905362776, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 10, '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': '730652', 'n_tokens_mistral': 1744, 'n_tokens_neox': 1658, 'n_words': 407}