<commit_before>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
 *
 *
 * Per Larsson a.k.a finalman
 * Olof Naessén a.k.a jansem/yakslem
 *
 * Visit: http://guichan.sourceforge.net
 *
 * License: (BSD)
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name of Guichan 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.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/widgets/tabbedarea.hpp"

#include "guichan/exception.hpp"
#include "guichan/focushandler.hpp"
#include "guichan/font.hpp"
#include "guichan/graphics.hpp"

#include "guichan/widgets/container.hpp"
#include "guichan/widgets/tab.hpp"

#include <algorithm>

namespace gcn
{
    TabbedArea::TabbedArea()
            :mSelectedTab(NULL),
             mOpaque(false)
    {
        setFocusable(true);
        addKeyListener(this);
        addMouseListener(this);

        mTabContainer = new Container();
        mTabContainer->setOpaque(false);
        mWidgetContainer = new Container();

        add(mTabContainer);
        add(mWidgetContainer);
    }

    TabbedArea::~TabbedArea()
    {
        remove(mTabContainer);
        remove(mWidgetContainer);

        delete mTabContainer;
        delete mWidgetContainer;

        for (unsigned int i = 0; i < mTabsToDelete.size(); i++)
        {
            delete mTabsToDelete[i];
        }
    }

    void TabbedArea::addTab(const std::string& caption, Widget* widget)
    {
        Tab* tab = new Tab();
        tab->setCaption(caption);
        mTabsToDelete.push_back(tab);

        addTab(tab, widget);
    }

    void TabbedArea::addTab(Tab* tab, Widget* widget)
    {
        tab->setTabbedArea(this);
        tab->addActionListener(this);

/**/    //tab->addMouseListener(mTabContainer);
        mTabContainer->add(tab);
        mTabs.push_back(std::pair<Tab*, Widget*>(tab, widget));

        if (mSelectedTab == NULL)
        {
            setSelectedTab(tab);
        }

        adjustTabPositions();
        adjustSize();
    }

    void TabbedArea::removeTabWithIndex(unsigned int index)
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        removeTab(mTabs[index].first);
    }

    void TabbedArea::removeTab(Tab* tab)
    {
        int tabIndexToBeSelected = - 1;

        if (tab == mSelectedTab)
        {
            int index = getSelectedTabIndex();

            if (index == (int)mTabs.size() - 1
                && mTabs.size() >= 2)
            {
                tabIndexToBeSelected = index--;
            }
            else if (index == (int)mTabs.size() - 1
                     && mTabs.size() == 1)
            {
                tabIndexToBeSelected = -1;
            }
            else
            {
                tabIndexToBeSelected = index;
            }
        }

        std::vector<std::pair<Tab*, Widget*> >::iterator iter;
        for (iter = mTabs.begin(); iter != mTabs.end(); iter++)
        {
            if (iter->first == tab)
            {
                mTabContainer->remove(tab);
                mTabs.erase(iter);
                break;
            }
        }

        std::vector<Tab*>::iterator iter2;
        for (iter2 = mTabsToDelete.begin(); iter2 != mTabsToDelete.end(); iter2++)
        {
            if (*iter2 == tab)
            {
                mTabsToDelete.erase(iter2);
                delete tab;
                break;
            }
        }

        if (tabIndexToBeSelected == -1)
        {
            mSelectedTab = NULL;
            mWidgetContainer->clear();
        }
        else
        {
            setSelectedTab(tabIndexToBeSelected);
        }

        adjustSize();
        adjustTabPositions();
    }

    int TabbedArea::getNumberOfTabs() const
    {
        return mTabs.size();
    }

    bool TabbedArea::isTabSelected(unsigned int index) const
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        return mSelectedTab == mTabs[index].first;
    }

    bool TabbedArea::isTabSelected(Tab* tab) const
    {
        return mSelectedTab == tab;
    }

    void TabbedArea::setSelectedTab(unsigned int index)
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        setSelectedTab(mTabs[index].first);
    }

    void TabbedArea::setSelectedTab(Tab* tab)
    {
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == mSelectedTab)
            {
                mWidgetContainer->remove(mTabs[i].second);
            }
        }

        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == tab)
            {
                mSelectedTab = tab;
                mWidgetContainer->add(mTabs[i].second);
            }
        }
    }

    int TabbedArea::getSelectedTabIndex() const
    {
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == mSelectedTab)
            {
                return i;
            }
        }

        return -1;
    }

    Tab* TabbedArea::getSelectedTab() const
    {
        return mSelectedTab;
    }

    bool TabbedArea::isTabActive() const
    {
        return tabActive;
    }

    void TabbedArea::setOpaque(bool opaque)
    {
        mOpaque = opaque;
    }

    bool TabbedArea::isOpaque() const
    {
        return mOpaque;
    }

    void TabbedArea::draw (Graphics *graphics)
    {
        const Color &faceColor = getBaseColor();
        const int alpha = getBaseColor().a;
        Color highlightColor = faceColor + 0x303030;
        highlightColor.a = alpha;
        Color shadowColor = faceColor - 0x303030;
        shadowColor.a = alpha;

        // Draw a border.
        graphics->setColor(highlightColor);
        graphics->drawLine(0,
                           mTabContainer->getHeight(),
                           0,
                           getHeight() - 2);
        graphics->setColor(shadowColor);
        graphics->drawLine(getWidth() - 1,
                           mTabContainer->getHeight() + 1,
                           getWidth() - 1,
                           getHeight() - 1);
        graphics->drawLine(1,
                           getHeight() - 1,
                           getWidth() - 1,
                           getHeight() - 1);

        if (isOpaque())
        {
            graphics->setColor(getBaseColor());
            graphics->fillRectangle(1, 1,
                                    getWidth() - 2,
                                    getHeight() - 2);
        }

        // Draw a line underneath the tabs.
        graphics->setColor(highlightColor);
        graphics->drawLine(1,
                           mTabContainer->getHeight(),
                           getWidth() - 1,
                           mTabContainer->getHeight());

        // If a tab is selected, remove the line right underneath
        // the selected tab.
        if (mSelectedTab != NULL)
        {
            graphics->setColor (getBaseColor());
            graphics->drawLine (mSelectedTab->getX() + 1,
                                mTabContainer->getHeight(),
                                mSelectedTab->getX() + mSelectedTab->getWidth() - 2,
                                mTabContainer->getHeight());
        }

        // Draw the widget from a select tab.
        std::vector<std::pair<Tab*, Widget*>>::iterator iter;
        for (iter = mTabs.begin(); iter != mTabs.end(); iter++)
        {
            iter->first->_draw(graphics);
            if (iter->first == mSelectedTab)
            {
                iter->second->_draw(graphics);
            }
        }
    }

    void TabbedArea::adjustSize()
    {
        int maxTabHeight = 0;

        for (unsigned int i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first->getHeight() > maxTabHeight)
            {
                maxTabHeight = mTabs[i].first->getHeight();
            }
        }

        mTabContainer->setSize(getWidth() - 2,
                               maxTabHeight);

        mWidgetContainer->setPosition(1, maxTabHeight + 1);
        mWidgetContainer->setSize(getWidth() - 2,
                                  getHeight() - maxTabHeight - 2);
    }

    void TabbedArea::adjustTabPositions()
    {
        int maxTabHeight = 0;
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first->getHeight() > maxTabHeight)
            {
                maxTabHeight = mTabs[i].first->getHeight();
            }
        }

        int x = 0;
        for (i = 0; i < mTabs.size(); i++)
        {
            Tab* tab = mTabs[i].first;
            tab->setPosition(x, maxTabHeight - tab->getHeight());
            x += tab->getWidth();

            Widget* widget = mTabs[i].second;
            widget->setX(mWidgetContainer->getX());
            widget->setY(mWidgetContainer->getY());
        }
    }

    void TabbedArea::setWidth(int width)
    {
        // This may seem odd, but we want the TabbedArea to adjust
        // it's size properly before we call Widget::setWidth as
        // Widget::setWidth might distribute a resize event.
        gcn::Rectangle dim = mDimension;
        mDimension.width = width;
        adjustSize();
        mDimension = dim;
        Widget::setWidth(width);
    }

    void TabbedArea::setHeight(int height)
    {
        // This may seem odd, but we want the TabbedArea to adjust
        // it's size properly before we call Widget::setHeight as
        // Widget::setHeight might distribute a resize event.
        gcn::Rectangle dim = mDimension;
        mDimension.height = height;
        adjustSize();
        mDimension = dim;
        Widget::setHeight(height);
    }

    void TabbedArea::setSize(int width, int height)
    {
        // This may seem odd, but we want the TabbedArea to adjust
        // it's size properly before we call Widget::setSize as
        // Widget::setSize might distribute a resize event.
        gcn::Rectangle dim = mDimension;
        mDimension.width = width;
        mDimension.height = height;
        adjustSize();
        mDimension = dim;
        Widget::setSize(width, height);
    }

    void TabbedArea::setDimension(const Rectangle& dimension)
    {
        // This may seem odd, but we want the TabbedArea to adjust
        // it's size properly before we call Widget::setDimension as
        // Widget::setDimension might distribute a resize event.
        gcn::Rectangle dim = mDimension;
        mDimension = dimension;
        adjustSize();
        mDimension = dim;
        Widget::setDimension(dimension);
    }

    void TabbedArea::keyPressed(KeyEvent& keyEvent)
    {
        if (keyEvent.isConsumed() || !isFocused())
        {
            return;
        }

        if (keyEvent.getKey().getValue() == Key::Left)
        {
            int index = getSelectedTabIndex();
            index--;

            if (index < 0)
            {
                return;
            }
            else
            {
                setSelectedTab(mTabs[index].first);
            }

            keyEvent.consume();
        }
        else if (keyEvent.getKey().getValue() == Key::Right)
        {
            int index = getSelectedTabIndex();
            index++;

            if (index >= (int)mTabs.size())
            {
                return;
            }
            else
            {
                setSelectedTab(mTabs[index].first);
            }

            keyEvent.consume();
        }
    }

    void TabbedArea::mousePressed(MouseEvent& mouseEvent)
    {
        if (mouseEvent.isConsumed())
        {
            return;
        }

        if (mouseEvent.getButton() == MouseEvent::Left)
        {
            Widget* widget = mTabContainer->getWidgetAt(mouseEvent.getX(), mouseEvent.getY());
            Tab* tab = dynamic_cast<Tab*>(widget);

            if (tab != NULL)
            {
                setSelectedTab (tab);
                tabActive = true;
                mouseEvent.consume ();
            }
            else
            {
                widget = mWidgetContainer->getWidgetAt(mouseEvent.getX(), mouseEvent.getY());
                if (widget == NULL)
                {
                    mouseEvent.consume();
                }
                tabActive = false;
            }
        }

        // Request focus only if the source of the event
        // is not focusable. If the source of the event
        // is focused we don't want to steal the focus.
        if (!mouseEvent.getSource()->isFocusable())
        {
            requestFocus();
        }
    }

    void TabbedArea::death(const Event& event)
    {
        Tab* tab = dynamic_cast<Tab*>(event.getSource());

        if (tab != NULL)
        {
            removeTab(tab);
        }
        else
        {
            //BasicContainer::death(event);
        }
    }

    void TabbedArea::action(const ActionEvent& actionEvent)
    {
        Widget* source = actionEvent.getSource();
        Tab* tab = dynamic_cast<Tab*>(source);

        if (tab == NULL)
        {
            throw GCN_EXCEPTION("Received an action from a widget that's not a tab!");
        }

        setSelectedTab(tab);
    }

    void TabbedArea::setBaseColor(const Color& color)
    {
        Widget::setBaseColor(color);
        mWidgetContainer->setBaseColor(color);
        mTabContainer->setBaseColor(color);
    }
}
<commit_msg>Fixed compiler error on clang<commit_after>/*      _______   __   __   __   ______   __   __   _______   __   __
 *     / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___  /\ /  |\/ /\
 *    / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / /
 *   / / /__   / / // / // / // / /    / ___  / // ___  / // /| ' / /
 *  / /_// /\ / /_// / // / // /_/_   / / // / // /\_/ / // / |  / /
 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ /
 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/
 *
 * Copyright (c) 2004 - 2008 Olof Naessén and Per Larsson
 *
 *
 * Per Larsson a.k.a finalman
 * Olof Naessén a.k.a jansem/yakslem
 *
 * Visit: http://guichan.sourceforge.net
 *
 * License: (BSD)
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. 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.
 * 3. Neither the name of Guichan 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.
 */

