<commit_before>#include "pch.h"
#include "slide_menu.h"

SlideMenu::SlideMenu()
    : _currentItemIndex(INVALID_ITEM_INDEX)
    , _animationDuration(0.2f)
    , _animationInterpolator(gameplay::Curve::QUARTIC_IN_OUT)
    , _itemScrollingClip(NULL)
{
}

SlideMenu::~SlideMenu()
{
}

const char * SlideMenu::getTypeName() const
{
    return "SlideMenu";
}

gameplay::Control * SlideMenu::create(gameplay::Theme::Style* style, gameplay::Properties* properties)
{
    SlideMenu * res = new SlideMenu();
    res->initialize(res->getTypeName(), style, properties);
    return res;
}

void SlideMenu::initialize(const char* typeName, gameplay::Theme::Style* style, gameplay::Properties* properties)
{
    gameplay::Container::initialize(typeName, style, properties);

    if (properties)
    {
        const char * interpolator = properties->getString("animationInterpolator");
        if (interpolator)
        {
            int type = gameplay::Curve::getInterpolationType(interpolator);
            if (type != -1)
                _animationInterpolator = static_cast<gameplay::Curve::InterpolationType>(type);
        }

        float duration = properties->getFloat("animationDuration");
        if (duration > 0)
            _animationDuration = duration;
    }
}

void SlideMenu::scrollToItem(unsigned itemIndex, bool immediately)
{
    if (itemIndex >= getControlCount() || itemIndex == _currentItemIndex)
        return;

    if (_itemScrollingClip && _itemScrollingClip->isPlaying())
    {
        _itemScrollingClip->removeEndListener(this);
        _itemScrollingClip->stop();
        _itemScrollingClip = NULL;
    }

    unsigned int lastItem = _currentItemIndex;
    if (_currentItemIndex != itemIndex)
    {
        _currentItemIndex = itemIndex;
        notifyListeners(gameplay::Control::Listener::VALUE_CHANGED);
    }

    if (!immediately && lastItem < getControlCount())
    {
        auto fadeAnimation = _fadeAnimations.find(_controls[itemIndex]);
        if (fadeAnimation != _fadeAnimations.end())
        {
            (*fadeAnimation).second->removeEndListener(this);
            (*fadeAnimation).second->stop();
        }

        float from = _controls[itemIndex]->isVisible() ? _controls[itemIndex]->getOpacity() : 0.0f;
        float to = 1.0f;
        _fadeAnimations[_controls[itemIndex]] = _controls[itemIndex]->createAnimationFromTo("scroll-fade-in", ANIMATE_OPACITY, &from, &to, gameplay::Curve::LINEAR, _animationDuration)->getClip();
        _fadeAnimations[_controls[itemIndex]]->play();
        itemFadeIn(itemIndex);

        fadeAnimation = _fadeAnimations.find(_controls[lastItem]);
        if (fadeAnimation != _fadeAnimations.end())
        {
            (*fadeAnimation).second->removeEndListener(this);
            (*fadeAnimation).second->stop();
        }

        from = _controls[lastItem]->isVisible() ? _controls[lastItem]->getOpacity() : 1.0f;
        to = 0.0f;
        _fadeAnimations[_controls[lastItem]] = _controls[lastItem]->createAnimationFromTo("scroll-fade-out", ANIMATE_OPACITY, &from, &to, gameplay::Curve::LINEAR, _animationDuration)->getClip();
        _fadeAnimations[_controls[lastItem]]->addEndListener(this);
        _fadeAnimations[_controls[lastItem]]->play();
        itemFadeOut(lastItem);

        for (unsigned i = 0; i < getControlCount(); i++)
        {
            bool visible = i == _currentItemIndex || i == lastItem;

            // stop all fade animations for items that doesn't participate in this sliding
            if (_controls[i]->isVisible() && !visible)
            {
                fadeAnimation = _fadeAnimations.find(_controls[i]);
                if (fadeAnimation != _fadeAnimations.end())
                {
                    (*fadeAnimation).second->removeEndListener(this);
                    (*fadeAnimation).second->stop();
                }
            }

            _controls[i]->setVisible(visible);
        }

        from = 0.0f;
        to = 0.0f;

        if (_layout->getType() == gameplay::Layout::LAYOUT_HORIZONTAL)
        {
            if ((_alignment & ALIGN_RIGHT) != 0)
            {
                if (itemIndex < lastItem)
                {
                    from = 0.0f;
                    to = _controls[lastItem]->getWidth() + _controls[lastItem]->getMargin().right + _controls[lastItem]->getMargin().left;
                }
                else
                {
                    GP_ASSERT(itemIndex > lastItem);
                    from = _controls[itemIndex]->getWidth() + _controls[itemIndex]->getMargin().right + _controls[itemIndex]->getMargin().left;
                    to = 0.0f;
                }
            }
            else if ((_alignment & ALIGN_LEFT) != 0)
            {
                if (itemIndex < lastItem)
                {
                    from = _controls[itemIndex]->getWidth() + _controls[itemIndex]->getMargin().right + _controls[itemIndex]->getMargin().left;
                    to = 0.0f;
                }
                else
                {
                    GP_ASSERT(itemIndex > lastItem);
                    from = 0.0f;
                    to = _controls[lastItem]->getWidth() + _controls[lastItem]->getMargin().right + _controls[lastItem]->getMargin().left;
                }
            }
        }
        else if (_layout->getType() == gameplay::Layout::LAYOUT_VERTICAL)
        {
            if ((_alignment & ALIGN_BOTTOM) != 0)
            {
                if (itemIndex < lastItem)
                {
                    from = 0.0f;
                    to = _controls[lastItem]->getHeight() + _controls[lastItem]->getMargin().top + _controls[lastItem]->getMargin().bottom;
                }
                else
                {
                    GP_ASSERT(itemIndex > lastItem);
                    from = _controls[itemIndex]->getHeight() + _controls[itemIndex]->getMargin().top + _controls[itemIndex]->getMargin().bottom;
                    to = 0.0f;
                }
            }
            else if ((_alignment & ALIGN_TOP) != 0)
            {
                if (itemIndex < lastItem)
                {
                    from = _controls[itemIndex]->getHeight() + _controls[itemIndex]->getMargin().top + _controls[itemIndex]->getMargin().bottom;
                    to = 0.0f;
                }
                else
                {
                    GP_ASSERT(itemIndex > lastItem);
                    from = 0.0f;
                    to = _controls[lastItem]->getHeight() + _controls[lastItem]->getMargin().top + _controls[lastItem]->getMargin().bottom;
                }
            }
        }

        gameplay::Animation * animation = createAnimationFromTo("menu-slide", ANIMATE_MENU_SLIDE, &from, &to,
            _animationInterpolator, _animationDuration);
        _itemScrollingClip = animation->getClip();
        _itemScrollingClip->play();
        _itemScrollingClip->addEndListener(this);
    }
    else
    {
        for (unsigned i = 0; i < getControlCount(); i++)
            _controls[i]->setVisible(i == _currentItemIndex);
    }
}

void SlideMenu::previewItem(unsigned itemIndex)
{
    // do not preview any items while scrolling
    if (_itemScrollingClip && _itemScrollingClip->isPlaying())
        return;

    unsigned i = 0;
    gameplay::Theme::Margin extraMargin;
    for (i = 0; i < getControlCount(); i++)
    {
        if (i == _currentItemIndex)
            continue;

        auto currentFadeAnimation = _fadeAnimations.find(_controls[i]);

        if (_controls[i]->isVisible() && i != itemIndex)
        {
            float from = _controls[i]->getOpacity();
            float to = 0.0f;

            if (currentFadeAnimation != _fadeAnimations.end())
            {
                (*currentFadeAnimation).second->removeEndListener(this);
                (*currentFadeAnimation).second->stop();
            }

            _fadeAnimations[_controls[i]] = _controls[i]->createAnimationFromTo("preview-fade-out", ANIMATE_OPACITY, &from, &to, gameplay::Curve::LINEAR, _animationDuration)->getClip();
            _fadeAnimations[_controls[i]]->addEndListener(this);
            _fadeAnimations[_controls[i]]->play();
            itemFadeOut(i);
        }
        else if (i == itemIndex)
        {
            float from = _controls[i]->isVisible() ? _controls[i]->getOpacity() : 0.0f;
            float to = 1.0f;

            if (currentFadeAnimation != _fadeAnimations.end())
            {
                (*currentFadeAnimation).second->removeEndListener(this);
                (*currentFadeAnimation).second->stop();
            }

            _controls[i]->setVisible(true);
            _fadeAnimations[_controls[i]] = _controls[i]->createAnimationFromTo("preview-fade-in", ANIMATE_OPACITY, &from, &to, gameplay::Curve::LINEAR, _animationDuration)->getClip();
            _fadeAnimations[_controls[i]]->play();
            itemFadeIn(i);
        }

        if (_controls[i]->isVisible())
        {
            if (_layout->getType() == gameplay::Layout::LAYOUT_HORIZONTAL)
            {
                float extraWidth = _controls[i]->getWidth() + _controls[i]->getMargin().right + _controls[i]->getMargin().left;
                if ((_alignment & ALIGN_LEFT) != 0 && i < _currentItemIndex)
                    extraMargin.left -= extraWidth;
                else if ((_alignment & ALIGN_RIGHT) != 0 && i > _currentItemIndex)
                    extraMargin.right -= extraWidth;
            }
            else if (_layout->getType() == gameplay::Layout::LAYOUT_VERTICAL)
            {
                float extraWidth = _controls[i]->getHeight() + _controls[i]->getMargin().top + _controls[i]->getMargin().bottom;
                if ((_alignment & ALIGN_TOP) != 0 && i < _currentItemIndex)
                    extraMargin.top -= extraWidth;
                else if ((_alignment & ALIGN_BOTTOM) != 0 && i > _currentItemIndex)
                    extraMargin.bottom -= extraWidth;
            }
        }
    }

    gameplay::Container::setMargin(_defaultMargin.top + extraMargin.top, _defaultMargin.bottom + extraMargin.bottom, _defaultMargin.left + extraMargin.left, _defaultMargin.right + extraMargin.right);
}

void SlideMenu::bindMenuButton(gameplay::Control * control, unsigned int menuIndex)
{
    bindControlEvent(control, gameplay::Control::Listener::PRESS, [=](gameplay::Control*){ this->previewItem(menuIndex); });
    bindControlEvent(control, gameplay::Control::Listener::RELEASE, [=](gameplay::Control*){ this->previewItem(SlideMenu::INVALID_ITEM_INDEX); });
    bindControlEvent(control, gameplay::Control::Listener::ENTER, [=](gameplay::Control* control){
        if (control->getState() == gameplay::Control::ACTIVE)
            this->previewItem(menuIndex);
    });
    bindControlEvent(control, gameplay::Control::Listener::LEAVE, [=](gameplay::Control* control){
        if (control->getState() == gameplay::Control::ACTIVE)
            this->previewItem(SlideMenu::INVALID_ITEM_INDEX);
    });
    bindControlEvent(control, gameplay::Control::Listener::CLICK, [=](gameplay::Control*){ this->scrollToItem(menuIndex); });
}

void SlideMenu::unbindMenuButton(gameplay::Control * control)
{
    unbindControlEvent(control, gameplay::Control::Listener::PRESS);
    unbindControlEvent(control, gameplay::Control::Listener::RELEASE);
    unbindControlEvent(control, gameplay::Control::Listener::ENTER);
    unbindControlEvent(control, gameplay::Control::Listener::LEAVE);
    unbindControlEvent(control, gameplay::Control::Listener::CLICK);
}