/*
 * For comments regarding functions please see the header file.
 */

#include "guichan/widgets/tabbedarea.hpp"

#include "guichan/exception.hpp"
#include "guichan/focushandler.hpp"
#include "guichan/font.hpp"
#include "guichan/graphics.hpp"

#include "guichan/widgets/container.hpp"
#include "guichan/widgets/tab.hpp"

#include <algorithm>

namespace gcn
{
    TabbedArea::TabbedArea()
            :mSelectedTab(NULL),
             mOpaque(false)
    {
        setFocusable(true);
        addKeyListener(this);
        addMouseListener(this);

        mTabContainer = new Container();
        mTabContainer->setOpaque(false);
        mWidgetContainer = new Container();

        add(mTabContainer);
        add(mWidgetContainer);
    }

    TabbedArea::~TabbedArea()
    {
        remove(mTabContainer);
        remove(mWidgetContainer);

        delete mTabContainer;
        delete mWidgetContainer;

        for (unsigned int i = 0; i < mTabsToDelete.size(); i++)
        {
            delete mTabsToDelete[i];
        }
    }

    void TabbedArea::addTab(const std::string& caption, Widget* widget)
    {
        Tab* tab = new Tab();
        tab->setCaption(caption);
        mTabsToDelete.push_back(tab);

        addTab(tab, widget);
    }

    void TabbedArea::addTab(Tab* tab, Widget* widget)
    {
        tab->setTabbedArea(this);
        tab->addActionListener(this);

/**/    //tab->addMouseListener(mTabContainer);
        mTabContainer->add(tab);
        mTabs.push_back(std::pair<Tab*, Widget*>(tab, widget));

        if (mSelectedTab == NULL)
        {
            setSelectedTab(tab);
        }

        adjustTabPositions();
        adjustSize();
    }

    void TabbedArea::removeTabWithIndex(unsigned int index)
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        removeTab(mTabs[index].first);
    }

    void TabbedArea::removeTab(Tab* tab)
    {
        int tabIndexToBeSelected = - 1;

        if (tab == mSelectedTab)
        {
            int index = getSelectedTabIndex();

            if (index == (int)mTabs.size() - 1
                && mTabs.size() >= 2)
            {
                tabIndexToBeSelected = index--;
            }
            else if (index == (int)mTabs.size() - 1
                     && mTabs.size() == 1)
            {
                tabIndexToBeSelected = -1;
            }
            else
            {
                tabIndexToBeSelected = index;
            }
        }

        std::vector<std::pair<Tab*, Widget*> >::iterator iter;
        for (iter = mTabs.begin(); iter != mTabs.end(); iter++)
        {
            if (iter->first == tab)
            {
                mTabContainer->remove(tab);
                mTabs.erase(iter);
                break;
            }
        }

        std::vector<Tab*>::iterator iter2;
        for (iter2 = mTabsToDelete.begin(); iter2 != mTabsToDelete.end(); iter2++)
        {
            if (*iter2 == tab)
            {
                mTabsToDelete.erase(iter2);
                delete tab;
                break;
            }
        }

        if (tabIndexToBeSelected == -1)
        {
            mSelectedTab = NULL;
            mWidgetContainer->clear();
        }
        else
        {
            setSelectedTab(tabIndexToBeSelected);
        }

        adjustSize();
        adjustTabPositions();
    }

    int TabbedArea::getNumberOfTabs() const
    {
        return mTabs.size();
    }

    bool TabbedArea::isTabSelected(unsigned int index) const
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        return mSelectedTab == mTabs[index].first;
    }

    bool TabbedArea::isTabSelected(Tab* tab) const
    {
        return mSelectedTab == tab;
    }

    void TabbedArea::setSelectedTab(unsigned int index)
    {
        if (index >= mTabs.size())
        {
            throw GCN_EXCEPTION("No such tab index.");
        }

        setSelectedTab(mTabs[index].first);
    }

    void TabbedArea::setSelectedTab(Tab* tab)
    {
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == mSelectedTab)
            {
                mWidgetContainer->remove(mTabs[i].second);
            }
        }

        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == tab)
            {
                mSelectedTab = tab;
                mWidgetContainer->add(mTabs[i].second);
            }
        }
    }

    int TabbedArea::getSelectedTabIndex() const
    {
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first == mSelectedTab)
            {
                return i;
            }
        }

        return -1;
    }

    Tab* TabbedArea::getSelectedTab() const
    {
        return mSelectedTab;
    }

    bool TabbedArea::isTabActive() const
    {
        return tabActive;
    }

    void TabbedArea::setOpaque(bool opaque)
    {
        mOpaque = opaque;
    }

    bool TabbedArea::isOpaque() const
    {
        return mOpaque;
    }

    void TabbedArea::draw (Graphics *graphics)
    {
        const Color &faceColor = getBaseColor();
        const int alpha = getBaseColor().a;
        Color highlightColor = faceColor + 0x303030;
        highlightColor.a = alpha;
        Color shadowColor = faceColor - 0x303030;
        shadowColor.a = alpha;

        // Draw a border.
        graphics->setColor(highlightColor);
        graphics->drawLine(0,
                           mTabContainer->getHeight(),
                           0,
                           getHeight() - 2);
        graphics->setColor(shadowColor);
        graphics->drawLine(getWidth() - 1,
                           mTabContainer->getHeight() + 1,
                           getWidth() - 1,
                           getHeight() - 1);
        graphics->drawLine(1,
                           getHeight() - 1,
                           getWidth() - 1,
                           getHeight() - 1);

        if (isOpaque())
        {
            graphics->setColor(getBaseColor());
            graphics->fillRectangle(1, 1,
                                    getWidth() - 2,
                                    getHeight() - 2);
        }

        // Draw a line underneath the tabs.
        graphics->setColor(highlightColor);
        graphics->drawLine(1,
                           mTabContainer->getHeight(),
                           getWidth() - 1,
                           mTabContainer->getHeight());

        // If a tab is selected, remove the line right underneath
        // the selected tab.
        if (mSelectedTab != NULL)
        {
            graphics->setColor (getBaseColor());
            graphics->drawLine (mSelectedTab->getX() + 1,
                                mTabContainer->getHeight(),
                                mSelectedTab->getX() + mSelectedTab->getWidth() - 2,
                                mTabContainer->getHeight());
        }

        // Draw the widget from a select tab.
        std::vector<std::pair<Tab*, Widget*> >::iterator iter;
        for (iter = mTabs.begin(); iter != mTabs.end(); iter++)
        {
            iter->first->_draw(graphics);
            if (iter->first == mSelectedTab)
            {
                iter->second->_draw(graphics);
            }
        }
    }

    void TabbedArea::adjustSize()
    {
        int maxTabHeight = 0;

        for (unsigned int i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first->getHeight() > maxTabHeight)
            {
                maxTabHeight = mTabs[i].first->getHeight();
            }
        }

        mTabContainer->setSize(getWidth() - 2,
                               maxTabHeight);

        mWidgetContainer->setPosition(1, maxTabHeight + 1);
        mWidgetContainer->setSize(getWidth() - 2,
                                  getHeight() - maxTabHeight - 2);
    }

    void TabbedArea::adjustTabPositions()
    {
        int maxTabHeight = 0;
        unsigned int i;
        for (i = 0; i < mTabs.size(); i++)
        {
            if (mTabs[i].first->getHeight() > maxTabHeight)
            {
                maxTabHeight = mTabs[i].first->getHeight();
            }
        }

        int x = 0;
        for (i = 0; i < mTabs.size(); i++)
        {
            Tab* tab = mTabs[i].first;
            tab->setPosition(x, maxTabHeight - tab->getHeight());
            x += tab->getWidth();

            Widget* widget = mTabs[i].second;
            widget->setX(mWidgetContainer->getX());
            widget->setY(mWidgetContainer->getY());
        }
    }

    void TabbedArea::setWidth(int width)
    {
        // This may seem odd, but we want the TabbedArea to adjust
        // it's size properly before we call Widget::setWidth as
        // Widget::setWidth might distribute a resize event.
        gcn::Rectangle dim = mDimension;
        mDimension.width = width;
        adjustSize();
        mDimension = dim;
        Widget::setWidth(width);
    }

    void TabbedArea::setHeight(int height)
    {
        // This may seem odd, but we want the TabbedArea to adjust
        // it's size properly before we call Widget::setHeight as
        // Widget::setHeight might distribute a resize event.
        gcn::Rectangle dim = mDimension;
        mDimension.height = height;
        adjustSize();
        mDimension = dim;
        Widget::setHeight(height);
    }

    void TabbedArea::setSize(int width, int height)
    {
        // This may seem odd, but we want the TabbedArea to adjust
        // it's size properly before we call Widget::setSize as
        // Widget::setSize might distribute a resize event.
        gcn::Rectangle dim = mDimension;
        mDimension.width = width;
        mDimension.height = height;
        adjustSize();
        mDimension = dim;
        Widget::setSize(width, height);
    }

    void TabbedArea::setDimension(const Rectangle& dimension)
    {
        // This may seem odd, but we want the TabbedArea to adjust
        // it's size properly before we call Widget::setDimension as
        // Widget::setDimension might distribute a resize event.
        gcn::Rectangle dim = mDimension;
        mDimension = dimension;
        adjustSize();
        mDimension = dim;
        Widget::setDimension(dimension);
    }

    void TabbedArea::keyPressed(KeyEvent& keyEvent)
    {
        if (keyEvent.isConsumed() || !isFocused())
        {
            return;
        }

        if (keyEvent.getKey().getValue() == Key::Left)
        {
            int index = getSelectedTabIndex();
            index--;

            if (index < 0)
            {
                return;
            }
            else
            {
                setSelectedTab(mTabs[index].first);
            }

            keyEvent.consume();
        }
        else if (keyEvent.getKey().getValue() == Key::Right)
        {
            int index = getSelectedTabIndex();
            index++;

            if (index >= (int)mTabs.size())
            {
                return;
            }
            else
            {
                setSelectedTab(mTabs[index].first);
            }

            keyEvent.consume();
        }
    }

    void TabbedArea::mousePressed(MouseEvent& mouseEvent)
    {
        if (mouseEvent.isConsumed())
        {
            return;
        }

        if (mouseEvent.getButton() == MouseEvent::Left)
        {
            Widget* widget = mTabContainer->getWidgetAt(mouseEvent.getX(), mouseEvent.getY());
            Tab* tab = dynamic_cast<Tab*>(widget);

            if (tab != NULL)
            {
                setSelectedTab (tab);
                tabActive = true;
                mouseEvent.consume ();
            }
            else
            {
                widget = mWidgetContainer->getWidgetAt(mouseEvent.getX(), mouseEvent.getY());
                if (widget == NULL)
                {
                    mouseEvent.consume();
                }
                tabActive = false;
            }
        }

        // Request focus only if the source of the event
        // is not focusable. If the source of the event
        // is focused we don't want to steal the focus.
        if (!mouseEvent.getSource()->isFocusable())
        {
            requestFocus();
        }
    }

    void TabbedArea::death(const Event& event)
    {
        Tab* tab = dynamic_cast<Tab*>(event.getSource());

        if (tab != NULL)
        {
            removeTab(tab);
        }
        else
        {
            //BasicContainer::death(event);
        }
    }

    void TabbedArea::action(const ActionEvent& actionEvent)
    {
        Widget* source = actionEvent.getSource();
        Tab* tab = dynamic_cast<Tab*>(source);

        if (tab == NULL)
        {
            throw GCN_EXCEPTION("Received an action from a widget that's not a tab!");
        }

        setSelectedTab(tab);
    }

    void TabbedArea::setBaseColor(const Color& color)
    {
        Widget::setBaseColor(color);
        mWidgetContainer->setBaseColor(color);
        mTabContainer->setBaseColor(color);
    }
}
<|endoftext|>