void SlideMenu::setMargin(float top, float bottom, float left, float right)
{
    _defaultMargin.top = top;
    _defaultMargin.bottom = bottom;
    _defaultMargin.left = left;
    _defaultMargin.right = right;
    gameplay::Container::setMargin(top, bottom, left, right);
}

unsigned int SlideMenu::getAnimationPropertyComponentCount(int propertyId) const
{
    switch (propertyId)
    {
    case ANIMATE_MENU_SLIDE:
        return 1;
    default:
        return Container::getAnimationPropertyComponentCount(propertyId);
    }
}

void SlideMenu::getAnimationPropertyValue(int propertyId, gameplay::AnimationValue* value)
{
    GP_ASSERT(value);

    switch (propertyId)
    {
    case ANIMATE_MENU_SLIDE:
        {
            const gameplay::Theme::Margin& margin = getMargin();
            if (margin.left < _defaultMargin.left)
                value->setFloat(0, _defaultMargin.left - margin.left);
            else if (margin.right < _defaultMargin.right)
                value->setFloat(0, _defaultMargin.right - margin.right);
            else if (margin.top < _defaultMargin.top)
                value->setFloat(0, _defaultMargin.top - margin.top);
            else if (margin.bottom < _defaultMargin.bottom)
                value->setFloat(0, _defaultMargin.bottom - margin.bottom);
        }
        break;
    default:
        Container::getAnimationPropertyValue(propertyId, value);
        break;
    }
}

void SlideMenu::setAnimationPropertyValue(int propertyId, gameplay::AnimationValue* value, float blendWeight)
{
    GP_ASSERT(value);

    switch (propertyId)
    {
    case ANIMATE_MENU_SLIDE:
        if (_currentItemIndex < getControlCount())
        {
            float margin = value->getFloat(0);

            gameplay::Theme::Margin extraMargin;
            if (_currentItemIndex != INVALID_ITEM_INDEX)
            {
                if (_layout->getType() == gameplay::Layout::LAYOUT_HORIZONTAL)
                {
                    if ((_alignment & ALIGN_RIGHT) != 0)
                        extraMargin.right = -margin;
                    else if ((_alignment & ALIGN_LEFT) != 0)
                        extraMargin.left = -margin;
                }
                else if (_layout->getType() == gameplay::Layout::LAYOUT_VERTICAL)
                {
                    if ((_alignment & ALIGN_BOTTOM) != 0)
                        extraMargin.bottom = -margin;
                    else if ((_alignment & ALIGN_TOP) != 0)
                        extraMargin.top = -margin;
                }
            }
            gameplay::Container::setMargin(_defaultMargin.top + extraMargin.top, _defaultMargin.bottom + extraMargin.bottom, _defaultMargin.left + extraMargin.left, _defaultMargin.right + extraMargin.right);
        }
        break;
    default:
        Container::setAnimationPropertyValue(propertyId, value, blendWeight);
        break;
    }
}

void SlideMenu::animationEvent(gameplay::AnimationClip* clip, gameplay::AnimationClip::Listener::EventType type)
{
    GP_ASSERT(type == gameplay::AnimationClip::Listener::END);

    for (unsigned i = 0; i < getControlCount(); i++)
        _controls[i]->setVisible(i == _currentItemIndex);
    gameplay::Container::setMargin(_defaultMargin.top, _defaultMargin.bottom, _defaultMargin.left, _defaultMargin.right);
}<commit_msg>using the same default animation values for SlideMenu as for other controls<commit_after>#include "pch.h"
#include "slide_menu.h"

SlideMenu::SlideMenu()
    : _currentItemIndex(INVALID_ITEM_INDEX)
    , _animationDuration(0.6f)
    , _animationInterpolator(gameplay::Curve::QUARTIC_IN_OUT)
    , _itemScrollingClip(NULL)
{
}

SlideMenu::~SlideMenu()
{
}

const char * SlideMenu::getTypeName() const
{
    return "SlideMenu";
}

gameplay::Control * SlideMenu::create(gameplay::Theme::Style* style, gameplay::Properties* properties)
{
    SlideMenu * res = new SlideMenu();
    res->initialize(res->getTypeName(), style, properties);
    return res;
}

void SlideMenu::initialize(const char* typeName, gameplay::Theme::Style* style, gameplay::Properties* properties)
{
    gameplay::Container::initialize(typeName, style, properties);

    if (properties)
    {
        const char * interpolator = properties->getString("animationInterpolator");
        if (interpolator)
        {
            int type = gameplay::Curve::getInterpolationType(interpolator);
            if (type != -1)
                _animationInterpolator = static_cast<gameplay::Curve::InterpolationType>(type);
        }

        float duration = properties->getFloat("animationDuration");
        if (duration > 0)
            _animationDuration = duration;
    }
}

void SlideMenu::scrollToItem(unsigned itemIndex, bool immediately)
{
    if (itemIndex >= getControlCount() || itemIndex == _currentItemIndex)
        return;

    if (_itemScrollingClip && _itemScrollingClip->isPlaying())
    {
        _itemScrollingClip->removeEndListener(this);
        _itemScrollingClip->stop();
        _itemScrollingClip = NULL;
    }

    unsigned int lastItem = _currentItemIndex;
    if (_currentItemIndex != itemIndex)
    {
        _currentItemIndex = itemIndex;
        notifyListeners(gameplay::Control::Listener::VALUE_CHANGED);
    }

    if (!immediately && lastItem < getControlCount())
    {
        auto fadeAnimation = _fadeAnimations.find(_controls[itemIndex]);
        if (fadeAnimation != _fadeAnimations.end())
        {
            (*fadeAnimation).second->removeEndListener(this);
            (*fadeAnimation).second->stop();
        }

        float from = _controls[itemIndex]->isVisible() ? _controls[itemIndex]->getOpacity() : 0.0f;
        float to = 1.0f;
        _fadeAnimations[_controls[itemIndex]] = _controls[itemIndex]->createAnimationFromTo("scroll-fade-in", ANIMATE_OPACITY, &from, &to, _animationInterpolator, _animationDuration)->getClip();
        _fadeAnimations[_controls[itemIndex]]->play();
        itemFadeIn(itemIndex);

        fadeAnimation = _fadeAnimations.find(_controls[lastItem]);
        if (fadeAnimation != _fadeAnimations.end())
        {
            (*fadeAnimation).second->removeEndListener(this);
            (*fadeAnimation).second->stop();
        }

        from = _controls[lastItem]->isVisible() ? _controls[lastItem]->getOpacity() : 1.0f;
        to = 0.0f;
        _fadeAnimations[_controls[lastItem]] = _controls[lastItem]->createAnimationFromTo("scroll-fade-out", ANIMATE_OPACITY, &from, &to, _animationInterpolator, _animationDuration)->getClip();
        _fadeAnimations[_controls[lastItem]]->addEndListener(this);
        _fadeAnimations[_controls[lastItem]]->play();
        itemFadeOut(lastItem);

        for (unsigned i = 0; i < getControlCount(); i++)
        {
            bool visible = i == _currentItemIndex || i == lastItem;

            // stop all fade animations for items that doesn't participate in this sliding
            if (_controls[i]->isVisible() && !visible)
            {
                fadeAnimation = _fadeAnimations.find(_controls[i]);
                if (fadeAnimation != _fadeAnimations.end())
                {
                    (*fadeAnimation).second->removeEndListener(this);
                    (*fadeAnimation).second->stop();
                }
            }

            _controls[i]->setVisible(visible);
        }

        from = 0.0f;
        to = 0.0f;

        if (_layout->getType() == gameplay::Layout::LAYOUT_HORIZONTAL)
        {
            if ((_alignment & ALIGN_RIGHT) != 0)
            {
                if (itemIndex < lastItem)
                {
                    from = 0.0f;
                    to = _controls[lastItem]->getWidth() + _controls[lastItem]->getMargin().right + _controls[lastItem]->getMargin().left;
                }
                else
                {
                    GP_ASSERT(itemIndex > lastItem);
                    from = _controls[itemIndex]->getWidth() + _controls[itemIndex]->getMargin().right + _controls[itemIndex]->getMargin().left;
                    to = 0.0f;
                }
            }
            else if ((_alignment & ALIGN_LEFT) != 0)
            {
                if (itemIndex < lastItem)
                {
                    from = _controls[itemIndex]->getWidth() + _controls[itemIndex]->getMargin().right + _controls[itemIndex]->getMargin().left;
                    to = 0.0f;
                }
                else
                {
                    GP_ASSERT(itemIndex > lastItem);
                    from = 0.0f;
                    to = _controls[lastItem]->getWidth() + _controls[lastItem]->getMargin().right + _controls[lastItem]->getMargin().left;
                }
            }
        }
        else if (_layout->getType() == gameplay::Layout::LAYOUT_VERTICAL)
        {
            if ((_alignment & ALIGN_BOTTOM) != 0)
            {
                if (itemIndex < lastItem)
                {
                    from = 0.0f;
                    to = _controls[lastItem]->getHeight() + _controls[lastItem]->getMargin().top + _controls[lastItem]->getMargin().bottom;
                }
                else
                {
                    GP_ASSERT(itemIndex > lastItem);
                    from = _controls[itemIndex]->getHeight() + _controls[itemIndex]->getMargin().top + _controls[itemIndex]->getMargin().bottom;
                    to = 0.0f;
                }
            }
            else if ((_alignment & ALIGN_TOP) != 0)
            {
                if (itemIndex < lastItem)
                {
                    from = _controls[itemIndex]->getHeight() + _controls[itemIndex]->getMargin().top + _controls[itemIndex]->getMargin().bottom;
                    to = 0.0f;
                }
                else
                {
                    GP_ASSERT(itemIndex > lastItem);
                    from = 0.0f;
                    to = _controls[lastItem]->getHeight() + _controls[lastItem]->getMargin().top + _controls[lastItem]->getMargin().bottom;
                }
            }
        }

        gameplay::Animation * animation = createAnimationFromTo("menu-slide", ANIMATE_MENU_SLIDE, &from, &to,
            _animationInterpolator, _animationDuration);
        _itemScrollingClip = animation->getClip();
        _itemScrollingClip->play();
        _itemScrollingClip->addEndListener(this);
    }
    else
    {
        for (unsigned i = 0; i < getControlCount(); i++)
            _controls[i]->setVisible(i == _currentItemIndex);
    }
}

void SlideMenu::previewItem(unsigned itemIndex)
{
    // do not preview any items while scrolling
    if (_itemScrollingClip && _itemScrollingClip->isPlaying())
        return;

    unsigned i = 0;
    gameplay::Theme::Margin extraMargin;
    for (i = 0; i < getControlCount(); i++)
    {
        if (i == _currentItemIndex)
            continue;

        auto currentFadeAnimation = _fadeAnimations.find(_controls[i]);

        if (_controls[i]->isVisible() && i != itemIndex)
        {
            float from = _controls[i]->getOpacity();
            float to = 0.0f;

            if (currentFadeAnimation != _fadeAnimations.end())
            {
                (*currentFadeAnimation).second->removeEndListener(this);
                (*currentFadeAnimation).second->stop();
            }

            _fadeAnimations[_controls[i]] = _controls[i]->createAnimationFromTo("preview-fade-out", ANIMATE_OPACITY, &from, &to, _animationInterpolator, _animationDuration)->getClip();
            _fadeAnimations[_controls[i]]->addEndListener(this);
            _fadeAnimations[_controls[i]]->play();
            itemFadeOut(i);
        }
        else if (i == itemIndex)
        {
            float from = _controls[i]->isVisible() ? _controls[i]->getOpacity() : 0.0f;
            float to = 1.0f;

            if (currentFadeAnimation != _fadeAnimations.end())
            {
                (*currentFadeAnimation).second->removeEndListener(this);
                (*currentFadeAnimation).second->stop();
            }

            _controls[i]->setVisible(true);
            _fadeAnimations[_controls[i]] = _controls[i]->createAnimationFromTo("preview-fade-in", ANIMATE_OPACITY, &from, &to, _animationInterpolator, _animationDuration)->getClip();
            _fadeAnimations[_controls[i]]->play();
            itemFadeIn(i);
        }

        if (_controls[i]->isVisible())
        {
            if (_layout->getType() == gameplay::Layout::LAYOUT_HORIZONTAL)
            {
                float extraWidth = _controls[i]->getWidth() + _controls[i]->getMargin().right + _controls[i]->getMargin().left;
                if ((_alignment & ALIGN_LEFT) != 0 && i < _currentItemIndex)
                    extraMargin.left -= extraWidth;
                else if ((_alignment & ALIGN_RIGHT) != 0 && i > _currentItemIndex)
                    extraMargin.right -= extraWidth;
            }
            else if (_layout->getType() == gameplay::Layout::LAYOUT_VERTICAL)
            {
                float extraWidth = _controls[i]->getHeight() + _controls[i]->getMargin().top + _controls[i]->getMargin().bottom;
                if ((_alignment & ALIGN_TOP) != 0 && i < _currentItemIndex)
                    extraMargin.top -= extraWidth;
                else if ((_alignment & ALIGN_BOTTOM) != 0 && i > _currentItemIndex)
                    extraMargin.bottom -= extraWidth;
            }
        }
    }

    gameplay::Container::setMargin(_defaultMargin.top + extraMargin.top, _defaultMargin.bottom + extraMargin.bottom, _defaultMargin.left + extraMargin.left, _defaultMargin.right + extraMargin.right);
}

void SlideMenu::bindMenuButton(gameplay::Control * control, unsigned int menuIndex)
{
    bindControlEvent(control, gameplay::Control::Listener::PRESS, [=](gameplay::Control*){ this->previewItem(menuIndex); });
    bindControlEvent(control, gameplay::Control::Listener::RELEASE, [=](gameplay::Control*){ this->previewItem(SlideMenu::INVALID_ITEM_INDEX); });
    bindControlEvent(control, gameplay::Control::Listener::ENTER, [=](gameplay::Control* control){
        if (control->getState() == gameplay::Control::ACTIVE)
            this->previewItem(menuIndex);
    });
    bindControlEvent(control, gameplay::Control::Listener::LEAVE, [=](gameplay::Control* control){
        if (control->getState() == gameplay::Control::ACTIVE)
            this->previewItem(SlideMenu::INVALID_ITEM_INDEX);
    });
    bindControlEvent(control, gameplay::Control::Listener::CLICK, [=](gameplay::Control*){ this->scrollToItem(menuIndex); });
}

void SlideMenu::unbindMenuButton(gameplay::Control * control)
{
    unbindControlEvent(control, gameplay::Control::Listener::PRESS);
    unbindControlEvent(control, gameplay::Control::Listener::RELEASE);
    unbindControlEvent(control, gameplay::Control::Listener::ENTER);
    unbindControlEvent(control, gameplay::Control::Listener::LEAVE);
    unbindControlEvent(control, gameplay::Control::Listener::CLICK);
}

void SlideMenu::setMargin(float top, float bottom, float left, float right)
{
    _defaultMargin.top = top;
    _defaultMargin.bottom = bottom;
    _defaultMargin.left = left;
    _defaultMargin.right = right;
    gameplay::Container::setMargin(top, bottom, left, right);
}

unsigned int SlideMenu::getAnimationPropertyComponentCount(int propertyId) const
{
    switch (propertyId)
    {
    case ANIMATE_MENU_SLIDE:
        return 1;
    default:
        return Container::getAnimationPropertyComponentCount(propertyId);
    }
}

void SlideMenu::getAnimationPropertyValue(int propertyId, gameplay::AnimationValue* value)
{
    GP_ASSERT(value);

    switch (propertyId)
    {
    case ANIMATE_MENU_SLIDE:
        {
            const gameplay::Theme::Margin& margin = getMargin();
            if (margin.left < _defaultMargin.left)
                value->setFloat(0, _defaultMargin.left - margin.left);
            else if (margin.right < _defaultMargin.right)
                value->setFloat(0, _defaultMargin.right - margin.right);
            else if (margin.top < _defaultMargin.top)
                value->setFloat(0, _defaultMargin.top - margin.top);
            else if (margin.bottom < _defaultMargin.bottom)
                value->setFloat(0, _defaultMargin.bottom - margin.bottom);
        }
        break;
    default:
        Container::getAnimationPropertyValue(propertyId, value);
        break;
    }
}

void SlideMenu::setAnimationPropertyValue(int propertyId, gameplay::AnimationValue* value, float blendWeight)
{
    GP_ASSERT(value);

    switch (propertyId)
    {
    case ANIMATE_MENU_SLIDE:
        if (_currentItemIndex < getControlCount())
        {
            float margin = value->getFloat(0);

            gameplay::Theme::Margin extraMargin;
            if (_currentItemIndex != INVALID_ITEM_INDEX)
            {
                if (_layout->getType() == gameplay::Layout::LAYOUT_HORIZONTAL)
                {
                    if ((_alignment & ALIGN_RIGHT) != 0)
                        extraMargin.right = -margin;
                    else if ((_alignment & ALIGN_LEFT) != 0)
                        extraMargin.left = -margin;
                }
                else if (_layout->getType() == gameplay::Layout::LAYOUT_VERTICAL)
                {
                    if ((_alignment & ALIGN_BOTTOM) != 0)
                        extraMargin.bottom = -margin;
                    else if ((_alignment & ALIGN_TOP) != 0)
                        extraMargin.top = -margin;
                }
            }
            gameplay::Container::setMargin(_defaultMargin.top + extraMargin.top, _defaultMargin.bottom + extraMargin.bottom, _defaultMargin.left + extraMargin.left, _defaultMargin.right + extraMargin.right);
        }
        break;
    default:
        Container::setAnimationPropertyValue(propertyId, value, blendWeight);
        break;
    }
}

void SlideMenu::animationEvent(gameplay::AnimationClip* clip, gameplay::AnimationClip::Listener::EventType type)
{
    GP_ASSERT(type == gameplay::AnimationClip::Listener::END);

    for (unsigned i = 0; i < getControlCount(); i++)
        _controls[i]->setVisible(i == _currentItemIndex);
    gameplay::Container::setMargin(_defaultMargin.top, _defaultMargin.bottom, _defaultMargin.left, _defaultMargin.right);
}<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// File contains modifications by: The Gulden developers
// All modifications:
// Copyright (c) 2016-2018 The Gulden developers
// Authored by: Malcolm MacLeod (mmacleod@gmx.com)
// Distributed under the GULDEN software license, see the accompanying
// file COPYING

#if defined(HAVE_CONFIG_H)
#include "config/build-config.h"
#endif

#include "chainparams.h"
#include "clientversion.h"
#include "compat.h"
#include "fs.h"
#include "rpc/server.h"
#include "init.h"
#include "noui.h"
#include "scheduler.h"
#include "util.h"
#include "httpserver.h"
#include "httprpc.h"
#include "utilstrencodings.h"
#include "net.h"
#include <unity/appmanager.h>

#include <boost/thread.hpp>
#include <boost/interprocess/sync/file_lock.hpp>

#include <stdio.h>

#define _(x) std::string(x)/* Keep the _() around in case gettext or such will be used later to translate non-UI */

/* Introduction text for doxygen: */

/*! \mainpage Developer documentation
 *
 * \section intro_sec Introduction
 *
 * This is the developer documentation of the reference client for an experimental new digital currency called Gulden (https://www.gulden.com),
 * which enables instant payments to anyone, anywhere in the world. Gulden uses peer-to-peer technology to operate
 * with no central authority: managing transactions and issuing money are carried out collectively by the network.
 *
 * The software is a community-driven open source project, released under the MIT license.
 *
 * \section Navigation
 * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code.
 */

int exitStatus = EXIT_SUCCESS;
bool shutDownFinalised = false;

static void handleFinalShutdown()
{
    shutDownFinalised = true;
}

static void WaitForShutdown()
{
    while (!shutDownFinalised)
    {
        MilliSleep(200);
    }
}

void handlePostInitMain()
{
}

static void handleAppInitResult(bool bResult)
{
    if (!bResult)
    {
        // InitError will have been called with detailed error, which ends up on console
        exitStatus = EXIT_FAILURE;
        AppLifecycleManager::gApp->shutdown();
        return;
    }
    handlePostInitMain();
}

static bool handlePreInitMain()
{
    return true;
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//
static void AppInit(int argc, char* argv[])
{
    AppLifecycleManager appManager;
    appManager.signalAppInitializeResult.connect(boost::bind(handleAppInitResult, _1));
    appManager.signalAboutToInitMain.connect(&handlePreInitMain);
    appManager.signalAppShutdownFinished.connect(&handleFinalShutdown);

    //fixme: (UNITY) - refactor this some more so that init is taken care of inside the app manager (like with qt app)

    //
    // Parameters
    //
    // If Qt is used, parameters/Gulden.conf are parsed in qt/Gulden.cpp's main()
    ParseParameters(argc, argv);

    // Process help and version before taking care about datadir
    if (IsArgSet("-?") || IsArgSet("-h") ||  IsArgSet("-help") || IsArgSet("-version"))
    {
        std::string strUsage = strprintf(_("%s Daemon"), _(PACKAGE_NAME)) + " " + _("version") + " " + FormatFullVersion() + "\n";

        if (IsArgSet("-version"))
        {
            strUsage += FormatParagraph(LicenseInfo());
        }
        else
        {
            strUsage += "\n" + _("Usage:") + "\n" + "  " + DAEMON_NAME + " [options]                     " + strprintf(_("Start %s Daemon"), _(PACKAGE_NAME)) + "\n";
            strUsage += "\n" + HelpMessage(HMM_GULDEND);
        }
        fprintf(stdout, "%s", strUsage.c_str());
        return;
    }

    //NB! Must be set before AppInitMain.
    fNoUI = true;

    try
    {
        if (!fs::is_directory(GetDataDir(false)))
        {
            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str());
            exitStatus = EXIT_FAILURE;
            return;
        }
        try
        {
            ReadConfigFile(GetArg("-conf", DEFAULT_CONF_FILENAME));
        }
        catch (const std::exception& e)
        {
            fprintf(stderr,"Error reading configuration file: %s\n", e.what());
            exitStatus = EXIT_FAILURE;
            return;
        }
        // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
        try
        {
            SelectParams(ChainNameFromCommandLine());
        }
        catch (const std::exception& e)
        {
            fprintf(stderr, "Error: %s\n", e.what());
            exitStatus = EXIT_FAILURE;
            return;
        }

        // Error out when loose non-argument tokens are encountered on command line
        for (int i = 1; i < argc; i++)
        {
            if (!IsSwitchChar(argv[i][0]))
            {
                fprintf(stderr, "Error: Command line contains unexpected token '%s', see GuldenD -h for a list of options.\n", argv[i]);
                exitStatus = EXIT_FAILURE;
                return;
            }
        }

        // -server defaults to true for GuldenD but not for the GUI so do this here
        SoftSetBoolArg("-server", true);
        // Set this early so that parameter interactions go to console
        InitLogging();
        InitParameterInteraction();

        //fixme: (UNITY) - This is now duplicated, factor this out into a common helper.
        // NB! This has to happen before we deamonise
        // Make sure only a single Gulden process is using the data directory.
        {
            fs::path pathLockFile = GetDataDir() / ".lock";
            FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
            if (file)
                fclose(file);

            try
            {
                static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
                if (!lock.try_lock())
                {
                    fprintf(stderr, "ERROR: Cannot obtain a lock on data directory %s. %s is probably already running.", GetDataDir().string().c_str(), _(PACKAGE_NAME).c_str());
                    exitStatus = EXIT_FAILURE;
                    AppLifecycleManager::gApp->shutdown();
                    return;
                }
            }
            catch(const boost::interprocess::interprocess_exception& e)
            {
                fprintf(stderr, "ERROR: Cannot obtain a lock on data directory %s. %s is probably already running.", GetDataDir().string().c_str(), _(PACKAGE_NAME).c_str());
                exitStatus = EXIT_FAILURE;
                AppLifecycleManager::gApp->shutdown();
                return;
            }
        }

        if (GetBoolArg("-daemon", false))
        {
            fprintf(stdout, "Gulden server starting\n");
            if (!AppLifecycleManager::gApp->daemonise())
            {
                LogPrintf("Failed to daemonise\n");
                exitStatus = EXIT_FAILURE;
                return;
            }
        }

        appManager.initialize();
    }
    catch (const std::exception& e)
    {
        PrintExceptionContinue(&e, "AppInit()");
    }
    catch (...)
    {
        PrintExceptionContinue(NULL, "AppInit()");
    }

    //fixme: (UNITY) - It would be much better to wait on a condition variable here.
    // Busy poll for shutdown and allow app to exit when we reach there.
    WaitForShutdown();
}