<commit_before>#pragma once
#include <memory>

#include "TimingTags.hpp"
#include "timing_graph_fwd.hpp"

/** \file
 * Timing Analysis: Overview
 * ===========================
 * Timing analysis involves determining at what point in time (relative to some reference,
 * usually a clock) signals arrive at every point in a circuit. This is used to verify
 * that none of these signals will violate any constraints, ensuring the circuit will operate
 * correctly and reliably.
 *
 * The circuit is typically modelled as a directed graph (called a timing graph) where nodes
 * represent the 'pins' of elements in the circuit and edges the connectivity between them.
 * Delays through the circuit (e.g. along wires, or through combinational logic) are associated
 * with the edges.
 *
 * We are generally interested in whether signals arrive late (causing a setup
 * constraint violation) or arrive to early (causing a hold violation).  Typically long/slow
 * paths cause setup violations, and short/fast paths hold violations.  Violating a setup or
 * hold constraint can cause meta-stability in Flip-Flops putting the circuit into an
 * undetermined state for an indeterminate period of time (this is not good).
 *
 * To perform a completely accurate, non-pessemistic timing analysis would involve determining
 * exactly which set of state/inputs to the circuit trigger the worst case path. This requires
 * a dynamic analysis of the circuits behaviour and is prohibitively expensive to compute in
 * practice.
 *
 *
 * Static Timing Analysis (STA)
 * ------------------------------
 * Static Timing Analysis (STA), which this library implements, simplifies the problem somewhat
 * by ignoring the dynamic behaviour the circuit. That is, we assume all paths could be sensitized,
 * even if in practice they may be extremely rare or impossible to sensitize in practice. This
 * makes the result of our analysis pessemistic, but also makes the problem tractable.
 *
 * There are two approaches to performing STA: 'path-based' and 'block-based'.
 *
 * Under Path-Based Analysis (PBA) all paths in the circuit are analyzed. This provides
 * a more accurate (less-pessimistic) analysis than block-based approaches but can require
 * an exponential amount of time. In particular, circuit structures with re-convergent fanout
 * can exponentiallly increase the number of paths through the circuit which must be evaluated.
 *
 * To avoid this unpleasent behaviour, we implement 'block-based' STA. Under this formulation,
 * only the worst case values are kept at each node in the circuit. While this is more
 * pessimistic (any path passing through a node is now viewed as having the worst case delay
 * of any path through that node), it greatly reduces the computational complexity, allowing
 * STA to be perfomed in linear time.
 *
 * Arrival Time, Required Time & Slack
 * ---------------------------------------
 * When a Timing Analyzer performs timing analysis it is primarily calculating the following:
 *
 *    - Arrival Time: The time a signal actually arrived at a particular point in the circuit.
 *
 *    - Required Time: The time a signal should have arrived (was required) at a particular
 *                     to avoid violating a timing constraint.
 *
 *    - Slack: The difference between required and arrival times. This indicates how close
 *             a particular path/node is to violating its timing constraint.  A positive
 *             value indicates there is no violation, a negative value indicates there is
 *             a violation. The magnitude of the slack indicates by how much the constraint
 *             is passing/failing.  A value of zero indicates that the constraint is met
 *             exactly.
 *             TODO: Implement slack calculator
 *
 *
 * Calculating Arrival & Required Times
 * --------------------------------------
 * It is also useful to define the following collections of timing graph nodes:
 *    - Primary Inputs (PIs): circuit external input pins, Flip-Flop Q pins
 *    - Primary Outputs (POs): circuit external output pins, Flip-Flop D pins
 * Note that in the timing graph PIs have no fan-in, and POs have no fan-out.
 *
 * The arrival and required times are calculated at every node in the timing graph by walking
 * the timing graph in either a 'forward' or 'backward' direction. The following provide a
 * high-level description of the process.
 *
 * On the initial (forward) traversal, the graph is walked from PIs to POs to calculate arrival
 * time, performing the following:
 *      1) Initialize the arrival time of all PIs based on constraints (typically zero in the
 *         simplest case)
 *      2) Add the delay of each edge to the arrival time of the edge's driving node to
 *         to calculate the edge arrival time.
 *      3) At each downstream node calculate the max (setup) or min (hold) of all input
 *         edge arrival times, and store it as the node arrival time.
 *      4) Repeat (2)-(3) until all nodes have valid arrival times.
 *
 * On the second (backward) traversal, the graph is walked in reverse from POs to PIs, performing
 * the following:
 *      1) Initialize the required times of all POs based on constraints (typically target
 *         clock period for setup analysis)
 *      2) Subtract the delay of each edge to the required time of the edge's sink node to
 *         to calculate the edge required time.
 *      3) At each upstream node calculate the min (setup) or max (hold) of all input
 *         edge required times, and store it as the node required time.
 *      4) Repeat (2)-(3) until all nodes have valid required times.
 *
 * Clock Skew
 * ------------
 * In a real system the clocks which launch signals at the PIs and capture them at POs may not
 * all arrive at the same instance in time.  This difference is known as 'skew'.
 *
 * Skew can be modled by adjusting the initialized PI arrival times to reflect when the clock
 * signal actually reaches the node.  Similarily the PO required times can also be adjusted.
 *
 * Multi-clock Analysis
 * ----------------------
 * The previous discussion has focused primarily on single-clock STA. In a multi-clock analysis
 * transfers between clock domains need to be handled (e.g. if the launch and capture clocks are
 * different). This is typically handled by identifying the worst-case alignment between all pairs
 * of clocks. This worst case value then becomes the constraint between the two clocks.
 *
 * To perform a multi-clock analysis the paths between different clocks need to be considered with
 * the identified constraint applied.  This can be handled in two ways either:
 *      a) Performing multiple single-clock analysis passes (one for each pair of clocks), or
 *      b) Perform a single analysis but track multiple arrival/required times (a unique one for
 *         each clock).
 *
 * Approach (b) turns out to be more efficient in practice, since it only requires a single traversal
 * of the timing graph. The combined values {clock, arrival time, required time} (and potentially other
 * info) are typically combined into a single 'Tag'.  As a result there may be multiple tags stored
 * at each node in the timing graph.
 */

 /* XXX TODO: these features haven't yet been implemented!
 * ======================================================
 *
 * Derating & Pesimism Reduction Techniques
 * ------------------------------------------
 *
 * Unlike the previous discussion (which assumed constant delay values), in reality circuit delays
 * varry based on a variety of different parameters.  To generate a correct (i.e. pessimistic and not
 * optimistic) analysis this means we must often choose a highly pessemistic value for this single
 * delay. In order to recovering some of this pessimism requires modeling more details of the system.
 *
 * Slew & Rise/Fall
 * ------------------
 * Two of the key parameters that the single delay model does not account for are the impact of:
 *     - Signals 'slew rate' (e.g. signal transition time from low to high), which can effect
 *       the delay through a logic gate
 *     - Signal direction (i.e. is a logic gate's output rising or falling). In CMOS
 *       technologies different transitors of different types are activated depending on the
 *       direction of the output signal (e.g. NMOS pull-down vs PMOS pull-up)
 *
 * Derating
 * ----------
 * Another challenge in modern CMOS technologies is the presence of On-Chip Variation (OCV),
 * identically design structures (e.g. transistors, wires) may have different performance
 * due to manufacturing variation. To capture this behaviour one approach is to apply a
 * derate to delays on different paths in the circuit.
 *
 * In the typical approach applies incrementally more advanced derating, focusing firstly
 * on the most significant sources of variation. A typical progressing is to apply derating to:
 *      1) Clock Path
 *          Since clocks often span large portions of the chip they can be subject to large
 *          variation. To ensure a pessemistic analysis an late (early) derate is applied to
 *          clock launch paths, and a early (launch) derate to clock capture paths for a setup
 *          (hold) analysis.
 *
 *      2) Data Path
 *          Early (late) derates can also be applied to data paths to account for their variation
 *          during setup (hold) analysis.
 *          Note that data paths tend to be more localized to clock networks so the impact of
 *          OCV tends to be smaller.
 *
 * The simplest form of derating is a fixed derate applied to every delay, this can be extended
 * to different delays for different types of circuit elements (wires vs cells, individual cells
 * etc.).
 *
 * It turns out that fixed derates are overly pessemistic, since it is unlikely (particularliy on
 * long paths) that random variation will always go in one direction.  Improved forms of derating
 * take into account the length (depth) of a path, often using a (user specified) table of derates
 * which falls off (derates less) along deeper paths.  It is also possible for the derate to take
 * into account the physical locality/spread of a path.
 *
 * Common Clock Pessimism Removal (CCPR)
 * ---------------------------------------
 * Note: Names for this vary, including: Clock Reconvergence Pessimism Removal (CRPR),
 *       Common Path Pessimism Removal (CPPR), and likely others.
 *
 * Derating can also introduce pessimism when applied to clock networks if the launch and
 * capture paths share some common portion of the clock network. Specifically, using
 * early/late derates on the launch/capture paths of a clock network may model a scenario
 * which is physically impossible to occur:  the shared portion of the clock path cannot
 * be both early and late at the same time.
 *
 * CCPR does not directly remove this effect, but instead calculates a 'credit' which is
 * added back to the final path to counter-act this extra pessimism.
 */

 /*
  * IMPLEMENTATION NOTES
  * --------------------
  *
  * All the timing analyzers defined here are pure abstract classes.
  * They should all have pure virtual functions and store NO data members.
  *
  * We use multiple (virtual) inheritance to define the SetupHoldTimingAnalyzer
  * class, allowing it to be cleanly substituted for any SetupTimingAnalyzer
  * or HoldTimingAnalyzer.
  *
  * Note also that we are using the NVF (Non-Virtual Interface) pattern, so
  * any public member functions should delegate their work to an appropriate
  * protected virtual member function.
  */

/**
 * TimingAnalyzer represents an abstract interface for all timing analyzers,
 * which can be:
 *   - updated (update_timing())
 *   - reset (reset_timing()).
 *
 * This is the most abstract interface provided (it does not allow access
 * to any calculated data).  As a result this interface is suitable for
 * code that needs to update timing analysis, but does not _require_ the
 * analysis results itself.
 *
 * If you need the analysis results you should be using one of the dervied
 * classes (e.g. SetupTimingAnalyzer).
 */
class TimingAnalyzer {
    public:
        virtual ~TimingAnalyzer() {};

        ///Perform timing analysis to update timing information (i.e. arrival & required times)
        void update_timing() { update_timing_impl(); }

        ///Clear any old timing values updated
        void reset_timing() { reset_timing_impl(); }

        double get_profiling_data(std::string key) { return get_profiling_data_impl(key); }

    protected:
        virtual void update_timing_impl() = 0;

        virtual void reset_timing_impl() = 0;

        virtual double get_profiling_data_impl(std::string key) = 0;
};

/**
 * SetupTimingAnalyzer represents an abstract interface for all timing analyzers
 * performing setup (i.e. long-path) analysis.
 */
class SetupTimingAnalyzer : public virtual TimingAnalyzer {
    public:
        const TimingTags& get_setup_data_tags(NodeId node_id) const { return get_setup_data_tags_impl(node_id); }
        const TimingTags& get_setup_clock_tags(NodeId node_id) const { return get_setup_clock_tags_impl(node_id); }

    protected:
        virtual const TimingTags& get_setup_data_tags_impl(NodeId node_id) const = 0;
        virtual const TimingTags& get_setup_clock_tags_impl(NodeId node_id) const = 0;

};

/**
 * HoldTimingAnalyzer represents an abstract interface for all timing analyzers
 * performing hold (i.e. short-path) analysis.
 */
class HoldTimingAnalyzer : public virtual TimingAnalyzer {
    public:
        const TimingTags& get_hold_data_tags(NodeId node_id) const { return get_hold_data_tags_impl(node_id); }
        const TimingTags& get_hold_clock_tags(NodeId node_id) const { return get_hold_clock_tags_impl(node_id); }

    protected:
        virtual const TimingTags& get_hold_data_tags_impl(NodeId node_id) const = 0;
        virtual const TimingTags& get_hold_clock_tags_impl(NodeId node_id) const = 0;
};

/**
 * SetupHoldTimingAnalyzer represents an abstract interface for all timing analyzers
 * performing combined setup and hold (i.e. simultaneous long and short-path) analysis.
 *
 * A combined analysis tends to be more efficient than performing two seperate analysies
 * (provided both setup and hold data are truly required).
 *
 * It implements both the SetupTimingAnalyzer and HoldTimingAnalyzer interfaces.
 */
class SetupHoldTimingAnalyzer : public SetupTimingAnalyzer, public HoldTimingAnalyzer {
    //Empty (all behaviour inherited)
    //
    // Note that we use virtual inheritance to avoid duplicating the common base class
};

<commit_msg>Clarify comments<commit_after>#pragma once
#include <memory>

#include "TimingTags.hpp"
#include "timing_graph_fwd.hpp"

/** \file
 * Timing Analysis: Overview
 * ===========================
 * Timing analysis involves determining at what point in time (relative to some reference,
 * usually a clock) signals arrive at every point in a circuit. This is used to verify
 * that none of these signals will violate any constraints, ensuring the circuit will operate
 * correctly and reliably.
 *
 * The circuit is typically modelled as a directed graph (called a timing graph) where nodes
 * represent the 'pins' of elements in the circuit and edges the connectivity between them.
 * Delays through the circuit (e.g. along wires, or through combinational logic) are associated
 * with the edges.
 *
 * We are generally interested in whether signals arrive late (causing a setup
 * constraint violation) or arrive to early (causing a hold violation).  Typically long/slow
 * paths cause setup violations, and short/fast paths hold violations.  Violating a setup or
 * hold constraint can cause meta-stability in Flip-Flops putting the circuit into an
 * undetermined state for an indeterminate period of time (this is not good).
 *
 * To perform a completely accurate, non-pessemistic timing analysis would involve determining
 * exactly which set of state/inputs to the circuit trigger the worst case path. This requires
 * a dynamic analysis of the circuits behaviour and is prohibitively expensive to compute in
 * practice.
 *
 *
 * Static Timing Analysis (STA)
 * ------------------------------
 * Static Timing Analysis (STA), which this library implements, simplifies the problem somewhat
 * by ignoring the dynamic behaviour the circuit. That is, we assume all paths could be sensitized,
 * even if in practice they may be extremely rare or impossible to sensitize in practice. This
 * makes the result of our analysis pessemistic, but also makes the problem tractable.
 *
 * There are two approaches to performing STA: 'path-based' and 'block-based'.
 *
 * Under Path-Based Analysis (PBA) all paths in the circuit are analyzed. This provides
 * a more accurate (less-pessimistic) analysis than block-based approaches but can require
 * an exponential amount of time. In particular, circuit structures with re-convergent fanout
 * can exponentiallly increase the number of paths through the circuit which must be evaluated.
 *
 * To avoid this unpleasent behaviour, we implement 'block-based' STA. Under this formulation,
 * only the worst case values are kept at each node in the circuit. While this is more
 * pessimistic (any path passing through a node is now viewed as having the worst case delay
 * of any path through that node), it greatly reduces the computational complexity, allowing
 * STA to be perfomed in linear time.
 *
 * Arrival Time, Required Time & Slack
 * ---------------------------------------
 * When a Timing Analyzer performs timing analysis it is primarily calculating the following:
 *
 *    - Arrival Time: The time a signal actually arrived at a particular point in the circuit.
 *
 *    - Required Time: The time a signal should have arrived (was required) at a particular
 *                     to avoid violating a timing constraint.
 *
 *    - Slack: The difference between required and arrival times. This indicates how close
 *             a particular path/node is to violating its timing constraint.  A positive
 *             value indicates there is no violation, a negative value indicates there is
 *             a violation. The magnitude of the slack indicates by how much the constraint
 *             is passing/failing.  A value of zero indicates that the constraint is met
 *             exactly.
 *             TODO: Implement slack calculator
 *
 *
 * Calculating Arrival & Required Times
 * --------------------------------------
 * It is also useful to define the following collections of timing graph nodes:
 *    - Primary Inputs (PIs): circuit external input pins, Flip-Flop Q pins
 *    - Primary Outputs (POs): circuit external output pins, Flip-Flop D pins
 * Note that in the timing graph PIs have no fan-in, and POs have no fan-out.
 *
 * The arrival and required times are calculated at every node in the timing graph by walking
 * the timing graph in either a 'forward' or 'backward' direction. The following provide a
 * high-level description of the process.
 *
 * On the initial (forward) traversal, the graph is walked from PIs to POs to calculate arrival
 * time, performing the following:
 *      1) Initialize the arrival time of all PIs based on constraints (typically zero in the
 *         simplest case)
 *      2) Add the delay of each edge to the arrival time of the edge's driving node to
 *         to calculate the edge arrival time.
 *      3) At each downstream node calculate the max (setup) or min (hold) of all input
 *         edge arrival times, and store it as the node arrival time.
 *      4) Repeat (2)-(3) until all nodes have valid arrival times.
 *
 * On the second (backward) traversal, the graph is walked in reverse from POs to PIs, performing
 * the following:
 *      1) Initialize the required times of all POs based on constraints (typically target
 *         clock period for setup analysis)
 *      2) Subtract the delay of each edge to the required time of the edge's sink node to
 *         to calculate the edge required time.
 *      3) At each upstream node calculate the min (setup) or max (hold) of all input
 *         edge required times, and store it as the node required time.
 *      4) Repeat (2)-(3) until all nodes have valid required times.
 *
 * Clock Skew
 * ------------
 * In a real system the clocks which launch signals at the PIs and capture them at POs may not
 * all arrive at the same instance in time.  This difference is known as 'skew'.
 *
 * Skew can be modled by adjusting the initialized PI arrival times to reflect when the clock
 * signal actually reaches the node.  Similarily the PO required times can also be adjusted.
 *
 * Multi-clock Analysis
 * ----------------------
 * The previous discussion has focused primarily on single-clock STA. In a multi-clock analysis
 * transfers between clock domains need to be handled (e.g. if the launch and capture clocks are
 * different). This is typically handled by identifying the worst-case alignment between all pairs
 * of clocks. This worst case value then becomes the constraint between the two clocks.
 *
 * To perform a multi-clock analysis the paths between different clocks need to be considered with
 * the identified constraint applied.  This can be handled in two ways either:
 *      a) Performing multiple single-clock analysis passes (one for each pair of clocks), or
 *      b) Perform a single analysis but track multiple arrival/required times (a unique one for
 *         each clock).
 *
 * Approach (b) turns out to be more efficient in practice, since it only requires a single traversal
 * of the timing graph. The combined values {clock, arrival time, required time} (and potentially other
 * info) are typically combined into a single 'Tag'.  As a result there may be multiple tags stored
 * at each node in the timing graph.
 */

 /* XXX TODO: these features haven't yet been implemented!
 * ======================================================
 *
 * Derating & Pesimism Reduction Techniques
 * ------------------------------------------
 *
 * Unlike the previous discussion (which assumed constant delay values), in reality circuit delays
 * varry based on a variety of different parameters.  To generate a correct (i.e. pessimistic and not
 * optimistic) analysis this means we must often choose a highly pessemistic value for this single
 * delay. In order to recovering some of this pessimism requires modeling more details of the system.
 *
 * Slew & Rise/Fall
 * ------------------
 * Two of the key parameters that the single delay model does not account for are the impact of:
 *     - Signals 'slew rate' (e.g. signal transition time from low to high), which can effect
 *       the delay through a logic gate
 *     - Signal direction (i.e. is a logic gate's output rising or falling). In CMOS
 *       technologies different transitors of different types are activated depending on the
 *       direction of the output signal (e.g. NMOS pull-down vs PMOS pull-up)
 *
 * Derating
 * ----------
 * Another challenge in modern CMOS technologies is the presence of On-Chip Variation (OCV),
 * identically design structures (e.g. transistors, wires) may have different performance
 * due to manufacturing variation. To capture this behaviour one approach is to apply a
 * derate to delays on different paths in the circuit.
 *
 * In the typical approach applies incrementally more advanced derating, focusing firstly
 * on the most significant sources of variation. A typical progressing is to apply derating to:
 *      1) Clock Path
 *          Since clocks often span large portions of the chip they can be subject to large
 *          variation. To ensure a pessemistic analysis an late (early) derate is applied to
 *          clock launch paths, and a early (launch) derate to clock capture paths for a setup
 *          (hold) analysis.
 *
 *      2) Data Path
 *          Early (late) derates can also be applied to data paths to account for their variation
 *          during setup (hold) analysis.
 *          Note that data paths tend to be more localized to clock networks so the impact of
 *          OCV tends to be smaller.
 *
 * The simplest form of derating is a fixed derate applied to every delay, this can be extended
 * to different delays for different types of circuit elements (wires vs cells, individual cells
 * etc.).
 *
 * It turns out that fixed derates are overly pessemistic, since it is unlikely (particularliy on
 * long paths) that random variation will always go in one direction.  Improved forms of derating
 * take into account the length (depth) of a path, often using a (user specified) table of derates
 * which falls off (derates less) along deeper paths.  It is also possible for the derate to take
 * into account the physical locality/spread of a path.
 *
 * Common Clock Pessimism Removal (CCPR)
 * ---------------------------------------
 * Note: Names for this vary, including: Clock Reconvergence Pessimism Removal (CRPR),
 *       Common Path Pessimism Removal (CPPR), and likely others.
 *
 * Derating can also introduce pessimism when applied to clock networks if the launch and
 * capture paths share some common portion of the clock network. Specifically, using
 * early/late derates on the launch/capture paths of a clock network may model a scenario
 * which is physically impossible to occur:  the shared portion of the clock path cannot
 * be both early and late at the same time.
 *
 * CCPR does not directly remove this effect, but instead calculates a 'credit' which is
 * added back to the final path to counter-act this extra pessimism.
 */

 /*
  * IMPLEMENTATION NOTES
  * --------------------
  *
  * All the timing analyzers defined here are pure abstract classes.
  * They should all have pure virtual functions and store NO data members.
  *
  * We use multiple (virtual) inheritance to define the SetupHoldTimingAnalyzer
  * class, allowing it to be cleanly substituted for any SetupTimingAnalyzer
  * or HoldTimingAnalyzer.
  *
  * Note also that we are using the NVF (Non-Virtual Interface) pattern, so
  * any public member functions should delegate their work to an appropriate
  * protected virtual member function.
  */