int main(int argc, char* argv[])
{
    SetupEnvironment();

    // Connect GuldenD signal handlers
    noui_connect();

    AppInit(argc, argv);

    return exitStatus;
}

//fixme: (HIGH)
//Super gross workaround - for some reason our macos build keeps failing to provide '___cpu_model' symbol, so we just define it ourselves as a workaround until we can fix the issue.
#ifdef MAC_OSX
#include "llvm-cpumodel-hack.cpp"
#endif
<commit_msg>MISC: Minor renames<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
//
// File contains modifications by: The Gulden developers
// All modifications:
// Copyright (c) 2016-2018 The Gulden developers
// Authored by: Malcolm MacLeod (mmacleod@gmx.com)
// Distributed under the GULDEN software license, see the accompanying
// file COPYING

#if defined(HAVE_CONFIG_H)
#include "config/build-config.h"
#endif

#include "chainparams.h"
#include "clientversion.h"
#include "compat.h"
#include "fs.h"
#include "rpc/server.h"
#include "init.h"
#include "noui.h"
#include "scheduler.h"
#include "util.h"
#include "httpserver.h"
#include "httprpc.h"
#include "utilstrencodings.h"
#include "net.h"
#include <unity/appmanager.h>

#include <boost/thread.hpp>
#include <boost/interprocess/sync/file_lock.hpp>

#include <stdio.h>

#define _(x) std::string(x)/* Keep the _() around in case gettext or such will be used later to translate non-UI */

/* Introduction text for doxygen: */

/*! \mainpage Developer documentation
 *
 * \section intro_sec Introduction
 *
 * This is the developer documentation of the reference client for an experimental new digital currency called Novo (https://www.novocurrency.com),
 * which enables instant payments to anyone, anywhere in the world. Novo uses peer-to-peer technology to operate
 * with no central authority: managing transactions and issuing money are carried out collectively by the network.
 *
 * The software is a community-driven open source project, released under the Novo license.
 *
 * \section Navigation
 * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code.
 */

int exitStatus = EXIT_SUCCESS;
bool shutDownFinalised = false;

static void handleFinalShutdown()
{
    shutDownFinalised = true;
}

static void WaitForShutdown()
{
    while (!shutDownFinalised)
    {
        MilliSleep(200);
    }
}

void handlePostInitMain()
{
}

static void handleAppInitResult(bool bResult)
{
    if (!bResult)
    {
        // InitError will have been called with detailed error, which ends up on console
        exitStatus = EXIT_FAILURE;
        AppLifecycleManager::gApp->shutdown();
        return;
    }
    handlePostInitMain();
}

static bool handlePreInitMain()
{
    return true;
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//
static void AppInit(int argc, char* argv[])
{
    AppLifecycleManager appManager;
    appManager.signalAppInitializeResult.connect(boost::bind(handleAppInitResult, _1));
    appManager.signalAboutToInitMain.connect(&handlePreInitMain);
    appManager.signalAppShutdownFinished.connect(&handleFinalShutdown);

    //fixme: (UNITY) - refactor this some more so that init is taken care of inside the app manager (like with qt app)

    //
    // Parameters
    //
    // If Qt is used, parameters/.conf are parsed in the qt clients main() implementation
    ParseParameters(argc, argv);

    // Process help and version before taking care about datadir
    if (IsArgSet("-?") || IsArgSet("-h") ||  IsArgSet("-help") || IsArgSet("-version"))
    {
        std::string strUsage = strprintf(_("%s Daemon"), _(PACKAGE_NAME)) + " " + _("version") + " " + FormatFullVersion() + "\n";

        if (IsArgSet("-version"))
        {
            strUsage += FormatParagraph(LicenseInfo());
        }
        else
        {
            strUsage += "\n" + _("Usage:") + "\n" + "  " + DAEMON_NAME + " [options]                     " + strprintf(_("Start %s Daemon"), _(PACKAGE_NAME)) + "\n";
            strUsage += "\n" + HelpMessage(HMM_GULDEND);
        }
        fprintf(stdout, "%s", strUsage.c_str());
        return;
    }

    //NB! Must be set before AppInitMain.
    fNoUI = true;

    try
    {
        if (!fs::is_directory(GetDataDir(false)))
        {
            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", GetArg("-datadir", "").c_str());
            exitStatus = EXIT_FAILURE;
            return;
        }
        try
        {
            ReadConfigFile(GetArg("-conf", DEFAULT_CONF_FILENAME));
        }
        catch (const std::exception& e)
        {
            fprintf(stderr,"Error reading configuration file: %s\n", e.what());
            exitStatus = EXIT_FAILURE;
            return;
        }
        // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
        try
        {
            SelectParams(ChainNameFromCommandLine());
        }
        catch (const std::exception& e)
        {
            fprintf(stderr, "Error: %s\n", e.what());
            exitStatus = EXIT_FAILURE;
            return;
        }

        // Error out when loose non-argument tokens are encountered on command line
        for (int i = 1; i < argc; i++)
        {
            if (!IsSwitchChar(argv[i][0]))
            {
                fprintf(stderr, "Error: Command line contains unexpected token '%s', see " DAEMON_NAME " -h for a list of options.\n", argv[i]);
                exitStatus = EXIT_FAILURE;
                return;
            }
        }

        // -server defaults to true for daemon but not for the GUI so do this here
        SoftSetBoolArg("-server", true);
        // Set this early so that parameter interactions go to console
        InitLogging();
        InitParameterInteraction();

        //fixme: (UNITY) - This is now duplicated, factor this out into a common helper.
        // NB! This has to happen before we deamonise
        // Make sure only a single process is using the data directory.
        {
            fs::path pathLockFile = GetDataDir() / ".lock";
            FILE* file = fopen(pathLockFile.string().c_str(), "a"); // empty lock file; created if it doesn't exist.
            if (file)
                fclose(file);

            try
            {
                static boost::interprocess::file_lock lock(pathLockFile.string().c_str());
                if (!lock.try_lock())
                {
                    fprintf(stderr, "ERROR: Cannot obtain a lock on data directory %s. %s is probably already running.", GetDataDir().string().c_str(), _(PACKAGE_NAME).c_str());
                    exitStatus = EXIT_FAILURE;
                    AppLifecycleManager::gApp->shutdown();
                    return;
                }
            }
            catch(const boost::interprocess::interprocess_exception& e)
            {
                fprintf(stderr, "ERROR: Cannot obtain a lock on data directory %s. %s is probably already running.", GetDataDir().string().c_str(), _(PACKAGE_NAME).c_str());
                exitStatus = EXIT_FAILURE;
                AppLifecycleManager::gApp->shutdown();
                return;
            }
        }

        if (GetBoolArg("-daemon", false))
        {
            fprintf(stdout, "%s server starting\n", _(PACKAGE_NAME));
            if (!AppLifecycleManager::gApp->daemonise())
            {
                LogPrintf("Failed to daemonise\n");
                exitStatus = EXIT_FAILURE;
                return;
            }
        }

        appManager.initialize();
    }
    catch (const std::exception& e)
    {
        PrintExceptionContinue(&e, "AppInit()");
    }
    catch (...)
    {
        PrintExceptionContinue(NULL, "AppInit()");
    }

    //fixme: (UNITY) - It would be much better to wait on a condition variable here.
    // Busy poll for shutdown and allow app to exit when we reach there.
    WaitForShutdown();
}

int main(int argc, char* argv[])
{
    SetupEnvironment();

    // Connect daemon signal handlers
    noui_connect();

    AppInit(argc, argv);

    return exitStatus;
}

//fixme: (HIGH)
//Super gross workaround - for some reason our macos build keeps failing to provide '___cpu_model' symbol, so we just define it ourselves as a workaround until we can fix the issue.
#ifdef MAC_OSX
#include "llvm-cpumodel-hack.cpp"
#endif
<|endoftext|>


<commit_before>//
// Copyright (c) 2008-2015 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "../Core/Mutex.h"
#include "../Core/ProcessUtils.h"
#include "../Math/MathDefs.h"

#include <cstdio>
#include <fcntl.h>

#ifdef __APPLE__
#include "TargetConditionals.h"
#endif

#if defined(IOS)
#include <mach/mach_host.h>
#elif !defined(ANDROID) && !defined(RPI) && !defined(EMSCRIPTEN)
#include <LibCpuId/libcpuid.h>
#endif

#ifdef WIN32
#include <windows.h>
#include <io.h>
#else
#include <unistd.h>
#endif

#if defined(_MSC_VER)
#include <float.h>
#elif !defined(ANDROID) && !defined(IOS) && !defined(RPI) && !defined(EMSCRIPTEN)
// From http://stereopsis.com/FPU.html

#define FPU_CW_PREC_MASK        0x0300
#define FPU_CW_PREC_SINGLE      0x0000
#define FPU_CW_PREC_DOUBLE      0x0200
#define FPU_CW_PREC_EXTENDED    0x0300
#define FPU_CW_ROUND_MASK       0x0c00
#define FPU_CW_ROUND_NEAR       0x0000
#define FPU_CW_ROUND_DOWN       0x0400
#define FPU_CW_ROUND_UP         0x0800
#define FPU_CW_ROUND_CHOP       0x0c00

inline unsigned GetFPUState()
{
    unsigned control = 0;
    __asm__ __volatile__ ("fnstcw %0" : "=m" (control));
    return control;
}

inline void SetFPUState(unsigned control)
{
    __asm__ __volatile__ ("fldcw %0" : : "m" (control));
}
#endif

#include "../DebugNew.h"

namespace Urho3D
{

#ifdef WIN32
static bool consoleOpened = false;
#endif
static String currentLine;
static Vector<String> arguments;

#if defined(IOS)
static void GetCPUData(host_basic_info_data_t* data)
{
    mach_msg_type_number_t infoCount;
    infoCount = HOST_BASIC_INFO_COUNT;
    host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)data, &infoCount);
}
#elif !defined(ANDROID) && !defined(RPI) && !defined(EMSCRIPTEN)
static void GetCPUData(struct cpu_id_t* data)
{
    if (cpu_identify(0, data) < 0)
    {
        data->num_logical_cpus = 1;
        data->num_cores = 1;
    }
}
#endif