/**
 * TimingAnalyzer represents an abstract interface for all timing analyzers,
 * which can be:
 *   - updated (update_timing())
 *   - reset (reset_timing()).
 *
 * This is the most abstract interface provided (it does not allow access
 * to any calculated data).  As a result this interface is suitable for
 * code that needs to update timing analysis, but does not _require_ the
 * analysis results itself.
 *
 * If you need the analysis results you should be using one of the dervied
 * classes (e.g. SetupTimingAnalyzer).
 */
class TimingAnalyzer {
    public:
        virtual ~TimingAnalyzer() {};

        ///Perform timing analysis to update timing information (i.e. arrival & required times)
        void update_timing() { update_timing_impl(); }

        ///Clear any old timing values updated
        void reset_timing() { reset_timing_impl(); }

        double get_profiling_data(std::string key) { return get_profiling_data_impl(key); }

    protected:
        virtual void update_timing_impl() = 0;

        virtual void reset_timing_impl() = 0;

        virtual double get_profiling_data_impl(std::string key) = 0;
};

/**
 * SetupTimingAnalyzer represents an abstract interface for all timing analyzers
 * performing setup (i.e. long-path) analysis.
 *
 * Note the use of virtual inheritance to avoid duplicating the base class
 */
class SetupTimingAnalyzer : public virtual TimingAnalyzer {
    public:
        const TimingTags& get_setup_data_tags(NodeId node_id) const { return get_setup_data_tags_impl(node_id); }
        const TimingTags& get_setup_clock_tags(NodeId node_id) const { return get_setup_clock_tags_impl(node_id); }

    protected:
        virtual const TimingTags& get_setup_data_tags_impl(NodeId node_id) const = 0;
        virtual const TimingTags& get_setup_clock_tags_impl(NodeId node_id) const = 0;

};

/**
 * HoldTimingAnalyzer represents an abstract interface for all timing analyzers
 * performing hold (i.e. short-path) analysis.
 *
 * Note the use of virtual inheritance to avoid duplicating the base class
 */
class HoldTimingAnalyzer : public virtual TimingAnalyzer {
    public:
        const TimingTags& get_hold_data_tags(NodeId node_id) const { return get_hold_data_tags_impl(node_id); }
        const TimingTags& get_hold_clock_tags(NodeId node_id) const { return get_hold_clock_tags_impl(node_id); }

    protected:
        virtual const TimingTags& get_hold_data_tags_impl(NodeId node_id) const = 0;
        virtual const TimingTags& get_hold_clock_tags_impl(NodeId node_id) const = 0;
};

/**
 * SetupHoldTimingAnalyzer represents an abstract interface for all timing analyzers
 * performing combined setup and hold (i.e. simultaneous long and short-path) analysis.
 *
 * A combined analysis tends to be more efficient than performing two seperate analysies
 * (provided both setup and hold data are truly required).
 *
 * It implements both the SetupTimingAnalyzer and HoldTimingAnalyzer interfaces.
 */
class SetupHoldTimingAnalyzer : public SetupTimingAnalyzer, public HoldTimingAnalyzer {
    //Empty (all behaviour inherited)
    //
    // Note that SetupTiminganalyzer and HoldTimingAnalyzer used virtual inheritance, so
    // there is no ambiguity when inheriting from both
};

<|endoftext|>


<commit_before>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
//
// Configuration include.
//// Included at first position before any other ones.
#include "ConfigureMonteverdi2.h"

//
// Qt includes (sorted by alphabetic order)
//// Must be included before system/custom includes.

//
// System includes (sorted by alphabetic order)

// Monteverdi includes (sorted by alphabetic order)
#include "mvdApplication.h"
#include "mvdMainWindow.h"

int mvdMonteverdi2ApplicationTest(int argc, char* argv[])
{
  QApplication qtApp( argc, argv );

  mvd::Application application( &qtApp );
  mvd::MainWindow main_window;

  main_window.show();

  QTimer::singleShot(1000, &application, SLOT(quit()));

  return qtApp.exec();
}
<commit_msg>TEST: Fixed signal/slot connection.<commit_after>/*=========================================================================

  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
//
// Configuration include.
//// Included at first position before any other ones.
#include "ConfigureMonteverdi2.h"

//
// Qt includes (sorted by alphabetic order)
//// Must be included before system/custom includes.

//
// System includes (sorted by alphabetic order)

// Monteverdi includes (sorted by alphabetic order)
#include "mvdApplication.h"
#include "mvdMainWindow.h"

int mvdMonteverdi2ApplicationTest(int argc, char* argv[])
{
  QApplication qtApp( argc, argv );

  mvd::Application application( &qtApp );
  mvd::MainWindow main_window;

  main_window.show();

  QTimer::singleShot(1000, &qtApp, SLOT(quit()));

  return qtApp.exec();
}
<|endoftext|>


<commit_before>//   fft.cpp - impelementation of class
//   of fast Fourier transform - FFT
//
//   The code is property of LIBROW
//   You can use it on your own
//   When utilizing credit LIBROW site

//   Include declaration file
#include "fft.h"
//   Include math library
#include <math.h>

//   FORWARD FOURIER TRANSFORM
//     Input  - input data
//     Output - transform result
//     N      - length of both input data and result
bool CFFT::Forward(const complex *const Input, complex *const Output, const unsigned int N)
{
	//   Check input parameters
	if (!Input || !Output || N < 1 || N & (N - 1))
		return false;
	//   Initialize data
	Rearrange(Input, Output, N);
	//   Call FFT implementation
	Perform(Output, N);
	//   Succeeded
	return true;
}

//   FORWARD FOURIER TRANSFORM, INPLACE VERSION
//     Data - both input data and output
//     N    - length of input data
bool CFFT::Forward(complex *const Data, const unsigned int N)
{
	//   Check input parameters
	if (!Data || N < 1 || N & (N - 1))
		return false;
	//   Rearrange
	Rearrange(Data, N);
	//   Call FFT implementation
	Perform(Data, N);
	//   Succeeded
	return true;
}

//   INVERSE FOURIER TRANSFORM
//     Input  - input data
//     Output - transform result
//     N      - length of both input data and result
//     Scale  - if to scale result
bool CFFT::Inverse(const complex *const Input, complex *const Output, const unsigned int N, const bool Scale /* = true */)
{
	//   Check input parameters
	if (!Input || !Output || N < 1 || N & (N - 1))
		return false;
	//   Initialize data
	Rearrange(Input, Output, N);
	//   Call FFT implementation
	Perform(Output, N, true);
	//   Scale if necessary
	if (Scale)
		CFFT::Scale(Output, N);
	//   Succeeded
	return true;
}

//   INVERSE FOURIER TRANSFORM, INPLACE VERSION
//     Data  - both input data and output
//     N     - length of both input data and result
//     Scale - if to scale result
bool CFFT::Inverse(complex *const Data, const unsigned int N, const bool Scale /* = true */)
{
	//   Check input parameters
	if (!Data || N < 1 || N & (N - 1))
		return false;
	//   Rearrange
	Rearrange(Data, N);
	//   Call FFT implementation
	Perform(Data, N, true);
	//   Scale if necessary
	if (Scale)
		CFFT::Scale(Data, N);
	//   Succeeded
	return true;
}

//   Rearrange function
void CFFT::Rearrange(const complex *const Input, complex *const Output, const unsigned int N)
{
	//   Data entry position
	unsigned int Target = 0;
	//   Process all positions of input signal
	for (unsigned int Position = 0; Position < N; ++Position)
	{
		//  Set data entry
		Output[Target] = Input[Position];
		//   Bit mask
		unsigned int Mask = N;
		//   While bit is set
		while (Target & (Mask >>= 1))
			//   Drop bit
			Target &= ~Mask;
		//   The current bit is 0 - set it
		Target |= Mask;
	}
}

//   Inplace version of rearrange function
void CFFT::Rearrange(complex *const Data, const unsigned int N)
{
	//   Swap position
	unsigned int Target = 0;
	//   Process all positions of input signal
	for (unsigned int Position = 0; Position < N; ++Position)
	{
		//   Only for not yet swapped entries
		if (Target > Position)
		{
			//   Swap entries
			const complex Temp(Data[Target]);
			Data[Target] = Data[Position];
			Data[Position] = Temp;
		}
		//   Bit mask
		unsigned int Mask = N;
		//   While bit is set
		while (Target & (Mask >>= 1))
			//   Drop bit
			Target &= ~Mask;
		//   The current bit is 0 - set it
		Target |= Mask;
	}
}

//   FFT implementation
void CFFT::Perform(complex *const Data, const unsigned int N, const bool Inverse /* = false */)
{
	const double pi = Inverse ? 3.14159265358979323846 : -3.14159265358979323846;
	//   Iteration through dyads, quadruples, octads and so on...
	for (unsigned int Step = 1; Step < N; Step <<= 1)
	{
		//   Jump to the next entry of the same transform factor
		const unsigned int Jump = Step << 1;
		//   Angle increment
		const double delta = pi / double(Step);
		//   Auxiliary sin(delta / 2)
		const double Sine = sin(delta * .5);
		//   Multiplier for trigonometric recurrence
		const complex Multiplier(-2. * Sine * Sine, sin(delta));
		//   Start value for transform factor, fi = 0
		complex Factor(1.);
		//   Iteration through groups of different transform factor
		for (unsigned int Group = 0; Group < Step; ++Group)
		{
			//   Iteration within group
			for (unsigned int Pair = Group; Pair < N; Pair += Jump)
			{
				//   Match position
				const unsigned int Match = Pair + Step;
				//   Second term of two-point transform
				const complex Product(Factor * Data[Match]);
				//   Transform for fi + pi
				Data[Match] = Data[Pair] - Product;
				//   Transform for fi
				Data[Pair] += Product;
			}
			//   Successive transform factor via trigonometric recurrence
			Factor = Multiplier * Factor + Factor;
		}
	}
}

//   Scaling of inverse FFT result
void CFFT::Scale(complex *const Data, const unsigned int N)
{
	const double Factor = 1. / double(N);
	//   Scale all data entries
	for (unsigned int Position = 0; Position < N; ++Position)
		Data[Position] *= Factor;
}
<commit_msg>fft.cpp looks for fft.h in the Sonic repo<commit_after>//   fft.cpp - impelementation of class
//   of fast Fourier transform - FFT
//
//   The code is property of LIBROW
//   You can use it on your own
//   When utilizing credit LIBROW site

//   Include declaration file
#include "../include/fft.h"
//   Include math library
#include <math.h>

//   FORWARD FOURIER TRANSFORM
//     Input  - input data
//     Output - transform result
//     N      - length of both input data and result
bool CFFT::Forward(const complex *const Input, complex *const Output, const unsigned int N)
{
	//   Check input parameters
	if (!Input || !Output || N < 1 || N & (N - 1))
		return false;
	//   Initialize data
	Rearrange(Input, Output, N);
	//   Call FFT implementation
	Perform(Output, N);
	//   Succeeded
	return true;
}

//   FORWARD FOURIER TRANSFORM, INPLACE VERSION
//     Data - both input data and output
//     N    - length of input data
bool CFFT::Forward(complex *const Data, const unsigned int N)
{
	//   Check input parameters
	if (!Data || N < 1 || N & (N - 1))
		return false;
	//   Rearrange
	Rearrange(Data, N);
	//   Call FFT implementation
	Perform(Data, N);
	//   Succeeded
	return true;
}

//   INVERSE FOURIER TRANSFORM
//     Input  - input data
//     Output - transform result
//     N      - length of both input data and result
//     Scale  - if to scale result
bool CFFT::Inverse(const complex *const Input, complex *const Output, const unsigned int N, const bool Scale /* = true */)
{
	//   Check input parameters
	if (!Input || !Output || N < 1 || N & (N - 1))
		return false;
	//   Initialize data
	Rearrange(Input, Output, N);
	//   Call FFT implementation
	Perform(Output, N, true);
	//   Scale if necessary
	if (Scale)
		CFFT::Scale(Output, N);
	//   Succeeded
	return true;
}

//   INVERSE FOURIER TRANSFORM, INPLACE VERSION
//     Data  - both input data and output
//     N     - length of both input data and result
//     Scale - if to scale result
bool CFFT::Inverse(complex *const Data, const unsigned int N, const bool Scale /* = true */)
{
	//   Check input parameters
	if (!Data || N < 1 || N & (N - 1))
		return false;
	//   Rearrange
	Rearrange(Data, N);
	//   Call FFT implementation
	Perform(Data, N, true);
	//   Scale if necessary
	if (Scale)
		CFFT::Scale(Data, N);
	//   Succeeded
	return true;
}

//   Rearrange function
void CFFT::Rearrange(const complex *const Input, complex *const Output, const unsigned int N)
{
	//   Data entry position
	unsigned int Target = 0;
	//   Process all positions of input signal
	for (unsigned int Position = 0; Position < N; ++Position)
	{
		//  Set data entry
		Output[Target] = Input[Position];
		//   Bit mask
		unsigned int Mask = N;
		//   While bit is set
		while (Target & (Mask >>= 1))
			//   Drop bit
			Target &= ~Mask;
		//   The current bit is 0 - set it
		Target |= Mask;
	}
}

//   Inplace version of rearrange function
void CFFT::Rearrange(complex *const Data, const unsigned int N)
{
	//   Swap position
	unsigned int Target = 0;
	//   Process all positions of input signal
	for (unsigned int Position = 0; Position < N; ++Position)
	{
		//   Only for not yet swapped entries
		if (Target > Position)
		{
			//   Swap entries
			const complex Temp(Data[Target]);
			Data[Target] = Data[Position];
			Data[Position] = Temp;
		}
		//   Bit mask
		unsigned int Mask = N;
		//   While bit is set
		while (Target & (Mask >>= 1))
			//   Drop bit
			Target &= ~Mask;
		//   The current bit is 0 - set it
		Target |= Mask;
	}
}

//   FFT implementation
void CFFT::Perform(complex *const Data, const unsigned int N, const bool Inverse /* = false */)
{
	const double pi = Inverse ? 3.14159265358979323846 : -3.14159265358979323846;
	//   Iteration through dyads, quadruples, octads and so on...
	for (unsigned int Step = 1; Step < N; Step <<= 1)
	{
		//   Jump to the next entry of the same transform factor
		const unsigned int Jump = Step << 1;
		//   Angle increment
		const double delta = pi / double(Step);
		//   Auxiliary sin(delta / 2)
		const double Sine = sin(delta * .5);
		//   Multiplier for trigonometric recurrence
		const complex Multiplier(-2. * Sine * Sine, sin(delta));
		//   Start value for transform factor, fi = 0
		complex Factor(1.);
		//   Iteration through groups of different transform factor
		for (unsigned int Group = 0; Group < Step; ++Group)
		{
			//   Iteration within group
			for (unsigned int Pair = Group; Pair < N; Pair += Jump)
			{
				//   Match position
				const unsigned int Match = Pair + Step;
				//   Second term of two-point transform
				const complex Product(Factor * Data[Match]);
				//   Transform for fi + pi
				Data[Match] = Data[Pair] - Product;
				//   Transform for fi
				Data[Pair] += Product;
			}
			//   Successive transform factor via trigonometric recurrence
			Factor = Multiplier * Factor + Factor;
		}
	}
}

//   Scaling of inverse FFT result
void CFFT::Scale(complex *const Data, const unsigned int N)
{
	const double Factor = 1. / double(N);
	//   Scale all data entries
	for (unsigned int Position = 0; Position < N; ++Position)
		Data[Position] *= Factor;
}
<|endoftext|>


<commit_before>// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "StdAfx.h"
#include "..\BatchEncoder.h"
#include "..\utilities\Utilities.h"
#include "WorkThread.h"

enum Mode { None = -1, Encode = 0, Transcode = 1 };

void ToFileContext(CFileContext &context, CWorkerContext *pWorkerContext, CFormat &format, int nPreset, int nItemId, CString szInputFile, CString szOutputFile)
{
    CPreset& preset = format.m_Presets.GetData(nPreset);

    context.pWorkerContext = pWorkerContext;
    context.szInputFile = szInputFile;
    context.szOutputFile = szOutputFile;

    CString szExecute;
    szExecute = format.szTemplate;
    szExecute.Replace(_T("$EXE"), _T("\"$EXE\""));
    szExecute.Replace(_T("$EXE"), format.szPath);
    szExecute.Replace(_T("$OPTIONS"), preset.szOptions);

    szExecute.Replace(_T("$INFILE"), _T("\"$INFILE\""));
    if (format.bPipeInput == true)
        szExecute.Replace(_T("$INFILE"), _T("-"));
    else
        szExecute.Replace(_T("$INFILE"), szInputFile);

    szExecute.Replace(_T("$OUTFILE"), _T("\"$OUTFILE\""));
    if (format.bPipeOutput == true)
        szExecute.Replace(_T("$OUTFILE"), _T("-"));
    else
        szExecute.Replace(_T("$OUTFILE"), szOutputFile);

    TCHAR szCommandLine[(64 * 1024)];
    ZeroMemory(szCommandLine, sizeof(szCommandLine));
    lstrcpy(szCommandLine, szExecute.GetBuffer(szExecute.GetLength()));
    context.szCommandLine = szCommandLine;

    context.nItemId = nItemId;
    context.szFunction = format.szFunction;
    context.bUseReadPipes = format.bPipeInput;
    context.bUseWritePipes = format.bPipeOutput;
}