void InitFPU()
{
    #if !defined(URHO3D_LUAJIT) && !defined(ANDROID) && !defined(IOS) && !defined(RPI) && !defined(__x86_64__) && !defined(_M_AMD64) && !defined(EMSCRIPTEN)
    // Make sure FPU is in round-to-nearest, single precision mode
    // This ensures Direct3D and OpenGL behave similarly, and all threads behave similarly
    #ifdef _MSC_VER
    _controlfp(_RC_NEAR | _PC_24, _MCW_RC | _MCW_PC);
    #else
    unsigned control = GetFPUState();
    control &= ~(FPU_CW_PREC_MASK | FPU_CW_ROUND_MASK);
    control |= (FPU_CW_PREC_SINGLE | FPU_CW_ROUND_NEAR);
    SetFPUState(control);
    #endif
    #endif
}

void ErrorDialog(const String& title, const String& message)
{
    #ifdef WIN32
    MessageBoxW(0, WString(message).CString(), WString(title).CString(), 0);
    #else
    PrintLine(message, true);
    #endif
}

void ErrorExit(const String& message, int exitCode)
{
    if (!message.Empty())
        PrintLine(message, true);

    exit(exitCode);
}

void OpenConsoleWindow()
{
    #ifdef WIN32
    if (consoleOpened)
        return;

    AllocConsole();

    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    int hCrt = _open_osfhandle((size_t)hOut, _O_TEXT);
    FILE* outFile = _fdopen(hCrt, "w");
    setvbuf(outFile, NULL, _IONBF, 1);
    *stdout = *outFile;

    HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
    hCrt = _open_osfhandle((size_t)hIn, _O_TEXT);
    FILE* inFile = _fdopen(hCrt, "r");
    setvbuf(inFile, NULL, _IONBF, 128);
    *stdin = *inFile;

    consoleOpened = true;
    #endif
}

void PrintUnicode(const String& str, bool error)
{
    #if !defined(ANDROID) && !defined(IOS)
    #ifdef WIN32
    HANDLE stream = GetStdHandle(error ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE);
    if (stream == INVALID_HANDLE_VALUE)
        return;
    WString strW(str);
    DWORD charsWritten;
    WriteConsoleW(stream, strW.CString(), strW.Length(), &charsWritten, 0);
    #else
    fprintf(error ? stderr : stdout, "%s", str.CString());
    #endif
    #endif
}

void PrintUnicodeLine(const String& str, bool error)
{
    PrintUnicode(str + '\n', error);
}

void PrintLine(const String& str, bool error)
{
    #if !defined(ANDROID) && !defined(IOS)
    fprintf(error ? stderr: stdout, "%s\n", str.CString());
    #endif
}

const Vector<String>& ParseArguments(const String& cmdLine, bool skipFirstArgument)
{
    arguments.Clear();

    unsigned cmdStart = 0, cmdEnd = 0;
    bool inCmd = false;
    bool inQuote = false;

    for (unsigned i = 0; i < cmdLine.Length(); ++i)
    {
        if (cmdLine[i] == '\"')
            inQuote = !inQuote;
        if (cmdLine[i] == ' ' && !inQuote)
        {
            if (inCmd)
            {
                inCmd = false;
                cmdEnd = i;
                // Do not store the first argument (executable name)
                if (!skipFirstArgument)
                    arguments.Push(cmdLine.Substring(cmdStart, cmdEnd - cmdStart));
                skipFirstArgument = false;
            }
        }
        else
        {
            if (!inCmd)
            {
                inCmd = true;
                cmdStart = i;
            }
        }
    }
    if (inCmd)
    {
        cmdEnd = cmdLine.Length();
        if (!skipFirstArgument)
            arguments.Push(cmdLine.Substring(cmdStart, cmdEnd - cmdStart));
    }

    // Strip double quotes from the arguments
    for (unsigned i = 0; i < arguments.Size(); ++i)
        arguments[i].Replace("\"", "");

    return arguments;
}

const Vector<String>& ParseArguments(const char* cmdLine)
{
    return ParseArguments(String(cmdLine));
}

const Vector<String>& ParseArguments(const WString& cmdLine)
{
    return ParseArguments(String(cmdLine));
}

const Vector<String>& ParseArguments(const wchar_t* cmdLine)
{
    return ParseArguments(String(cmdLine));
}

const Vector<String>& ParseArguments(int argc, char** argv)
{
    String cmdLine;

    for (int i = 0; i < argc; ++i)
        cmdLine.AppendWithFormat("\"%s\" ", (const char*)argv[i]);

    return ParseArguments(cmdLine);
}

const Vector<String>& GetArguments()
{
    return arguments;
}

String GetConsoleInput()
{
    String ret;
    #ifdef URHO3D_TESTING
    // When we are running automated tests, reading the console may block. Just return empty in that case
    return ret;
    #endif

    #ifdef WIN32
    HANDLE input = GetStdHandle(STD_INPUT_HANDLE);
    HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
    if (input == INVALID_HANDLE_VALUE || output == INVALID_HANDLE_VALUE)
        return ret;

    // Use char-based input
    SetConsoleMode(input, ENABLE_PROCESSED_INPUT);

    INPUT_RECORD record;
    DWORD events = 0;
    DWORD readEvents = 0;

    if (!GetNumberOfConsoleInputEvents(input, &events))
        return ret;

    while (events--)
    {
        ReadConsoleInputW(input, &record, 1, &readEvents);
        if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown)
        {
            unsigned c = record.Event.KeyEvent.uChar.UnicodeChar;
            if (c)
            {
                if (c == '\b')
                {
                    PrintUnicode("\b \b");
                    int length = currentLine.LengthUTF8();
                    if (length)
                        currentLine = currentLine.SubstringUTF8(0, length - 1);
                }
                else if (c == '\r')
                {
                    PrintUnicode("\n");
                    ret = currentLine;
                    currentLine.Clear();
                    return ret;
                }
                else
                {
                    // We have disabled echo, so echo manually
                    wchar_t out = c;
                    DWORD charsWritten;
                    WriteConsoleW(output, &out, 1, &charsWritten, 0);
                    currentLine.AppendUTF8(c);
                }
            }
        }
    }
    #elif !defined(ANDROID) && !defined(IOS)
    int flags = fcntl(STDIN_FILENO, F_GETFL);
    fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
    for (;;)
    {
        int ch = fgetc(stdin);
        if (ch >= 0 && ch != '\n')
            ret += (char)ch;
        else
            break;
    }
    #endif

    return ret;
}

String GetPlatform()
{
    #if defined(ANDROID)
    return "Android";
    #elif defined(IOS)
    return "iOS";
    #elif defined(WIN32)
    return "Windows";
    #elif defined(__APPLE__)
    return "Mac OS X";
    #elif defined(RPI)
    return "Raspberry Pi";
    #elif defined(EMSCRIPTEN)
    return "HTML5";
    #elif defined(__linux__)
    return "Linux";
    #else
    return String::EMPTY;
    #endif
}

#if defined(ANDROID) || defined(RPI)
static unsigned GetArmCPUCount()
{
    FILE* fp;
    int res, i = -1, j = -1;

    fp = fopen("/sys/devices/system/cpu/present", "r");
    // If failed, return at least 1
    if (fp == 0)
        return 1;

    res = fscanf(fp, "%d-%d", &i, &j);
    fclose(fp);

    if (res == 1 && i == 0)
        return 1;
    else if (res == 2 && i == 0)
        return j + 1;

    // If failed, return at least 1
    return 1;
}
#endif

unsigned GetNumPhysicalCPUs()
{
    #if defined(IOS)
    host_basic_info_data_t data;
    GetCPUData(&data);
    #if defined(TARGET_IPHONE_SIMULATOR)
    // Hardcoded to dual-core on simulator mode even if the host has more
    return Min(2, data.physical_cpu);
    #else
    return data.physical_cpu;
    #endif
    #elif defined(ANDROID) || defined(RPI)
    return GetArmCPUCount();
    #elif !defined(EMSCRIPTEN)
    struct cpu_id_t data;
    GetCPUData(&data);
    return data.num_cores;
    #else
    /// \todo Implement properly
    return 1;
    #endif
}

unsigned GetNumLogicalCPUs()
{
    #if defined(IOS)
    host_basic_info_data_t data;
    GetCPUData(&data);
    #if defined(TARGET_IPHONE_SIMULATOR)
    return Min(2, data.logical_cpu);
    #else
    return data.logical_cpu;
    #endif
    #elif defined(ANDROID) || defined (RPI)
    return GetArmCPUCount();
    #elif !defined(EMSCRIPTEN)
    struct cpu_id_t data;
    GetCPUData(&data);
    return data.num_logical_cpus;
    #else
    /// \todo Implement properly
    return 1;
    #endif
}

}
<commit_msg>On Windows, when stdout/stderr has been redirected, use fprintf instead of WriteConsoleW() to allow capturing log output from tools. Closes #703.<commit_after>//
// Copyright (c) 2008-2015 the Urho3D project.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//

#include "../Core/Mutex.h"
#include "../Core/ProcessUtils.h"
#include "../Math/MathDefs.h"

#include <cstdio>
#include <fcntl.h>

#ifdef __APPLE__
#include "TargetConditionals.h"
#endif

#if defined(IOS)
#include <mach/mach_host.h>
#elif !defined(ANDROID) && !defined(RPI) && !defined(EMSCRIPTEN)
#include <LibCpuId/libcpuid.h>
#endif

#ifdef WIN32
#include <windows.h>
#include <io.h>
#else
#include <unistd.h>
#endif

#if defined(_MSC_VER)
#include <float.h>
#elif !defined(ANDROID) && !defined(IOS) && !defined(RPI) && !defined(EMSCRIPTEN)
// From http://stereopsis.com/FPU.html

#define FPU_CW_PREC_MASK        0x0300
#define FPU_CW_PREC_SINGLE      0x0000
#define FPU_CW_PREC_DOUBLE      0x0200
#define FPU_CW_PREC_EXTENDED    0x0300
#define FPU_CW_ROUND_MASK       0x0c00
#define FPU_CW_ROUND_NEAR       0x0000
#define FPU_CW_ROUND_DOWN       0x0400
#define FPU_CW_ROUND_UP         0x0800
#define FPU_CW_ROUND_CHOP       0x0c00

inline unsigned GetFPUState()
{
    unsigned control = 0;
    __asm__ __volatile__ ("fnstcw %0" : "=m" (control));
    return control;
}

inline void SetFPUState(unsigned control)
{
    __asm__ __volatile__ ("fldcw %0" : : "m" (control));
}
#endif

#include "../DebugNew.h"