bool ConvertItem(CItemContext* pContext)
{
    // input path
    CString szInputFile = pContext->item->szPath;

    // output path
    CString szOutPath;
    if (pContext->pWorkerContext->pConfig->m_Options.bOutputPathChecked == true)
    {
        szOutPath = pContext->pWorkerContext->pConfig->m_Options.szOutputPath;
    }
    else
    {
        CString szInputFileName = ::GetFileName(szInputFile);
        szOutPath = szInputFile;
        szOutPath.Truncate(szOutPath.GetLength() - szInputFileName.GetLength());
    }

    // output format
    int nEncoder = pContext->pWorkerContext->pConfig->m_Formats.GetFormatById(pContext->item->szFormatId);
    if (nEncoder == -1)
    {
        pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: can not find valid encoder by id."));
        return false;
    }

    CFormat& encoderFormat = pContext->pWorkerContext->pConfig->m_Formats.GetData(nEncoder);

    // check input extensions
    CString szInputFileExt = ::GetFileExtension(szInputFile).MakeUpper();
    bool bIsValidEncoderInput = encoderFormat.IsValidInputExtension(szInputFileExt);

    // processing mode
    Mode nProcessingMode = Mode::None;
    if (bIsValidEncoderInput)
        nProcessingMode = Mode::Encode;
    else
        nProcessingMode = Mode::Transcode;

    // output path
    CString szEncoderExtension = encoderFormat.szOutputExtension;
    CString szName = pContext->item->szName + _T(".") + szEncoderExtension.MakeLower();
    CString szOutputFile;
    if (szOutPath.GetLength() >= 1)
    {
        if (szOutPath[szOutPath.GetLength() - 1] == '\\' || szOutPath[szOutPath.GetLength() - 1] == '/')
            szOutputFile = szOutPath + szName;
        else
            szOutputFile = szOutPath + _T("\\") + szName;
    }
    else
    {
        szOutputFile = szName;
    }

    CString szOrgInputFile = szInputFile;
    CString szOrgOutputFile = szOutputFile;

    if (nProcessingMode == Mode::Transcode)
    {
        int nDecoder = pContext->pWorkerContext->pConfig->m_Formats.GetDecoderByExtension(pContext->item->szExtension);
        if (nDecoder == -1)
        {
            pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: can not find valid decoder by extension."));
            return false;
        }

        CFormat& decoderFormat = pContext->pWorkerContext->pConfig->m_Formats.GetData(nDecoder);

        bIsValidEncoderInput = encoderFormat.IsValidInputExtension(decoderFormat.szOutputExtension);
        if (bIsValidEncoderInput == false)
        {
            pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: decoder output not supported by encoder."));
            return false;
        }

        CString szDecoderExtension = decoderFormat.szOutputExtension;
        szOutputFile = szOutputFile + +_T(".") + szDecoderExtension.MakeLower();

        pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Decoding..."));

        if (decoderFormat.nDefaultPreset >= decoderFormat.m_Presets.GetSize())
        {
            pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: can not find format preset."));
            return false;
        }

        try
        {
            CFileContext context;
            ToFileContext(context, pContext->pWorkerContext, decoderFormat, decoderFormat.nDefaultPreset, pContext->item->nId, szInputFile, szOutputFile);

            bool bResult = ::ConvertFile(&context);
            if (bResult == false)
            {
                if (pContext->pWorkerContext->pConfig->m_Options.bDeleteOnErrors == true)
                    ::DeleteFile(szOutputFile);

                return false;
            }
        }
        catch (...)
        {
            if (pContext->pWorkerContext->pConfig->m_Options.bDeleteOnErrors == true)
                ::DeleteFile(szOutputFile);

            pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: exception thrown while converting file."));
            pWorkerContext->Callback(pContext->item->nId, -1, true, true);
        }
    }

    if (pContext->pWorkerContext->bRunning == false)
        return false;

    if (nProcessingMode == Mode::Transcode)
    {
        szInputFile = szOutputFile;
        szOutputFile = szOrgOutputFile;
    }

    if ((nProcessingMode == Mode::Encode) || (nProcessingMode == Mode::Transcode))
    {
        pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Encoding..."));

        if (pContext->item->nPreset >= encoderFormat.m_Presets.GetSize())
        {
            pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: can not find format preset."));
            return false;
        }

        try
        {
            CFileContext context;
            ToFileContext(context, pContext->pWorkerContext, encoderFormat, pContext->item->nPreset, pContext->item->nId, szInputFile, szOutputFile);

            bool bResult = ::ConvertFile(&context);

            if (nProcessingMode == Mode::Transcode)
                ::DeleteFile(szInputFile);

            if (bResult == true)
            {
                if (pContext->pWorkerContext->pConfig->m_Options.bDeleteSourceFiles == true)
                    ::DeleteFile(szOrgInputFile);

                return true;
            }
            else
            {
                if (pContext->pWorkerContext->pConfig->m_Options.bDeleteOnErrors == true)
                    ::DeleteFile(szOutputFile);

                return false;
            }
        }
        catch (...)
        {
            if (nProcessingMode == Mode::Transcode)
                ::DeleteFile(szInputFile);

            if (pContext->pWorkerContext->pConfig->m_Options.bDeleteOnErrors == true)
                ::DeleteFile(szOutputFile);

            pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: exception thrown while converting file."));
            pWorkerContext->Callback(pContext->item->nId, -1, true, true);
        }
    }

    return false;
}
<commit_msg>Update ConvertItem.cpp<commit_after>// Copyright (c) Wiesław Šoltés. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "StdAfx.h"
#include "..\BatchEncoder.h"
#include "..\utilities\Utilities.h"
#include "WorkThread.h"

enum Mode { None = -1, Encode = 0, Transcode = 1 };

void ToFileContext(CFileContext &context, CWorkerContext *pWorkerContext, CFormat &format, int nPreset, int nItemId, CString szInputFile, CString szOutputFile)
{
    CPreset& preset = format.m_Presets.GetData(nPreset);

    context.pWorkerContext = pWorkerContext;
    context.szInputFile = szInputFile;
    context.szOutputFile = szOutputFile;

    CString szExecute;
    szExecute = format.szTemplate;
    szExecute.Replace(_T("$EXE"), _T("\"$EXE\""));
    szExecute.Replace(_T("$EXE"), format.szPath);
    szExecute.Replace(_T("$OPTIONS"), preset.szOptions);

    szExecute.Replace(_T("$INFILE"), _T("\"$INFILE\""));
    if (format.bPipeInput == true)
        szExecute.Replace(_T("$INFILE"), _T("-"));
    else
        szExecute.Replace(_T("$INFILE"), szInputFile);

    szExecute.Replace(_T("$OUTFILE"), _T("\"$OUTFILE\""));
    if (format.bPipeOutput == true)
        szExecute.Replace(_T("$OUTFILE"), _T("-"));
    else
        szExecute.Replace(_T("$OUTFILE"), szOutputFile);

    TCHAR szCommandLine[(64 * 1024)];
    ZeroMemory(szCommandLine, sizeof(szCommandLine));
    lstrcpy(szCommandLine, szExecute.GetBuffer(szExecute.GetLength()));
    context.szCommandLine = szCommandLine;

    context.nItemId = nItemId;
    context.szFunction = format.szFunction;
    context.bUseReadPipes = format.bPipeInput;
    context.bUseWritePipes = format.bPipeOutput;
}

bool ConvertItem(CItemContext* pContext)
{
    // input path
    CString szInputFile = pContext->item->szPath;

    // output path
    CString szOutPath;
    if (pContext->pWorkerContext->pConfig->m_Options.bOutputPathChecked == true)
    {
        szOutPath = pContext->pWorkerContext->pConfig->m_Options.szOutputPath;
    }
    else
    {
        CString szInputFileName = ::GetFileName(szInputFile);
        szOutPath = szInputFile;
        szOutPath.Truncate(szOutPath.GetLength() - szInputFileName.GetLength());
    }

    // output format
    int nEncoder = pContext->pWorkerContext->pConfig->m_Formats.GetFormatById(pContext->item->szFormatId);
    if (nEncoder == -1)
    {
        pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: can not find valid encoder by id."));
        return false;
    }

    CFormat& encoderFormat = pContext->pWorkerContext->pConfig->m_Formats.GetData(nEncoder);

    // check input extensions
    CString szInputFileExt = ::GetFileExtension(szInputFile).MakeUpper();
    bool bIsValidEncoderInput = encoderFormat.IsValidInputExtension(szInputFileExt);

    // processing mode
    Mode nProcessingMode = Mode::None;
    if (bIsValidEncoderInput)
        nProcessingMode = Mode::Encode;
    else
        nProcessingMode = Mode::Transcode;

    // output path
    CString szEncoderExtension = encoderFormat.szOutputExtension;
    CString szName = pContext->item->szName + _T(".") + szEncoderExtension.MakeLower();
    CString szOutputFile;
    if (szOutPath.GetLength() >= 1)
    {
        if (szOutPath[szOutPath.GetLength() - 1] == '\\' || szOutPath[szOutPath.GetLength() - 1] == '/')
            szOutputFile = szOutPath + szName;
        else
            szOutputFile = szOutPath + _T("\\") + szName;
    }
    else
    {
        szOutputFile = szName;
    }

    CString szOrgInputFile = szInputFile;
    CString szOrgOutputFile = szOutputFile;

    if (nProcessingMode == Mode::Transcode)
    {
        int nDecoder = pContext->pWorkerContext->pConfig->m_Formats.GetDecoderByExtension(pContext->item->szExtension);
        if (nDecoder == -1)
        {
            pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: can not find valid decoder by extension."));
            return false;
        }

        CFormat& decoderFormat = pContext->pWorkerContext->pConfig->m_Formats.GetData(nDecoder);

        bIsValidEncoderInput = encoderFormat.IsValidInputExtension(decoderFormat.szOutputExtension);
        if (bIsValidEncoderInput == false)
        {
            pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: decoder output not supported by encoder."));
            return false;
        }

        CString szDecoderExtension = decoderFormat.szOutputExtension;
        szOutputFile = szOutputFile + +_T(".") + szDecoderExtension.MakeLower();

        pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Decoding..."));

        if (decoderFormat.nDefaultPreset >= decoderFormat.m_Presets.GetSize())
        {
            pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: can not find format preset."));
            return false;
        }

        try
        {
            CFileContext context;
            ToFileContext(context, pContext->pWorkerContext, decoderFormat, decoderFormat.nDefaultPreset, pContext->item->nId, szInputFile, szOutputFile);

            bool bResult = ::ConvertFile(&context);
            if (bResult == false)
            {
                if (pContext->pWorkerContext->pConfig->m_Options.bDeleteOnErrors == true)
                    ::DeleteFile(szOutputFile);

                return false;
            }
        }
        catch (...)
        {
            if (pContext->pWorkerContext->pConfig->m_Options.bDeleteOnErrors == true)
                ::DeleteFile(szOutputFile);

            pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: exception thrown while converting file."));
            pContext->pWorkerContext->Callback(pContext->item->nId, -1, true, true);
        }
    }

    if (pContext->pWorkerContext->bRunning == false)
        return false;

    if (nProcessingMode == Mode::Transcode)
    {
        szInputFile = szOutputFile;
        szOutputFile = szOrgOutputFile;
    }

    if ((nProcessingMode == Mode::Encode) || (nProcessingMode == Mode::Transcode))
    {
        pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Encoding..."));

        if (pContext->item->nPreset >= encoderFormat.m_Presets.GetSize())
        {
            pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: can not find format preset."));
            return false;
        }

        try
        {
            CFileContext context;
            ToFileContext(context, pContext->pWorkerContext, encoderFormat, pContext->item->nPreset, pContext->item->nId, szInputFile, szOutputFile);

            bool bResult = ::ConvertFile(&context);

            if (nProcessingMode == Mode::Transcode)
                ::DeleteFile(szInputFile);

            if (bResult == true)
            {
                if (pContext->pWorkerContext->pConfig->m_Options.bDeleteSourceFiles == true)
                    ::DeleteFile(szOrgInputFile);

                return true;
            }
            else
            {
                if (pContext->pWorkerContext->pConfig->m_Options.bDeleteOnErrors == true)
                    ::DeleteFile(szOutputFile);

                return false;
            }
        }
        catch (...)
        {
            if (nProcessingMode == Mode::Transcode)
                ::DeleteFile(szInputFile);

            if (pContext->pWorkerContext->pConfig->m_Options.bDeleteOnErrors == true)
                ::DeleteFile(szOutputFile);

            pContext->pWorkerContext->Status(pContext->item->nId, _T("--:--"), _T("Error: exception thrown while converting file."));
            pContext->pWorkerContext->Callback(pContext->item->nId, -1, true, true);
        }
    }

    return false;
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
//  IOFacade.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#include "IOFacade.h"
#include "IO/assignRegistry.h"
#include "Core/CoreFacade.h"

namespace Oryol {
namespace IO {

using namespace Core;

OryolClassImpl(IOFacade);
OryolGlobalSingletonImpl(IOFacade);

/// @todo: make numIOLanes configurable
const int32 IOFacade::numIOLanes = 4;

//------------------------------------------------------------------------------
IOFacade::IOFacade() {
    this->SingletonEnsureUnique();
    this->mainThreadId = std::this_thread::get_id();
    assignRegistry::CreateSingleton();
    schemeRegistry::CreateSingleton();
    this->ioRequestRouter = ioRequestRouter::Create(IOFacade::numIOLanes);
    CoreFacade::Instance()->ThreadRunLoop()->Add(RunLoop::Callback("IO::IOFacade", 0, std::bind(&IOFacade::doWork, this)));
}

//------------------------------------------------------------------------------
IOFacade::~IOFacade() {
    o_assert(this->isMainThread());
    CoreFacade::Instance()->ThreadRunLoop()->Remove("IO::IOFacade");
    this->ioRequestRouter = 0;
    schemeRegistry::DestroySingleton();
    assignRegistry::DestroySingleton();
}

//------------------------------------------------------------------------------
void
IOFacade::doWork() {
    if (this->ioRequestRouter.isValid()) {
        this->ioRequestRouter->DoWork();
    }
}

//------------------------------------------------------------------------------
bool
IOFacade::isMainThread() {
    return std::this_thread::get_id() == this->mainThreadId;
}

//------------------------------------------------------------------------------
void
IOFacade::SetAssign(const String& assign, const String& path) {
    assignRegistry::Instance()->SetAssign(assign, path);
}

//------------------------------------------------------------------------------
bool
IOFacade::HasAssign(const String& assign) const {
    return assignRegistry::Instance()->HasAssign(assign);
}

//------------------------------------------------------------------------------
String
IOFacade::LookupAssign(const String& assign) const {
    return assignRegistry::Instance()->LookupAssign(assign);
}

//------------------------------------------------------------------------------
String
IOFacade::ResolveAssigns(const String& str) const {
    return assignRegistry::Instance()->ResolveAssigns(str);
}

//------------------------------------------------------------------------------
void
IOFacade::UnregisterFileSystem(const StringAtom& scheme) {
    schemeRegistry::Instance()->UnregisterFileSystem(scheme);
}

//------------------------------------------------------------------------------
bool
IOFacade::IsFileSystemRegistered(const StringAtom& scheme) const {
    return schemeRegistry::Instance()->IsFileSystemRegistered(scheme);
}

//------------------------------------------------------------------------------
Ptr<IOProtocol::Get>
IOFacade::LoadFile(const URL& url, int32 ioLane) {
    Ptr<IOProtocol::Get> ioReq = IOProtocol::Get::Create();
    ioReq->SetURL(url);
    ioReq->SetLane(ioLane);
    this->ioRequestRouter->Put(ioReq);
    return ioReq;
}

//------------------------------------------------------------------------------
Ptr<IOProtocol::GetRange>
IOFacade::LoadFileRange(const URL& url, int32 startOffset, int32 endOffset, int32 ioLane) {
    Ptr<IOProtocol::GetRange> ioReq = IOProtocol::GetRange::Create();
    ioReq->SetURL(url);
    ioReq->SetLane(ioLane);
    ioReq->SetStartOffset(startOffset);
    ioReq->SetEndOffset(endOffset);
    this->ioRequestRouter->Put(ioReq);
    return ioReq;
}

//------------------------------------------------------------------------------
void
IOFacade::AddPreloadFile(const URL& url, int32 ioLane) {
    /// @todo: implement AddPreloadFile()
}

//------------------------------------------------------------------------------
bool
IOFacade::IsPreloadingFinished() const {
    /// @todo: implement IsPreloadingFinished()
    return false;
}

} // namespace IO
} // namespace Oryol<commit_msg>Assert that IOFacade::DoWork() is only called on main-thread<commit_after>//------------------------------------------------------------------------------
//  IOFacade.cc
//------------------------------------------------------------------------------
#include "Pre.h"
#include "IOFacade.h"
#include "IO/assignRegistry.h"
#include "Core/CoreFacade.h"

namespace Oryol {
namespace IO {

using namespace Core;

OryolClassImpl(IOFacade);
OryolGlobalSingletonImpl(IOFacade);

/// @todo: make numIOLanes configurable
const int32 IOFacade::numIOLanes = 4;

//------------------------------------------------------------------------------
IOFacade::IOFacade() {
    this->SingletonEnsureUnique();
    this->mainThreadId = std::this_thread::get_id();
    assignRegistry::CreateSingleton();
    schemeRegistry::CreateSingleton();
    this->ioRequestRouter = ioRequestRouter::Create(IOFacade::numIOLanes);
    CoreFacade::Instance()->ThreadRunLoop()->Add(RunLoop::Callback("IO::IOFacade", 0, std::bind(&IOFacade::doWork, this)));
}

//------------------------------------------------------------------------------
IOFacade::~IOFacade() {
    o_assert(this->isMainThread());
    CoreFacade::Instance()->ThreadRunLoop()->Remove("IO::IOFacade");
    this->ioRequestRouter = 0;
    schemeRegistry::DestroySingleton();
    assignRegistry::DestroySingleton();
}

//------------------------------------------------------------------------------
void
IOFacade::doWork() {
    o_assert(this->isMainThread());
    if (this->ioRequestRouter.isValid()) {
        this->ioRequestRouter->DoWork();
    }
}

//------------------------------------------------------------------------------
bool
IOFacade::isMainThread() {
    return std::this_thread::get_id() == this->mainThreadId;
}

//------------------------------------------------------------------------------
void
IOFacade::SetAssign(const String& assign, const String& path) {
    assignRegistry::Instance()->SetAssign(assign, path);
}

//------------------------------------------------------------------------------
bool
IOFacade::HasAssign(const String& assign) const {
    return assignRegistry::Instance()->HasAssign(assign);
}

//------------------------------------------------------------------------------
String
IOFacade::LookupAssign(const String& assign) const {
    return assignRegistry::Instance()->LookupAssign(assign);
}

//------------------------------------------------------------------------------
String
IOFacade::ResolveAssigns(const String& str) const {
    return assignRegistry::Instance()->ResolveAssigns(str);
}

//------------------------------------------------------------------------------
void
IOFacade::UnregisterFileSystem(const StringAtom& scheme) {
    schemeRegistry::Instance()->UnregisterFileSystem(scheme);
}

//------------------------------------------------------------------------------
bool
IOFacade::IsFileSystemRegistered(const StringAtom& scheme) const {
    return schemeRegistry::Instance()->IsFileSystemRegistered(scheme);
}

//------------------------------------------------------------------------------
Ptr<IOProtocol::Get>
IOFacade::LoadFile(const URL& url, int32 ioLane) {
    Ptr<IOProtocol::Get> ioReq = IOProtocol::Get::Create();
    ioReq->SetURL(url);
    ioReq->SetLane(ioLane);
    this->ioRequestRouter->Put(ioReq);
    return ioReq;
}

//------------------------------------------------------------------------------
Ptr<IOProtocol::GetRange>
IOFacade::LoadFileRange(const URL& url, int32 startOffset, int32 endOffset, int32 ioLane) {
    Ptr<IOProtocol::GetRange> ioReq = IOProtocol::GetRange::Create();
    ioReq->SetURL(url);
    ioReq->SetLane(ioLane);
    ioReq->SetStartOffset(startOffset);
    ioReq->SetEndOffset(endOffset);
    this->ioRequestRouter->Put(ioReq);
    return ioReq;
}

//------------------------------------------------------------------------------
void
IOFacade::AddPreloadFile(const URL& url, int32 ioLane) {
    /// @todo: implement AddPreloadFile()
}

//------------------------------------------------------------------------------
bool
IOFacade::IsPreloadingFinished() const {
    /// @todo: implement IsPreloadingFinished()
    return false;
}

} // namespace IO
} // namespace Oryol<|endoftext|>


<commit_before>#include <iostream>
#include <queue>
#include <utility>
#include <stdio.h>
#include <vector>
using namespace std;
typedef  pair<long long ,long long> node;

long long re[1300];
int main(int argc, char const *argv[])
{
	priority_queue<node ,vector<node> ,greater<node> > pq;

	pq.push(node(1,2));
	node n;
	int i=0;
	while(i<1200){

		node n=pq.top();
		//printf("%d",i);
		pq.pop();
		switch(n.second){
			case 2:
				pq.push(node(n.first*2,2));

			case 3:
				pq.push(node(n.first*3,3));

			case 5:
				pq.push(node(n.first*5,5));
		}
		re[i++]=n.first;
	}
	int T;
	scanf("%d",&T);
	int re1[1300]={0};
	for (int i = 1; i < 1200; ++i)
		re1[i]=re1[i-1]+(re[i]-re[i-1]-1);

	while(T--){
		int num;
		scanf("%d",&num);
		i=0;
		while(re1[i]<num){
			i++;
		}
		printf("%d\n",i+num);
	}

	return 0;
}
<commit_msg>update 346588<commit_after>#include <iostream>
#include <queue>
#include <utility>
#include <stdio.h>
#include <vector>
using namespace std;
typedef  pair<long long ,long long> node;
long long re[1300];
int re1[1300]={0};
int main(int argc, char const *argv[])
{
	priority_queue<node ,vector<node> ,greater<node> > pq;
	pq.push(node(1,2));
	node n;

	int i=0,T,num;
	while(i<1200){

		node n=pq.top();
		pq.pop();

		switch(n.second){
			case 2:pq.push(node(n.first*2,2));
			case 3:pq.push(node(n.first*3,3));
			case 5:pq.push(node(n.first*5,5));
		}
		re[i++]=n.first;
	}

	scanf("%d",&T);

	for (int i = 1; i < 1200; ++i)
		re1[i]=re1[i-1]+(re[i]-re[i-1]-1);

	i=0;
	while(T--){
		scanf("%d",&num);
		while(re1[i]<num)
			i++;
		printf("%d\n",i+num);
	}
	return 0;
}
<|endoftext|>