namespace Urho3D
{

#ifdef WIN32
static bool consoleOpened = false;
#endif
static String currentLine;
static Vector<String> arguments;

#if defined(IOS)
static void GetCPUData(host_basic_info_data_t* data)
{
    mach_msg_type_number_t infoCount;
    infoCount = HOST_BASIC_INFO_COUNT;
    host_info(mach_host_self(), HOST_BASIC_INFO, (host_info_t)data, &infoCount);
}
#elif !defined(ANDROID) && !defined(RPI) && !defined(EMSCRIPTEN)
static void GetCPUData(struct cpu_id_t* data)
{
    if (cpu_identify(0, data) < 0)
    {
        data->num_logical_cpus = 1;
        data->num_cores = 1;
    }
}
#endif

void InitFPU()
{
    #if !defined(URHO3D_LUAJIT) && !defined(ANDROID) && !defined(IOS) && !defined(RPI) && !defined(__x86_64__) && !defined(_M_AMD64) && !defined(EMSCRIPTEN)
    // Make sure FPU is in round-to-nearest, single precision mode
    // This ensures Direct3D and OpenGL behave similarly, and all threads behave similarly
    #ifdef _MSC_VER
    _controlfp(_RC_NEAR | _PC_24, _MCW_RC | _MCW_PC);
    #else
    unsigned control = GetFPUState();
    control &= ~(FPU_CW_PREC_MASK | FPU_CW_ROUND_MASK);
    control |= (FPU_CW_PREC_SINGLE | FPU_CW_ROUND_NEAR);
    SetFPUState(control);
    #endif
    #endif
}

void ErrorDialog(const String& title, const String& message)
{
    #ifdef WIN32
    MessageBoxW(0, WString(message).CString(), WString(title).CString(), 0);
    #else
    PrintLine(message, true);
    #endif
}

void ErrorExit(const String& message, int exitCode)
{
    if (!message.Empty())
        PrintLine(message, true);

    exit(exitCode);
}

void OpenConsoleWindow()
{
    #ifdef WIN32
    if (consoleOpened)
        return;

    AllocConsole();

    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    int hCrt = _open_osfhandle((size_t)hOut, _O_TEXT);
    FILE* outFile = _fdopen(hCrt, "w");
    setvbuf(outFile, NULL, _IONBF, 1);
    *stdout = *outFile;

    HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
    hCrt = _open_osfhandle((size_t)hIn, _O_TEXT);
    FILE* inFile = _fdopen(hCrt, "r");
    setvbuf(inFile, NULL, _IONBF, 128);
    *stdin = *inFile;

    consoleOpened = true;
    #endif
}

void PrintUnicode(const String& str, bool error)
{
    #if !defined(ANDROID) && !defined(IOS)
    #ifdef WIN32
    // If the output stream has been redirected, use fprintf instead of WriteConsoleW,
    // though it means that proper Unicode output will not work
    FILE* out = error ? stderr : stdout;
    if (!_isatty(_fileno(out)))
        fprintf(out, "%s", str.CString());
    else
    {
        HANDLE stream = GetStdHandle(error ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE);
        if (stream == INVALID_HANDLE_VALUE)
            return;
        WString strW(str);
        DWORD charsWritten;
        WriteConsoleW(stream, strW.CString(), strW.Length(), &charsWritten, 0);
    }
    #else
    fprintf(error ? stderr : stdout, "%s", str.CString());
    #endif
    #endif
}

void PrintUnicodeLine(const String& str, bool error)
{
    PrintUnicode(str + '\n', error);
}

void PrintLine(const String& str, bool error)
{
    #if !defined(ANDROID) && !defined(IOS)
    fprintf(error ? stderr: stdout, "%s\n", str.CString());
    #endif
}

const Vector<String>& ParseArguments(const String& cmdLine, bool skipFirstArgument)
{
    arguments.Clear();

    unsigned cmdStart = 0, cmdEnd = 0;
    bool inCmd = false;
    bool inQuote = false;

    for (unsigned i = 0; i < cmdLine.Length(); ++i)
    {
        if (cmdLine[i] == '\"')
            inQuote = !inQuote;
        if (cmdLine[i] == ' ' && !inQuote)
        {
            if (inCmd)
            {
                inCmd = false;
                cmdEnd = i;
                // Do not store the first argument (executable name)
                if (!skipFirstArgument)
                    arguments.Push(cmdLine.Substring(cmdStart, cmdEnd - cmdStart));
                skipFirstArgument = false;
            }
        }
        else
        {
            if (!inCmd)
            {
                inCmd = true;
                cmdStart = i;
            }
        }
    }
    if (inCmd)
    {
        cmdEnd = cmdLine.Length();
        if (!skipFirstArgument)
            arguments.Push(cmdLine.Substring(cmdStart, cmdEnd - cmdStart));
    }

    // Strip double quotes from the arguments
    for (unsigned i = 0; i < arguments.Size(); ++i)
        arguments[i].Replace("\"", "");

    return arguments;
}

const Vector<String>& ParseArguments(const char* cmdLine)
{
    return ParseArguments(String(cmdLine));
}

const Vector<String>& ParseArguments(const WString& cmdLine)
{
    return ParseArguments(String(cmdLine));
}

const Vector<String>& ParseArguments(const wchar_t* cmdLine)
{
    return ParseArguments(String(cmdLine));
}

const Vector<String>& ParseArguments(int argc, char** argv)
{
    String cmdLine;

    for (int i = 0; i < argc; ++i)
        cmdLine.AppendWithFormat("\"%s\" ", (const char*)argv[i]);

    return ParseArguments(cmdLine);
}

const Vector<String>& GetArguments()
{
    return arguments;
}

String GetConsoleInput()
{
    String ret;
    #ifdef URHO3D_TESTING
    // When we are running automated tests, reading the console may block. Just return empty in that case
    return ret;
    #endif

    #ifdef WIN32
    HANDLE input = GetStdHandle(STD_INPUT_HANDLE);
    HANDLE output = GetStdHandle(STD_OUTPUT_HANDLE);
    if (input == INVALID_HANDLE_VALUE || output == INVALID_HANDLE_VALUE)
        return ret;

    // Use char-based input
    SetConsoleMode(input, ENABLE_PROCESSED_INPUT);

    INPUT_RECORD record;
    DWORD events = 0;
    DWORD readEvents = 0;

    if (!GetNumberOfConsoleInputEvents(input, &events))
        return ret;

    while (events--)
    {
        ReadConsoleInputW(input, &record, 1, &readEvents);
        if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown)
        {
            unsigned c = record.Event.KeyEvent.uChar.UnicodeChar;
            if (c)
            {
                if (c == '\b')
                {
                    PrintUnicode("\b \b");
                    int length = currentLine.LengthUTF8();
                    if (length)
                        currentLine = currentLine.SubstringUTF8(0, length - 1);
                }
                else if (c == '\r')
                {
                    PrintUnicode("\n");
                    ret = currentLine;
                    currentLine.Clear();
                    return ret;
                }
                else
                {
                    // We have disabled echo, so echo manually
                    wchar_t out = c;
                    DWORD charsWritten;
                    WriteConsoleW(output, &out, 1, &charsWritten, 0);
                    currentLine.AppendUTF8(c);
                }
            }
        }
    }
    #elif !defined(ANDROID) && !defined(IOS)
    int flags = fcntl(STDIN_FILENO, F_GETFL);
    fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK);
    for (;;)
    {
        int ch = fgetc(stdin);
        if (ch >= 0 && ch != '\n')
            ret += (char)ch;
        else
            break;
    }
    #endif

    return ret;
}

String GetPlatform()
{
    #if defined(ANDROID)
    return "Android";
    #elif defined(IOS)
    return "iOS";
    #elif defined(WIN32)
    return "Windows";
    #elif defined(__APPLE__)
    return "Mac OS X";
    #elif defined(RPI)
    return "Raspberry Pi";
    #elif defined(EMSCRIPTEN)
    return "HTML5";
    #elif defined(__linux__)
    return "Linux";
    #else
    return String::EMPTY;
    #endif
}

#if defined(ANDROID) || defined(RPI)
static unsigned GetArmCPUCount()
{
    FILE* fp;
    int res, i = -1, j = -1;

    fp = fopen("/sys/devices/system/cpu/present", "r");
    // If failed, return at least 1
    if (fp == 0)
        return 1;

    res = fscanf(fp, "%d-%d", &i, &j);
    fclose(fp);

    if (res == 1 && i == 0)
        return 1;
    else if (res == 2 && i == 0)
        return j + 1;

    // If failed, return at least 1
    return 1;
}
#endif

unsigned GetNumPhysicalCPUs()
{
    #if defined(IOS)
    host_basic_info_data_t data;
    GetCPUData(&data);
    #if defined(TARGET_IPHONE_SIMULATOR)
    // Hardcoded to dual-core on simulator mode even if the host has more
    return Min(2, data.physical_cpu);
    #else
    return data.physical_cpu;
    #endif
    #elif defined(ANDROID) || defined(RPI)
    return GetArmCPUCount();
    #elif !defined(EMSCRIPTEN)
    struct cpu_id_t data;
    GetCPUData(&data);
    return data.num_cores;
    #else
    /// \todo Implement properly
    return 1;
    #endif
}

unsigned GetNumLogicalCPUs()
{
    #if defined(IOS)
    host_basic_info_data_t data;
    GetCPUData(&data);
    #if defined(TARGET_IPHONE_SIMULATOR)
    return Min(2, data.logical_cpu);
    #else
    return data.logical_cpu;
    #endif
    #elif defined(ANDROID) || defined (RPI)
    return GetArmCPUCount();
    #elif !defined(EMSCRIPTEN)
    struct cpu_id_t data;
    GetCPUData(&data);
    return data.num_logical_cpus;
    #else
    /// \todo Implement properly
    return 1;
    #endif
}

}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2004-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ali Saidi
 *          Andrew Schultz
 *          Miguel Serrano
 */

#include <sys/time.h>

#include <ctime>
#include <string>

#include "base/bitfield.hh"
#include "base/time.hh"
#include "base/trace.hh"
#include "debug/MC146818.hh"
#include "dev/mc146818.hh"
#include "dev/rtcreg.h"

using namespace std;

static uint8_t
bcdize(uint8_t val)
{
    uint8_t result;
    result = val % 10;
    result += (val / 10) << 4;
    return result;
}

static uint8_t
unbcdize(uint8_t val)
{
    uint8_t result;
    result = val & 0xf;
    result += (val >> 4) * 10;
    return result;
}

void
MC146818::setTime(const struct tm time)
{
    curTime = time;
    year = time.tm_year;
    // Unix is 0-11 for month, data seet says start at 1
    mon = time.tm_mon + 1;
    mday = time.tm_mday;
    hour = time.tm_hour;
    min = time.tm_min;
    sec = time.tm_sec;

    // Datasheet says 1 is sunday
    wday = time.tm_wday + 1;

    if (!(stat_regB & RTCB_BIN)) {
        // The datasheet says that the year field can be either BCD or
        // years since 1900.  Linux seems to be happy with years since
        // 1900.
        year = bcdize(year % 100);
        mon = bcdize(mon);
        mday = bcdize(mday);
        hour = bcdize(hour);
        min = bcdize(min);
        sec = bcdize(sec);
    }
}

MC146818::MC146818(EventManager *em, const string &n, const struct tm time,
                   bool bcd, Tick frequency)
    : EventManager(em), _name(n), event(this, frequency), tickEvent(this)
{
    memset(clock_data, 0, sizeof(clock_data));
    stat_regA = RTCA_32768HZ | RTCA_1024HZ;
    stat_regB = RTCB_PRDC_IE | RTCB_24HR;
    if (!bcd)
        stat_regB |= RTCB_BIN;

    setTime(time);
    DPRINTFN("Real-time clock set to %s", asctime(&time));
}

MC146818::~MC146818()
{
    deschedule(tickEvent);
    deschedule(event);
}

void
MC146818::writeData(const uint8_t addr, const uint8_t data)
{
    if (addr < RTC_STAT_REGA) {
        clock_data[addr] = data;
        curTime.tm_sec = unbcdize(sec);
        curTime.tm_min = unbcdize(min);
        curTime.tm_hour = unbcdize(hour);
        curTime.tm_mday = unbcdize(mday);
        curTime.tm_mon = unbcdize(mon) - 1;
        curTime.tm_year = ((unbcdize(year) + 50) % 100) + 1950;
        curTime.tm_wday = unbcdize(wday) - 1;
    } else {
        switch (addr) {
          case RTC_STAT_REGA:
            // The "update in progress" bit is read only.
            if ((data & ~RTCA_UIP) != (RTCA_32768HZ | RTCA_1024HZ))
                panic("Unimplemented RTC register A value write!\n");
            replaceBits(stat_regA, data, 6, 0);
            break;
          case RTC_STAT_REGB:
            if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != RTCB_24HR)
                panic("Write to RTC reg B bits that are not implemented!\n");

            if (data & RTCB_PRDC_IE) {
                if (!event.scheduled())
                    event.scheduleIntr();
            } else {
                if (event.scheduled())
                    deschedule(event);
            }
            stat_regB = data;
            break;
          case RTC_STAT_REGC:
          case RTC_STAT_REGD:
            panic("RTC status registers C and D are not implemented.\n");
            break;
        }
    }
}

uint8_t
MC146818::readData(uint8_t addr)
{
    if (addr < RTC_STAT_REGA)
        return clock_data[addr];
    else {
        switch (addr) {
          case RTC_STAT_REGA:
            // toggle UIP bit for linux
            stat_regA ^= RTCA_UIP;
            return stat_regA;
            break;
          case RTC_STAT_REGB:
            return stat_regB;
            break;
          case RTC_STAT_REGC:
          case RTC_STAT_REGD:
            return 0x00;
            break;
          default:
            panic("Shouldn't be here");
        }
    }
}

static time_t
mkutctime(struct tm *time)
{
    time_t ret;
    char *tz;

    tz = getenv("TZ");
    setenv("TZ", "", 1);
    tzset();
    ret = mktime(time);
    if (tz)
        setenv("TZ", tz, 1);
    else
        unsetenv("TZ");
    tzset();
    return ret;
}

void
MC146818::tickClock()
{
    if (stat_regB & RTCB_NO_UPDT)
        return;
    time_t calTime = mkutctime(&curTime);
    calTime++;
    setTime(*gmtime(&calTime));
}

void
MC146818::serialize(const string &base, ostream &os)
{
    arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data));
    paramOut(os, base + ".stat_regA", stat_regA);
    paramOut(os, base + ".stat_regB", stat_regB);

    //
    // save the timer tick and rtc clock tick values to correctly reschedule
    // them during unserialize
    //
    Tick rtcTimerInterruptTickOffset = event.when() - curTick();
    SERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
    Tick rtcClockTickOffset = event.when() - curTick();
    SERIALIZE_SCALAR(rtcClockTickOffset);
}

void
MC146818::unserialize(const string &base, Checkpoint *cp,
                      const string &section)
{
    arrayParamIn(cp, section, base + ".clock_data", clock_data,
                 sizeof(clock_data));
    paramIn(cp, section, base + ".stat_regA", stat_regA);
    paramIn(cp, section, base + ".stat_regB", stat_regB);

    //
    // properly schedule the timer and rtc clock events
    //
    Tick rtcTimerInterruptTickOffset;
    UNSERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
    reschedule(event, curTick() + rtcTimerInterruptTickOffset);
    Tick rtcClockTickOffset;
    UNSERIALIZE_SCALAR(rtcClockTickOffset);
    reschedule(tickEvent, curTick() + rtcClockTickOffset);
}

MC146818::RTCEvent::RTCEvent(MC146818 * _parent, Tick i)
    : parent(_parent), interval(i)
{
    DPRINTF(MC146818, "RTC Event Initilizing\n");
    parent->schedule(this, curTick() + interval);
}

void
MC146818::RTCEvent::scheduleIntr()
{
    parent->schedule(this, curTick() + interval);
}

void
MC146818::RTCEvent::process()
{
    DPRINTF(MC146818, "RTC Timer Interrupt\n");
    parent->schedule(this, curTick() + interval);
    parent->handleEvent();
}

const char *
MC146818::RTCEvent::description() const
{
    return "RTC interrupt";
}

void
MC146818::RTCTickEvent::process()
{
    DPRINTF(MC146818, "RTC clock tick\n");
    parent->schedule(this, curTick() + SimClock::Int::s);
    parent->tickClock();
}

const char *
MC146818::RTCTickEvent::description() const
{
    return "RTC clock tick";
}
<commit_msg>mc146818: Correctly serialize tickEvent 'tickEvent' was not being serialized as in its place 'event' was being used. This patch rectifies this error.<commit_after>/*
 * Copyright (c) 2004-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Ali Saidi
 *          Andrew Schultz
 *          Miguel Serrano
 */

#include <sys/time.h>

#include <ctime>
#include <string>

#include "base/bitfield.hh"
#include "base/time.hh"
#include "base/trace.hh"
#include "debug/MC146818.hh"
#include "dev/mc146818.hh"
#include "dev/rtcreg.h"

using namespace std;

static uint8_t
bcdize(uint8_t val)
{
    uint8_t result;
    result = val % 10;
    result += (val / 10) << 4;
    return result;
}

static uint8_t
unbcdize(uint8_t val)
{
    uint8_t result;
    result = val & 0xf;
    result += (val >> 4) * 10;
    return result;
}

void
MC146818::setTime(const struct tm time)
{
    curTime = time;
    year = time.tm_year;
    // Unix is 0-11 for month, data seet says start at 1
    mon = time.tm_mon + 1;
    mday = time.tm_mday;
    hour = time.tm_hour;
    min = time.tm_min;
    sec = time.tm_sec;

    // Datasheet says 1 is sunday
    wday = time.tm_wday + 1;

    if (!(stat_regB & RTCB_BIN)) {
        // The datasheet says that the year field can be either BCD or
        // years since 1900.  Linux seems to be happy with years since
        // 1900.
        year = bcdize(year % 100);
        mon = bcdize(mon);
        mday = bcdize(mday);
        hour = bcdize(hour);
        min = bcdize(min);
        sec = bcdize(sec);
    }
}

MC146818::MC146818(EventManager *em, const string &n, const struct tm time,
                   bool bcd, Tick frequency)
    : EventManager(em), _name(n), event(this, frequency), tickEvent(this)
{
    memset(clock_data, 0, sizeof(clock_data));
    stat_regA = RTCA_32768HZ | RTCA_1024HZ;
    stat_regB = RTCB_PRDC_IE | RTCB_24HR;
    if (!bcd)
        stat_regB |= RTCB_BIN;

    setTime(time);
    DPRINTFN("Real-time clock set to %s", asctime(&time));
}

MC146818::~MC146818()
{
    deschedule(tickEvent);
    deschedule(event);
}

void
MC146818::writeData(const uint8_t addr, const uint8_t data)
{
    if (addr < RTC_STAT_REGA) {
        clock_data[addr] = data;
        curTime.tm_sec = unbcdize(sec);
        curTime.tm_min = unbcdize(min);
        curTime.tm_hour = unbcdize(hour);
        curTime.tm_mday = unbcdize(mday);
        curTime.tm_mon = unbcdize(mon) - 1;
        curTime.tm_year = ((unbcdize(year) + 50) % 100) + 1950;
        curTime.tm_wday = unbcdize(wday) - 1;
    } else {
        switch (addr) {
          case RTC_STAT_REGA:
            // The "update in progress" bit is read only.
            if ((data & ~RTCA_UIP) != (RTCA_32768HZ | RTCA_1024HZ))
                panic("Unimplemented RTC register A value write!\n");
            replaceBits(stat_regA, data, 6, 0);
            break;
          case RTC_STAT_REGB:
            if ((data & ~(RTCB_PRDC_IE | RTCB_SQWE)) != RTCB_24HR)
                panic("Write to RTC reg B bits that are not implemented!\n");

            if (data & RTCB_PRDC_IE) {
                if (!event.scheduled())
                    event.scheduleIntr();
            } else {
                if (event.scheduled())
                    deschedule(event);
            }
            stat_regB = data;
            break;
          case RTC_STAT_REGC:
          case RTC_STAT_REGD:
            panic("RTC status registers C and D are not implemented.\n");
            break;
        }
    }
}

uint8_t
MC146818::readData(uint8_t addr)
{
    if (addr < RTC_STAT_REGA)
        return clock_data[addr];
    else {
        switch (addr) {
          case RTC_STAT_REGA:
            // toggle UIP bit for linux
            stat_regA ^= RTCA_UIP;
            return stat_regA;
            break;
          case RTC_STAT_REGB:
            return stat_regB;
            break;
          case RTC_STAT_REGC:
          case RTC_STAT_REGD:
            return 0x00;
            break;
          default:
            panic("Shouldn't be here");
        }
    }
}

static time_t
mkutctime(struct tm *time)
{
    time_t ret;
    char *tz;

    tz = getenv("TZ");
    setenv("TZ", "", 1);
    tzset();
    ret = mktime(time);
    if (tz)
        setenv("TZ", tz, 1);
    else
        unsetenv("TZ");
    tzset();
    return ret;
}

void
MC146818::tickClock()
{
    if (stat_regB & RTCB_NO_UPDT)
        return;
    time_t calTime = mkutctime(&curTime);
    calTime++;
    setTime(*gmtime(&calTime));
}

void
MC146818::serialize(const string &base, ostream &os)
{
    arrayParamOut(os, base + ".clock_data", clock_data, sizeof(clock_data));
    paramOut(os, base + ".stat_regA", stat_regA);
    paramOut(os, base + ".stat_regB", stat_regB);

    //
    // save the timer tick and rtc clock tick values to correctly reschedule
    // them during unserialize
    //
    Tick rtcTimerInterruptTickOffset = event.when() - curTick();
    SERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
    Tick rtcClockTickOffset = tickEvent.when() - curTick();
    SERIALIZE_SCALAR(rtcClockTickOffset);
}

void
MC146818::unserialize(const string &base, Checkpoint *cp,
                      const string &section)
{
    arrayParamIn(cp, section, base + ".clock_data", clock_data,
                 sizeof(clock_data));
    paramIn(cp, section, base + ".stat_regA", stat_regA);
    paramIn(cp, section, base + ".stat_regB", stat_regB);

    //
    // properly schedule the timer and rtc clock events
    //
    Tick rtcTimerInterruptTickOffset;
    UNSERIALIZE_SCALAR(rtcTimerInterruptTickOffset);
    reschedule(event, curTick() + rtcTimerInterruptTickOffset);
    Tick rtcClockTickOffset;
    UNSERIALIZE_SCALAR(rtcClockTickOffset);
    reschedule(tickEvent, curTick() + rtcClockTickOffset);
}

MC146818::RTCEvent::RTCEvent(MC146818 * _parent, Tick i)
    : parent(_parent), interval(i)
{
    DPRINTF(MC146818, "RTC Event Initilizing\n");
    parent->schedule(this, curTick() + interval);
}

void
MC146818::RTCEvent::scheduleIntr()
{
    parent->schedule(this, curTick() + interval);
}

void
MC146818::RTCEvent::process()
{
    DPRINTF(MC146818, "RTC Timer Interrupt\n");
    parent->schedule(this, curTick() + interval);
    parent->handleEvent();
}

const char *
MC146818::RTCEvent::description() const
{
    return "RTC interrupt";
}

void
MC146818::RTCTickEvent::process()
{
    DPRINTF(MC146818, "RTC clock tick\n");
    parent->schedule(this, curTick() + SimClock::Int::s);
    parent->tickClock();
}

const char *
MC146818::RTCTickEvent::description() const
{
    return "RTC clock tick";
}
<|endoftext|>


<commit_before>/* This file is part of Zanshin

   Copyright 2014 Kevin Ottens <ervin@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "task.h"

using namespace Domain;

Task::Task(QObject *parent)
    : Artifact(parent)
{
}

Task::~Task()
{
}

bool Task::isDone() const
{
    return (status() == Complete);
}

void Task::setDone(bool done)
{
    if (done) {
        setStatus(Complete);
    } else {
        setStatus(None);
    }
}

QDateTime Task::startDate() const
{
    return m_startDate;
}

void Task::setStartDate(const QDateTime &startDate)
{
    if (m_startDate == startDate)
        return;

    m_startDate = startDate;
    emit startDateChanged(startDate);
}

QDateTime Task::dueDate() const
{
    return m_dueDate;
}

Task::Delegate Task::delegate() const
{
    return m_delegate;
}

void Task::setDueDate(const QDateTime &dueDate)
{
    if (m_dueDate == dueDate)
        return;

    m_dueDate = dueDate;
    emit dueDateChanged(dueDate);
}

void Task::setDelegate(const Task::Delegate &delegate)
{
    if (m_delegate == delegate)
        return;

    m_delegate = delegate;
    emit delegateChanged(delegate);
}

int Task::progress() const
{
    return m_progress;
}

void Task::setProgress(int progress)
{
    if (m_progress == progress)
        return;

    m_progress = progress;
    emit progressChanged(progress);
}

Task::Status Task::status() const
{
    return m_status;
}

void Task::setStatus(int status)
{
    if (m_status == static_cast<Status>(status))
        return;

    m_status = static_cast<Status>(status);
    emit statusChanged(status);
}

Task::Delegate::Delegate()
{
}

Task::Delegate::Delegate(const QString &name, const QString &email)
    : m_name(name), m_email(email)
{
}

Task::Delegate::Delegate(const Task::Delegate &other)
    : m_name(other.m_name), m_email(other.m_email)
{
}

Task::Delegate &Task::Delegate::operator=(const Task::Delegate &other)
{
    Delegate copy(other);
    std::swap(m_name, copy.m_name);
    std::swap(m_email, copy.m_email);
    return *this;
}

bool Task::Delegate::operator==(const Task::Delegate &other) const
{
    return m_name == other.m_name
        && m_email == other.m_email;
}

bool Task::Delegate::isValid() const
{
    return !m_email.isEmpty();
}

QString Task::Delegate::display() const
{
    return !isValid() ? QString()
         : !m_name.isEmpty() ? m_name
         : m_email;
}

QString Task::Delegate::name() const
{
    return m_name;
}

void Task::Delegate::setName(const QString &name)
{
    m_name = name;
}

QString Task::Delegate::email() const
{
    return m_email;
}

void Task::Delegate::setEmail(const QString &email)
{
    m_email = email;
}

<commit_msg>Default values for task status and progress<commit_after>/* This file is part of Zanshin

   Copyright 2014 Kevin Ottens <ervin@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License or (at your option) version 3 or any later version
   accepted by the membership of KDE e.V. (or its successor approved
   by the membership of KDE e.V.), which shall act as a proxy
   defined in Section 14 of version 3 of the license.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
   USA.
*/

#include "task.h"

using namespace Domain;

Task::Task(QObject *parent)
    : Artifact(parent),
    m_progress(0),
    m_status(None)
{
}

Task::~Task()
{
}

bool Task::isDone() const
{
    return (status() == Complete);
}

void Task::setDone(bool done)
{
    if (done) {
        setStatus(Complete);
    } else {
        setStatus(None);
    }
}

QDateTime Task::startDate() const
{
    return m_startDate;
}

void Task::setStartDate(const QDateTime &startDate)
{
    if (m_startDate == startDate)
        return;

    m_startDate = startDate;
    emit startDateChanged(startDate);
}

QDateTime Task::dueDate() const
{
    return m_dueDate;
}

Task::Delegate Task::delegate() const
{
    return m_delegate;
}

void Task::setDueDate(const QDateTime &dueDate)
{
    if (m_dueDate == dueDate)
        return;

    m_dueDate = dueDate;
    emit dueDateChanged(dueDate);
}

void Task::setDelegate(const Task::Delegate &delegate)
{
    if (m_delegate == delegate)
        return;

    m_delegate = delegate;
    emit delegateChanged(delegate);
}

int Task::progress() const
{
    return m_progress;
}

void Task::setProgress(int progress)
{
    if (m_progress == progress)
        return;

    m_progress = progress;
    emit progressChanged(progress);
}

Task::Status Task::status() const
{
    return m_status;
}

void Task::setStatus(int status)
{
    if (m_status == static_cast<Status>(status))
        return;

    m_status = static_cast<Status>(status);
    emit statusChanged(status);
}

Task::Delegate::Delegate()
{
}

Task::Delegate::Delegate(const QString &name, const QString &email)
    : m_name(name), m_email(email)
{
}

Task::Delegate::Delegate(const Task::Delegate &other)
    : m_name(other.m_name), m_email(other.m_email)
{
}

Task::Delegate &Task::Delegate::operator=(const Task::Delegate &other)
{
    Delegate copy(other);
    std::swap(m_name, copy.m_name);
    std::swap(m_email, copy.m_email);
    return *this;
}

bool Task::Delegate::operator==(const Task::Delegate &other) const
{
    return m_name == other.m_name
        && m_email == other.m_email;
}

bool Task::Delegate::isValid() const
{
    return !m_email.isEmpty();
}

QString Task::Delegate::display() const
{
    return !isValid() ? QString()
         : !m_name.isEmpty() ? m_name
         : m_email;
}

QString Task::Delegate::name() const
{
    return m_name;
}

void Task::Delegate::setName(const QString &name)
{
    m_name = name;
}

QString Task::Delegate::email() const
{
    return m_email;
}

void Task::Delegate::setEmail(const QString &email)
{
    m_email = email;
}

<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template <typename T>
class BinaryTree;

template <typename T>
std::ostream& operator<<<T>(std::ostream&, const BinaryTree<T>&);

template <typename T>
struct Node {
	Node *left;
	Node *right;
	T data;
};

template <typename T>
class BinaryTree
{
private:
	Node<T>*root;
	int CountElements = 0;

public:
	BinaryTree();
	~BinaryTree();
	Node<T>* root_();
	unsigned int count() const;
	void insert_node(const T&x);
	Node<T> *find_node(const T&, Node<T>*)const;
	void deleteNode(Node<T>* temp);
	void writing(const std::string& filename)const;
	friend std::ostream& output(std::ostream& ost, const Node<T>* temp);
	friend std::ostream& operator<<<T>(std::ostream&, const BinaryTree<T>&);

};

template <typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
Node<T>* BinaryTree<T>::root_()
{
	return root;
}

template <typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
}

template<typename T>
void BinaryTree<T>::insert_node(const T&x)
{
	if (find_node(x, root_())) return;
	Node<T>* MyTree = new Node<T>;
	MyTree->data = x;
	MyTree->left = MyTree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = MyTree;
	else
	{
		if (x < buff->data)
			buff->left = MyTree;
		else
			buff->right = MyTree;
	}
	++CountElements;
}

template<typename T>
Node<T>* BinaryTree<T>::find_node(const T& value, Node<T>* temp) const
{
	if (temp == 0 || value == temp->data)
		return temp;
	if (value > temp->data)
		return find_node(value, temp->right);
	else
		return find_node(value, temp->left);
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	//if (!temp)
	//{
		//throw "error";
	//}
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template<typename T>
void BinaryTree<T>::writing(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << CountElements << "\t";
	output(file_1, root);
	file_1.close();
}

template <typename T>
std::ostream& output(std::ostream& ost, const Node<T>* node, unsigned int level)
{
	if (!node)
		return ost;
	output(ost, node->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		ost << "\t";
	ost << node->data << std::endl;
	output(ost, node->left, level + 1);
	return ost;
}

template <typename T>
std::ostream& operator<<(std::ostream& ost, const BinaryTree<T>& temp)
{
	//if (!temp.root)
		//throw "error";
	output(ost, temp.root, 0);
	return ost;
}
<commit_msg>Update BinaryTree.hpp<commit_after>#include <iostream>
#include <string>
#include <fstream>
#include <cstdint>

using namespace std;

template <typename T>
class BinaryTree;

template <typename T>
std::ostream& operator<<<>(std::ostream&, const BinaryTree<T>&);

template <typename T>
struct Node {
	Node *left;
	Node *right;
	T data;
};

template <typename T>
class BinaryTree
{
private:
	Node<T>*root;
	int CountElements = 0;

public:
	BinaryTree();
	~BinaryTree();
	Node<T>* root_();
	unsigned int count() const;
	void insert_node(const T&x);
	Node<T> *find_node(const T&, Node<T>*)const;
	void deleteNode(Node<T>* temp);
	void writing(const std::string& filename)const;
	friend std::ostream& output(std::ostream& ost, const Node<T>* temp);
	friend std::ostream& operator<<<>(std::ostream&, const BinaryTree<T>&);

};

template <typename T>
BinaryTree<T>::BinaryTree()
{
	root = nullptr;
}

template<typename T>
Node<T>* BinaryTree<T>::root_()
{
	return root;
}

template <typename T>
BinaryTree<T>::~BinaryTree()
{
	deleteNode(root);
}

template<typename T>
void BinaryTree<T>::insert_node(const T&x)
{
	if (find_node(x, root_())) return;
	Node<T>* MyTree = new Node<T>;
	MyTree->data = x;
	MyTree->left = MyTree->right = 0;
	Node<T>* buff = root;
	Node<T>* temp = root;
	while (temp)
	{
		buff = temp;
		if (x < temp->data)
			temp = temp->left;
		else
			temp = temp->right;
	}
	if (!buff)
		root = MyTree;
	else
	{
		if (x < buff->data)
			buff->left = MyTree;
		else
			buff->right = MyTree;
	}
	++CountElements;
}

template<typename T>
Node<T>* BinaryTree<T>::find_node(const T& value, Node<T>* temp) const
{
	if (temp == 0 || value == temp->data)
		return temp;
	if (value > temp->data)
		return find_node(value, temp->right);
	else
		return find_node(value, temp->left);
}

template<typename T>
void BinaryTree<T>::deleteNode(Node<T>* temp)
{
	//if (!temp)
	//{
		//throw "error";
	//}
	if (temp->left)
	{
		deleteNode(temp->left);
		temp->left = nullptr;
	}

	if (temp->right)
	{
		deleteNode(temp->right);
		temp->right = nullptr;
	}
	delete temp;
}

template<typename T>
void BinaryTree<T>::writing(const std::string& filename)const
{
	ofstream file_1(filename);
	file_1 << CountElements << "\t";
	output(file_1, root);
	file_1.close();
}

template <typename T>
std::ostream& output(std::ostream& ost, const Node<T>* node, unsigned int level)
{
	if (!node)
		return ost;
	output(ost, node->right, level + 1);
	for (unsigned int i = 0; i < level; i++)
		ost << "\t";
	ost << node->data << std::endl;
	output(ost, node->left, level + 1);
	return ost;
}

template <typename T>
std::ostream& operator<<(std::ostream& ost, const BinaryTree<T>& temp)
{
	//if (!temp.root)
		//throw "error";
	output(ost, temp.root, 0);
	return ost;
}
<|endoftext|>


<commit_before>#pragma once

#if defined(__arm__)
#  define __NR_pause 29
#elif defined(__x86_64__)
#  define __NR_pause 34
#else
#  error
#endif
<commit_msg>pause: not needed (yet)<commit_after><|endoftext|>