<commit_before>//
// SceneOSG.cpp
//
// Implementation of vtScene for the OSG library
//
// Copyright (c) 2001-2003 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include <osg/LightSource>
#include <osg/PolygonMode>
#include <osg/Switch>
#include <osg/Fog>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <time.h>		// clock() & CLOCKS_PER_SEC

#ifdef __FreeBSD__
#  include <sys/types.h>
#  include <sys/time.h>
#  include <sys/resource.h>
#endif

#include <streambuf>
#include "vtdata/vtLog.h"

using namespace osg;

///////////////////////////////////////////////////////////////
// Trap for OSG messages
//

class OsgMsgTrap : public std::streambuf
{
public:
	inline virtual int_type overflow(int_type c = traits_type::eof())
	{
		if (c == traits_type::eof()) return traits_type::not_eof(c);
		char str[2];
		str[0] = c;
		str[1] = 0;
		g_Log._Log(str);
		return c;
	}
} g_Trap;

///////////////////////////////////////////////////////////////

// There is always and only one global vtScene object
vtScene g_Scene;

vtScene::vtScene() : vtSceneBase()
{
	m_bInitialized = false;
	m_bWireframe = false;
	m_bWinInfo = false;
}

vtScene::~vtScene()
{
	if (m_pCamera)
		m_pCamera->Destroy();
}

vtScene *vtGetScene()
{
	return &g_Scene;
}

float vtGetTime()
{
	return g_Scene.GetTime();
}

float vtGetFrameTime()
{
	return g_Scene.GetFrameTime();
}

void vtScene::SetBgColor(RGBf color)
{
	Vec4 color2;
	v2s(color, color2);
	m_pOsgSceneView->setBackgroundColor(color2);
}

void vtScene::SetAmbient(RGBf color)
{
	// TODO?  Or should applications simply set the ambient component of
	// their lights.
}

bool vtScene::Init()
{
	// Redirect cout messages (where OSG sends its messages) to our own log
	std::cout.rdbuf(&g_Trap);
	std::cerr.rdbuf(&g_Trap);

	SetCamera(new vtCamera());

	m_pOsgSceneView = new osgUtil::SceneView();
	m_pOsgSceneView->setDefaults();

	// OSG 0.8.45 and before
//	m_pOsgSceneView->setCalcNearFar(false);

	// OSG 0.9.0 and newer
	m_pOsgSceneView->setComputeNearFarMode(osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR);

//	m_pOsgSceneView->setLightingMode(osgUtil::SceneView::SKY_LIGHT);
	m_pOsgSceneView->setLightingMode(osgUtil::SceneView::NO_SCENEVIEW_LIGHT);

	// OSG 0.8.45
//	osgUtil::CullVisitor *cvis = m_pOsgSceneView->getCullVisitor();
//	osgUtil::CullVisitor::CullingMode mode = cvis->getCullingMode();
//	mode &= ~(osgUtil::CullVisitor::SMALL_FEATURE_CULLING);
//	cvis->setCullingMode(mode);

	// OSG 0.9.2
	m_pOsgSceneView->setCullingMode( m_pOsgSceneView->getCullingMode() & ~osg::CullStack::SMALL_FEATURE_CULLING);

	m_bInitialized = true;

	_initialTick = _timer.tick();
	_frameTick = _initialTick;

	return true;
}

void vtScene::DoUpdate()
{
	if (!m_bInitialized)
		return;

	_lastFrameTick = _frameTick;
	_frameTick = _timer.tick();

	DoEngines();

	Camera *pOsgCam = m_pCamera->m_pOsgCamera.get();

	// let the OSG Camera know that its transform has (probably) changed
	// apparently no longer needed as of OSG 0.8.45
//	pOsgCam->dirtyTransform();

	// Copy the camera transform position to camera.  With OSG 0.9.2, we
	// used to be able to do this one call to Camera::attachTransform.
	// With 0.9.3, we have to do it each frame:
	static RefMatrix *cmat = NULL;
	if (cmat == NULL) cmat = new RefMatrix;
	Matrix &rcmat = *cmat;
	rcmat = m_pCamera->m_pTransform->getMatrix();
	pOsgCam->attachTransform(Camera::EYE_TO_MODEL, cmat);

	m_pOsgSceneView->setCamera(pOsgCam);
	m_pOsgSceneView->setViewport(0, 0, m_WindowSize.x, m_WindowSize.y);
	m_pOsgSceneView->cull();
	m_pOsgSceneView->draw();
}

void vtScene::SetRoot(vtRoot *pRoot)
{
	m_pOsgSceneRoot = pRoot->m_pOsgRoot;
	m_pOsgSceneView->setSceneData(m_pOsgSceneRoot.get());
	m_pRoot = pRoot;
}

//
// convert window coordinates (in pixels) to a ray from the camera
// in world coordinates
//
bool vtScene::CameraRay(const IPoint2 &win, FPoint3 &pos, FPoint3 &dir)
{
	Vec3 near_point, far_point, diff;

	// call the handy OSG function
	m_pOsgSceneView->projectWindowXYIntoObject(win.x, m_WindowSize.y-win.y, near_point, far_point);

	diff = far_point - near_point;
	diff.normalize();

	s2v(near_point, pos);
	s2v(diff, dir);

	return true;
}

void vtScene::DrawFrameRateChart()
{
	static float fps[100];
	static int s = 0;
	fps[s] = GetFrameRate();

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_LIGHTING);
	glColor3f(1.0f, 1.0f, 0.0f);

	glBegin(GL_LINE_STRIP);
	for (int i = 1; i <= 100; i++)
	{
		glVertex3f(-1.0 + i/200.0f, -1.0f + fps[(s+i)%100]/200.0f, 0.0f);
	}
	glEnd();

	s++;
	if (s == 100) s = 0;
}

void vtScene::SetGlobalWireframe(bool bWire)
{
	m_bWireframe = bWire;

	// Set the scene's global PolygonMode attribute, which will affect all
	// other materials in the scene, except those which explicitly override
	// the attribute themselves.
	StateSet *global_state = m_pOsgSceneView->getGlobalStateSet();
	PolygonMode *npm = new PolygonMode();
	if (m_bWireframe)
		npm->setMode(PolygonMode::FRONT_AND_BACK, PolygonMode::LINE);
	else
		npm->setMode(PolygonMode::FRONT_AND_BACK, PolygonMode::FILL);
	global_state->setAttributeAndModes(npm, StateAttribute::ON);
}

bool vtScene::GetGlobalWireframe()
{
	return m_bWireframe;
}

////////////////////////////////////////

vtNodeBase *vtLoadModel(const char *filename)
{
	// Temporary workaround for OSG OBJ-MTL reader which doesn't like
	// backslashes in the version we're using
	char newname[500];
	strcpy(newname, filename);
	for (unsigned int i = 0; i < strlen(filename); i++)
	{
		if (newname[i] == '\\') newname[i] = '/';
	}

	// We must insert a 'Normalize' state above the geometry objets
	// that we load, otherwise when they are scaled, the vertex normals
	// will cause strange lighting.  Fortunately, we only need to create
	// a single State object which is shared by all loaded models.
	static 	StateSet *normstate = NULL;
	if (!normstate)
	{
		normstate = new StateSet;
		normstate->setMode(GL_NORMALIZE, StateAttribute::ON);
	}

	Node *node = osgDB::readNodeFile(newname);
	if (node)
	{
		vtGroup *pGroup = new vtGroup();
		pGroup->SetName2(newname);
		pGroup->GetOsgGroup()->addChild(node);
		pGroup->GetOsgNode()->setStateSet(normstate);
		return pGroup;
	}
	else
		return NULL;
}

RGBf vtNodeBase::s_white(1, 1, 1);

/**
 * Set the Fog state for a node.
 *
 * You can turn fog on or off.  When you turn fog on, it affects this node
 * and all others below it in the scene graph.
 *
 * \param bOn True to turn fog on, false to turn it off.
 * \param start The distance from the camera at which fog starts, in meters.
 * \param end The distance from the camera at which fog end, in meters.  This
 *		is the point at which it becomes totally opaque.
 * \param color The color of the fog.  All geometry will be faded toward this
 *		color.
 * \param iType Can be GL_LINEAR, GL_EXP or GL_EXP2 for linear or exponential
 *		increase of the fog density.
 */
void vtNode::SetFog(bool bOn, float start, float end, const RGBf &color, int iType)
{
	osg::StateSet *set = GetOsgNode()->getStateSet();
	if (!set)
	{
		set = new osg::StateSet;
		GetOsgNode()->setStateSet(set);
	}

	if (bOn)
	{
		Fog::Mode eType;
		switch (iType)
		{
		case GL_LINEAR: eType = Fog::LINEAR; break;
		case GL_EXP: eType = Fog::EXP; break;
		case GL_EXP2: eType = Fog::EXP2; break;
		default: return;
		}
		Fog *fog = new Fog;
		fog->setMode(eType);
		fog->setDensity(0.25f);	// not used for linear
		fog->setStart(start);
		fog->setEnd(end);
		fog->setColor(osg::Vec4(color.r, color.g, color.b, 1));

		set->setAttributeAndModes(fog, StateAttribute::OVERRIDE | StateAttribute::ON);
	}
	else
	{
		// turn fog off
		set->setModeToInherit(GL_FOG);
	}
}

<commit_msg>store fog/fogstateset on node so they can be tracked and cleaned up<commit_after>//
// SceneOSG.cpp
//
// Implementation of vtScene for the OSG library
//
// Copyright (c) 2001-2003 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

#include "vtlib/vtlib.h"
#include <osg/LightSource>
#include <osg/PolygonMode>
#include <osg/Switch>
#include <osg/Fog>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <time.h>		// clock() & CLOCKS_PER_SEC

#ifdef __FreeBSD__
#  include <sys/types.h>
#  include <sys/time.h>
#  include <sys/resource.h>
#endif

#include <streambuf>
#include "vtdata/vtLog.h"

using namespace osg;

///////////////////////////////////////////////////////////////
// Trap for OSG messages
//

class OsgMsgTrap : public std::streambuf
{
public:
	inline virtual int_type overflow(int_type c = traits_type::eof())
	{
		if (c == traits_type::eof()) return traits_type::not_eof(c);
		char str[2];
		str[0] = c;
		str[1] = 0;
		g_Log._Log(str);
		return c;
	}
} g_Trap;

///////////////////////////////////////////////////////////////

// There is always and only one global vtScene object
vtScene g_Scene;

vtScene::vtScene() : vtSceneBase()
{
	m_bInitialized = false;
	m_bWireframe = false;
	m_bWinInfo = false;
}

vtScene::~vtScene()
{
	if (m_pCamera)
		m_pCamera->Destroy();
}

vtScene *vtGetScene()
{
	return &g_Scene;
}

float vtGetTime()
{
	return g_Scene.GetTime();
}

float vtGetFrameTime()
{
	return g_Scene.GetFrameTime();
}

void vtScene::SetBgColor(RGBf color)
{
	Vec4 color2;
	v2s(color, color2);
	m_pOsgSceneView->setBackgroundColor(color2);
}

void vtScene::SetAmbient(RGBf color)
{
	// TODO?  Or should applications simply set the ambient component of
	// their lights.
}

bool vtScene::Init()
{
	// Redirect cout messages (where OSG sends its messages) to our own log
	std::cout.rdbuf(&g_Trap);
	std::cerr.rdbuf(&g_Trap);

	SetCamera(new vtCamera());

	m_pOsgSceneView = new osgUtil::SceneView();
	m_pOsgSceneView->setDefaults();

	// OSG 0.8.45 and before
//	m_pOsgSceneView->setCalcNearFar(false);

	// OSG 0.9.0 and newer
	m_pOsgSceneView->setComputeNearFarMode(osgUtil::CullVisitor::DO_NOT_COMPUTE_NEAR_FAR);

//	m_pOsgSceneView->setLightingMode(osgUtil::SceneView::SKY_LIGHT);
	m_pOsgSceneView->setLightingMode(osgUtil::SceneView::NO_SCENEVIEW_LIGHT);

	// OSG 0.8.45
//	osgUtil::CullVisitor *cvis = m_pOsgSceneView->getCullVisitor();
//	osgUtil::CullVisitor::CullingMode mode = cvis->getCullingMode();
//	mode &= ~(osgUtil::CullVisitor::SMALL_FEATURE_CULLING);
//	cvis->setCullingMode(mode);

	// OSG 0.9.2
	m_pOsgSceneView->setCullingMode( m_pOsgSceneView->getCullingMode() & ~osg::CullStack::SMALL_FEATURE_CULLING);

	m_bInitialized = true;

	_initialTick = _timer.tick();
	_frameTick = _initialTick;

	return true;
}

void vtScene::DoUpdate()
{
	if (!m_bInitialized)
		return;

	_lastFrameTick = _frameTick;
	_frameTick = _timer.tick();

	DoEngines();

	Camera *pOsgCam = m_pCamera->m_pOsgCamera.get();

	// let the OSG Camera know that its transform has (probably) changed
	// apparently no longer needed as of OSG 0.8.45
//	pOsgCam->dirtyTransform();

	// Copy the camera transform position to camera.  With OSG 0.9.2, we
	// used to be able to do this one call to Camera::attachTransform.
	// With 0.9.3, we have to do it each frame:
	static RefMatrix *cmat = NULL;
	if (cmat == NULL) cmat = new RefMatrix;
	Matrix &rcmat = *cmat;
	rcmat = m_pCamera->m_pTransform->getMatrix();
	pOsgCam->attachTransform(Camera::EYE_TO_MODEL, cmat);

	m_pOsgSceneView->setCamera(pOsgCam);
	m_pOsgSceneView->setViewport(0, 0, m_WindowSize.x, m_WindowSize.y);
	m_pOsgSceneView->cull();
	m_pOsgSceneView->draw();
}

void vtScene::SetRoot(vtRoot *pRoot)
{
	m_pOsgSceneRoot = pRoot->m_pOsgRoot;
	m_pOsgSceneView->setSceneData(m_pOsgSceneRoot.get());
	m_pRoot = pRoot;
}

//
// convert window coordinates (in pixels) to a ray from the camera
// in world coordinates
//
bool vtScene::CameraRay(const IPoint2 &win, FPoint3 &pos, FPoint3 &dir)
{
	Vec3 near_point, far_point, diff;

	// call the handy OSG function
	m_pOsgSceneView->projectWindowXYIntoObject(win.x, m_WindowSize.y-win.y, near_point, far_point);

	diff = far_point - near_point;
	diff.normalize();

	s2v(near_point, pos);
	s2v(diff, dir);

	return true;
}

void vtScene::DrawFrameRateChart()
{
	static float fps[100];
	static int s = 0;
	fps[s] = GetFrameRate();

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glDisable(GL_TEXTURE_2D);
	glDisable(GL_LIGHTING);
	glColor3f(1.0f, 1.0f, 0.0f);

	glBegin(GL_LINE_STRIP);
	for (int i = 1; i <= 100; i++)
	{
		glVertex3f(-1.0 + i/200.0f, -1.0f + fps[(s+i)%100]/200.0f, 0.0f);
	}
	glEnd();

	s++;
	if (s == 100) s = 0;
}

void vtScene::SetGlobalWireframe(bool bWire)
{
	m_bWireframe = bWire;

	// Set the scene's global PolygonMode attribute, which will affect all
	// other materials in the scene, except those which explicitly override
	// the attribute themselves.
	StateSet *global_state = m_pOsgSceneView->getGlobalStateSet();
	PolygonMode *npm = new PolygonMode();
	if (m_bWireframe)
		npm->setMode(PolygonMode::FRONT_AND_BACK, PolygonMode::LINE);
	else
		npm->setMode(PolygonMode::FRONT_AND_BACK, PolygonMode::FILL);
	global_state->setAttributeAndModes(npm, StateAttribute::ON);
}

bool vtScene::GetGlobalWireframe()
{
	return m_bWireframe;
}

////////////////////////////////////////

vtNodeBase *vtLoadModel(const char *filename)
{
	// Temporary workaround for OSG OBJ-MTL reader which doesn't like
	// backslashes in the version we're using
	char newname[500];
	strcpy(newname, filename);
	for (unsigned int i = 0; i < strlen(filename); i++)
	{
		if (newname[i] == '\\') newname[i] = '/';
	}

	// We must insert a 'Normalize' state above the geometry objets
	// that we load, otherwise when they are scaled, the vertex normals
	// will cause strange lighting.  Fortunately, we only need to create
	// a single State object which is shared by all loaded models.
	static 	StateSet *normstate = NULL;
	if (!normstate)
	{
		normstate = new StateSet;
		normstate->setMode(GL_NORMALIZE, StateAttribute::ON);
	}

	Node *node = osgDB::readNodeFile(newname);
	if (node)
	{
		vtGroup *pGroup = new vtGroup();
		pGroup->SetName2(newname);
		pGroup->GetOsgGroup()->addChild(node);
		pGroup->GetOsgNode()->setStateSet(normstate);
		return pGroup;
	}
	else
		return NULL;
}

RGBf vtNodeBase::s_white(1, 1, 1);

/**
 * Set the Fog state for a node.
 *
 * You can turn fog on or off.  When you turn fog on, it affects this node
 * and all others below it in the scene graph.
 *
 * \param bOn True to turn fog on, false to turn it off.
 * \param start The distance from the camera at which fog starts, in meters.
 * \param end The distance from the camera at which fog end, in meters.  This
 *		is the point at which it becomes totally opaque.
 * \param color The color of the fog.  All geometry will be faded toward this
 *		color.
 * \param iType Can be GL_LINEAR, GL_EXP or GL_EXP2 for linear or exponential
 *		increase of the fog density.
 */
void vtNode::SetFog(bool bOn, float start, float end, const RGBf &color, int iType)
{
	osg::StateSet *set = GetOsgNode()->getStateSet();
	if (!set)
	{
		m_pFogStateSet = new osg::StateSet;
		set = m_pFogStateSet.get();
		GetOsgNode()->setStateSet(set);
	}

	if (bOn)
	{
		Fog::Mode eType;
		switch (iType)
		{
		case GL_LINEAR: eType = Fog::LINEAR; break;
		case GL_EXP: eType = Fog::EXP; break;
		case GL_EXP2: eType = Fog::EXP2; break;
		default: return;
		}
		m_pFog = new Fog;
		m_pFog->setMode(eType);
		m_pFog->setDensity(0.25f);	// not used for linear
		m_pFog->setStart(start);
		m_pFog->setEnd(end);
		m_pFog->setColor(osg::Vec4(color.r, color.g, color.b, 1));

		set->setAttributeAndModes(m_pFog.get(), StateAttribute::OVERRIDE | StateAttribute::ON);
	}
	else
	{
		// turn fog off
		set->setModeToInherit(GL_FOG);
	}
}

<|endoftext|>


<commit_before>#ifndef IMAP__H__
#define IMAP__H__

#include "zip.hpp"

#include <utility>
#include <type_traits>

namespace iter {

    // Everything in detail namespace
    // modified from http://stackoverflow.com/questions/10766112/
    // Question by Thomas http://stackoverflow.com/users/115355/thomas
    // Answer by Kerrek SB http://stackoverflow.com/users/596781/kerrek-sb
    namespace detail
    {
        // implementation details, users never invoke these directly
        template <typename F, typename Tuple, bool Done, int Total, int... N>
        struct call_impl
        {
            static auto call(F f, Tuple&& t) ->
                decltype(call_impl<F,
                    Tuple,
                    Total == 1 + sizeof...(N),
                    Total,
                    N...,
                    sizeof...(N)>::call(f, std::forward<Tuple>(t)))
            {
                return call_impl<F,
                    Tuple,
                    Total == 1 + sizeof...(N),
                    Total,
                    N...,
                    sizeof...(N)>::call(f, std::forward<Tuple>(t));
            }
        };

        template <typename F, typename Tuple, int Total, int... N>
        struct call_impl<F, Tuple, true, Total, N...>
        {
            static auto call(F f, Tuple&& t) ->
                decltype(f(std::get<N>(std::forward<Tuple>(t))...))
            {
                return f(std::get<N>(std::forward<Tuple>(t))...);
            }
        };

        // user invokes this
        template <typename F, typename Tuple>
        auto call(F f, Tuple&& t) ->
            decltype(call_impl<F,
                Tuple,
                0 == std::tuple_size<typename std::decay<Tuple>::type>::value,
                std::tuple_size<typename std::decay<Tuple>::type>::value>
                ::call(f,std::forward<Tuple>(t)))
        {
            typedef typename std::decay<Tuple>::type ttype;
            return call_impl<F,
                Tuple,
                0 == std::tuple_size<ttype>::value,
                std::tuple_size<ttype>::value>::call(f,std::forward<Tuple>(t));
        }
    }

    //Forward declarations of IMap and imap
    template <typename MapFunc, typename... Containers>
    class IMap;

    template <typename MapFunc, typename... Containers>
    IMap<MapFunc, Containers...> imap(MapFunc, Containers&&...);

    template <typename MapFunc, typename... Containers>
    class IMap {
        // The imap function is the only thing allowed to create a IMap
        friend IMap imap<MapFunc, Containers...>(MapFunc, Containers&& ...);

        using ZippedIterType = iterator_type<Zipped<Containers...>>;
        private:
            MapFunc map_func;
            Zipped<Containers...> zipped;

            // Value constructor for use only in the imap function
            IMap(MapFunc map_func, Containers&& ... containers) :
                map_func(map_func),
                zipped(zip(std::forward<Containers>(containers)...))
            { }
            IMap() = delete;
            IMap& operator=(const IMap&) = delete;

        public:
            IMap(const IMap&) = default;

            class Iterator {
                private:
                    MapFunc map_func;
                    mutable ZippedIterType zipiter;

                public:
                    Iterator(MapFunc map_func, ZippedIterType zipiter) :
                        map_func(map_func),
                        zipiter(zipiter)
                    { }

                    auto operator*() const ->
                        decltype(detail::call(this->map_func, *(this->zipiter)))
                    {
                        return detail::call(this->map_func, *(this->zipiter));
                    }

                    Iterator& operator++() {
                        ++this->zipiter;
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->zipiter != other.zipiter;
                    }
            };

            Iterator begin() {
                return {this->map_func, this->zipped.begin()};
            }

            Iterator end() {
                return {this->map_func, this->zipped.end()};
            }

    };

    // Helper function to instantiate a IMap
    template <typename MapFunc, typename... Containers>
    IMap<MapFunc, Containers...> imap(
            MapFunc map_func, Containers&& ... containers) {
        return {map_func, std::forward<Containers>(containers)...};
    }

}

#endif //ifndef IMAP__H__
<commit_msg>replaces SO explosion implementation<commit_after>#ifndef IMAP__H__
#define IMAP__H__

#include "zip.hpp"

#include <utility>
#include <type_traits>

namespace iter {

    namespace detail {

    template <std::size_t Index, typename Functor, typename Tup>
    struct Expander {
        template <typename... Ts>
        static auto call(Functor&& f, Tup&& tup, Ts&&... args)
            -> decltype(Expander<Index-1, Functor, Tup>::call(
                    std::forward<Functor>(f),
                    std::forward<Tup>(tup),
                    std::get<Index-1>(tup),
                    std::forward<Ts>(args)...))
        {
            // recurse
            return Expander<Index-1, Functor, Tup>::call(
                    std::forward<Functor>(f),
                    std::forward<Tup>(tup),
                    std::get<Index-1>(tup), // pull out one element
                    std::forward<Ts>(args)...); // everything already expanded
        }
    };

    template <typename Functor, typename Tup>
    struct Expander<0, Functor, Tup> {
        template <typename... Ts>
        static auto call(Functor&& f, Tup&&, Ts&&... args)
            -> decltype(f(std::forward<Ts>(args)...))
        {
            static_assert(
                std::tuple_size<
                    typename std::remove_reference<Tup>::type>::value
                    == sizeof...(Ts),
                "tuple has not been fully expanded");
            return f(std::forward<Ts>(args)...); // the actual call
        }
    };

    template <typename Functor, typename Tup>
    auto call_with_tuple(Functor&& f, Tup&& tup)
        -> decltype(Expander<std::tuple_size<
                    typename std::remove_reference<Tup>::type>::value,
                    Functor, Tup>::call(
                        std::forward<Functor>(f),
                        std::forward<Tup>(tup)))
    {
        return Expander<std::tuple_size<
            typename std::remove_reference<Tup>::type>::value,
            Functor, Tup>::call(
                std::forward<Functor>(f),
                std::forward<Tup>(tup));
    }

    } // end detail

    //Forward declarations of IMap and imap
    template <typename MapFunc, typename... Containers>
    class IMap;

    template <typename MapFunc, typename... Containers>
    IMap<MapFunc, Containers...> imap(MapFunc, Containers&&...);

    template <typename MapFunc, typename... Containers>
    class IMap {
        // The imap function is the only thing allowed to create a IMap
        friend IMap imap<MapFunc, Containers...>(MapFunc, Containers&& ...);

        using ZippedIterType = iterator_type<Zipped<Containers...>>;
        private:
            MapFunc map_func;
            Zipped<Containers...> zipped;

            // Value constructor for use only in the imap function
            IMap(MapFunc map_func, Containers&& ... containers) :
                map_func(map_func),
                zipped(zip(std::forward<Containers>(containers)...))
            { }
            IMap() = delete;
            IMap& operator=(const IMap&) = delete;

        public:
            IMap(const IMap&) = default;

            class Iterator {
                private:
                    MapFunc map_func;
                    mutable ZippedIterType zipiter;

                public:
                    Iterator(MapFunc map_func, ZippedIterType zipiter) :
                        map_func(map_func),
                        zipiter(zipiter)
                    { }

                    auto operator*() const ->
                        decltype(detail::call_with_tuple(
                                    this->map_func, *(this->zipiter)))
                    {
                        return detail::call_with_tuple(
                                this->map_func, *(this->zipiter));
                    }

                    Iterator& operator++() {
                        ++this->zipiter;
                        return *this;
                    }

                    bool operator!=(const Iterator& other) const {
                        return this->zipiter != other.zipiter;
                    }
            };

            Iterator begin() {
                return {this->map_func, this->zipped.begin()};
            }

            Iterator end() {
                return {this->map_func, this->zipped.end()};
            }

    };

    // Helper function to instantiate a IMap
    template <typename MapFunc, typename... Containers>
    IMap<MapFunc, Containers...> imap(
            MapFunc map_func, Containers&& ... containers) {
        return {map_func, std::forward<Containers>(containers)...};
    }

}

#endif //ifndef IMAP__H__
<|endoftext|>


<commit_before>//=============================================================================================================
/**
* @file     measurement.cpp
* @author   Christoph Dinh <chdinh@nmr.mgh.harvard.edu>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     February, 2013
*
* @section  LICENSE
*
* Copyright (C) 2013, Christoph Dinh and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of the Massachusetts General Hospital 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 MASSACHUSETTS GENERAL HOSPITAL 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.
*
*
* @brief    Contains the implementation of the Measurement base class.
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "measurement.h"
#include <generics/observerpattern.h>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace XMEASLIB;

//*************************************************************************************************************
//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

Measurement::Measurement(bool p_pIsSingleChannel)
: Subject()
, m_qString_Name("")
//, m_MDL_ID(MDL_ID::_default)
, m_MSR_ID(MSR_ID::_default)
, m_bVisibility(true)
, m_MDL_ID_new(MDL_ID::_default)
, m_iMSR_idx(-1)
, m_bIsSingleChannel(p_pIsSingleChannel)
{

}

//*************************************************************************************************************

Measurement::~Measurement()
{

}
<commit_msg>single channel measurement dynamic_cast option<commit_after>//=============================================================================================================
/**
* @file     measurement.cpp
* @author   Christoph Dinh <chdinh@nmr.mgh.harvard.edu>;
*           Matti Hamalainen <msh@nmr.mgh.harvard.edu>
* @version  1.0
* @date     February, 2013
*
* @section  LICENSE
*
* Copyright (C) 2013, Christoph Dinh and Matti Hamalainen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that
* the following conditions are met:
*     * Redistributions of source code must retain the above copyright notice, this list of conditions and the
*       following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
*       the following disclaimer in the documentation and/or other materials provided with the distribution.
*     * Neither the name of the Massachusetts General Hospital 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 MASSACHUSETTS GENERAL HOSPITAL 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.
*
*
* @brief    Contains the implementation of the Measurement base class.
*
*/

//*************************************************************************************************************
//=============================================================================================================
// INCLUDES
//=============================================================================================================

#include "measurement.h"
#include <generics/observerpattern.h>

//*************************************************************************************************************
//=============================================================================================================
// USED NAMESPACES
//=============================================================================================================

using namespace XMEASLIB;

//*************************************************************************************************************
//=============================================================================================================
// DEFINE MEMBER METHODS
//=============================================================================================================

Measurement::Measurement(bool p_pIsSingleChannel)
: Subject()
, m_qString_Name("")
//, m_MDL_ID(MDL_ID::_default)
, m_MSR_ID(MSR_ID::_default)
, m_bVisibility(true)
, m_MDL_ID_new(MDL_ID::_default)
, m_iMSR_idx(-1)
, m_bIsSingleChannel(p_pIsSingleChannel)
{

}

//*************************************************************************************************************

Measurement::~Measurement()
{

}

////*************************************************************************************************************

//bool Measurement::isSingleChannel()
//{
//    MltChnMeasurement* pSngChnMeasurement = NULL;
//    pSngChnMeasurement = dynamic_cast<MltChnMeasurement*>(this);

//    if(pSngChnMeasurement == NULL)
//        return false;
//    else
//        return true;
//}
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2012-2021 Inviwo Foundation
 * All rights reserved.
 *
 * 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.
 *
 * 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.
 *
 *********************************************************************************/

#include <modules/qtwidgets/propertylistwidget.h>

#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/properties/propertywidgetfactory.h>
#include <inviwo/core/processors/processor.h>
#include <inviwo/core/network/processornetwork.h>
#include <inviwo/core/network/processornetworkevaluator.h>
#include <inviwo/core/properties/propertywidgetfactory.h>
#include <inviwo/core/util/rendercontext.h>

#include <modules/qtwidgets/properties/collapsiblegroupboxwidgetqt.h>
#include <modules/qtwidgets/properties/propertywidgetqt.h>

#include <modules/qtwidgets/inviwoqtutils.h>
#include <warn/push>
#include <warn/ignore/all>
#include <QLabel>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QSignalMapper>
#include <QSettings>
#include <QStyle>
#include <QStyleOption>
#include <QPainter>
#include <warn/pop>

namespace inviwo {

PropertyListFrame::PropertyListFrame(QWidget* parent, PropertyWidgetFactory* factory)
    : QWidget(parent), listLayout_{new QVBoxLayout()}, factory_{factory} {

    QSizePolicy sp(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
    sp.setVerticalStretch(0);
    sp.setHorizontalStretch(1);
    QWidget::setSizePolicy(sp);

    setLayout(listLayout_);

    const auto space = utilqt::refSpacePx(this);
    listLayout_->setAlignment(Qt::AlignTop);
#ifdef __APPLE__
    // Add some space for the scrollbar on mac
    listLayout_->setContentsMargins(0, space, 10, space);
#else
    listLayout_->setContentsMargins(0, space, 0, space);
#endif
    listLayout_->setSpacing(space);
    listLayout_->setSizeConstraint(QLayout::SetMinAndMaxSize);
}

QSize PropertyListFrame::sizeHint() const {
    QSize size = layout()->minimumSize();
    size.setHeight(parentWidget()->width());
    return size;
}

QSize PropertyListFrame::minimumSizeHint() const {
    QSize size = layout()->minimumSize();
    size.setWidth(parentWidget()->width());
    return size;
}

void PropertyListFrame::paintEvent(QPaintEvent*) {
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

void PropertyListFrame::add(Processor* processor) {
    setUpdatesEnabled(false);
    listLayout_->setEnabled(false);
    util::OnScopeExit enableUpdates([&]() {
        listLayout_->setEnabled(true);
        setUpdatesEnabled(true);
    });

    if (auto widget = get(processor)) {
        widget->show();
    }
}

void PropertyListFrame::hide(Processor* processor) {
    auto it = processorMap_.find(processor);
    if (it != processorMap_.end()) it->second->hide();
}

void PropertyListFrame::remove(Processor* processor) {
    auto it = processorMap_.find(processor);
    if (it != processorMap_.end()) {
        it->second->hide();
        listLayout_->removeWidget(it->second);
        delete it->second;
        processorMap_.erase(it);
    }
}

void PropertyListFrame::add(Property* property) {
    setUpdatesEnabled(false);
    listLayout_->setEnabled(false);
    util::OnScopeExit enableUpdates([&]() {
        listLayout_->setEnabled(true);
        setUpdatesEnabled(true);
    });

    if (auto widget = get(property)) {
        widget->show();
    }
}
void PropertyListFrame::hide(Property* property) {
    auto it = propertyMap_.find(property);
    if (it != propertyMap_.end()) it->second->hide();
}
void PropertyListFrame::remove(Property* property) {
    auto it = propertyMap_.find(property);
    if (it != propertyMap_.end()) {
        it->second->hide();
        listLayout_->removeWidget(it->second);
        delete it->second;
        propertyMap_.erase(it);
    }
}

void PropertyListFrame::clear() {
    for (auto&& [p, w] : processorMap_) {
        w->hide();
        listLayout_->removeWidget(w);
        delete w;
    }
    processorMap_.clear();

    for (auto&& [p, w] : propertyMap_) {
        w->hide();
        listLayout_->removeWidget(w);
        delete w;
    }
    propertyMap_.clear();
}

QWidget* PropertyListFrame::get(Processor* processor) {
    // check if processor widget has been already generated
    auto it = processorMap_.find(processor);
    if (it != processorMap_.end()) {
        return it->second;
    } else {
        return create(processor);
    }
}

QWidget* PropertyListFrame::create(Processor* processor) {
    // create property widget and store it in the map
    auto widget = new CollapsibleGroupBoxWidgetQt(processor);
    widget->hide();
    listLayout_->insertWidget(-1, widget, 0, Qt::AlignTop);
    for (auto prop : processor->getProperties()) {
        widget->addProperty(prop);
    }
    processorMap_[processor] = widget;
    processor->getNetwork()->addObserver(this);
    return widget;
}

QWidget* PropertyListFrame::get(Property* property) {
    // check if processor widget has been already generated
    auto it = propertyMap_.find(property);
    if (it != propertyMap_.end()) {
        return it->second;
    } else {
        return create(property);
    }
}
QWidget* PropertyListFrame::create(Property* property) {
    // create property widget and store it in the map
    if (auto widget = static_cast<PropertyWidgetQt*>(factory_->create(property).release())) {
        widget->hide();
        listLayout_->insertWidget(-1, widget, 0, Qt::AlignTop);
        widget->initState();
        propertyMap_[property] = widget;
        property->getOwner()->addObserver(this);
        RenderContext::getPtr()->activateDefaultRenderContext();
        return widget;
    }
    return nullptr;
}

void PropertyListFrame::onProcessorNetworkWillRemoveProcessor(Processor* processor) {
    remove(processor);
}
void PropertyListFrame::onWillRemoveProperty(Property* property, size_t) { remove(property); }

PropertyListWidget::PropertyListWidget(QWidget* parent, InviwoApplication* app)
    : InviwoDockWidget(tr("Properties"), parent, "PropertyListWidget"), app_{app} {

    setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
    resize(utilqt::emToPx(this, QSizeF(45, 80)));  // default size

    QSizePolicy sp(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
    sp.setVerticalStretch(1);
    sp.setHorizontalStretch(1);
    setSizePolicy(sp);

    const auto space = utilqt::refSpacePx(this);

    scrollArea_ = new QScrollArea(this);
    scrollArea_->setWidgetResizable(true);
    scrollArea_->setMinimumWidth(utilqt::emToPx(this, 30));
    scrollArea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
#ifdef __APPLE__
    // Scrollbars are overlayed in different way on mac...
    scrollArea_->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
#else
    scrollArea_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
#endif
    scrollArea_->setFrameShape(QFrame::NoFrame);
    scrollArea_->setContentsMargins(0, space, 0, space);

    frame_ = new PropertyListFrame(this, app->getPropertyWidgetFactory());
    scrollArea_->setWidget(frame_);
    setWidget(scrollArea_);

    app->getProcessorNetworkEvaluator()->addObserver(this);
}

PropertyListWidget::~PropertyListWidget() = default;

void PropertyListWidget::addProcessorProperties(Processor* processor) {
    frame_->add(processor);
    QWidget::raise();  // Put this tab in front
}

void PropertyListWidget::removeProcessorProperties(Processor* processor) {
    frame_->hide(processor);
}

void PropertyListWidget::removeAndDeleteProcessorProperties(Processor* processor) {
    frame_->remove(processor);
}

void PropertyListWidget::addPropertyWidgets(Property* property) {
    frame_->add(property);
    QWidget::raise();  // Put this tab in front
}
void PropertyListWidget::removePropertyWidgets(Property* property) { frame_->hide(property); }
void PropertyListWidget::removeAndDeletePropertyWidgets(Property* property) {
    frame_->remove(property);
}

bool PropertyListWidget::event(QEvent* e) {
    // The network editor will post these events.
    if (e->type() == PropertyListEvent::type()) {
        PropertyListEvent* ple = static_cast<PropertyListEvent*>(e);
        ple->accept();

        auto nw = app_->getProcessorNetwork();
        Processor* p(nw->getProcessorByIdentifier(ple->processorId_));
        if (!p) return true;

        switch (ple->action_) {
            case PropertyListEvent::Action::Add: {
                addProcessorProperties(p);
                break;
            }
            case PropertyListEvent::Action::Remove: {
                removeProcessorProperties(p);
                break;
            }
        }
        return true;

    } else {
        return InviwoDockWidget::event(e);
    }
}

void PropertyListWidget::onProcessorNetworkEvaluationBegin() {
    setUpdatesEnabled(false);
    frame_->setEnabled(false);
}

void PropertyListWidget::onProcessorNetworkEvaluationEnd() {
    frame_->setEnabled(true);
    setUpdatesEnabled(true);
}

PropertyListEvent::PropertyListEvent(Action action, std::string processorId)
    : QEvent(PropertyListEvent::type()), action_(action), processorId_(processorId) {}

QEvent::Type PropertyListEvent::type() {
    if (PropertyListEventType == QEvent::None) {
        PropertyListEventType = static_cast<QEvent::Type>(QEvent::registerEventType());
    }
    return PropertyListEventType;
}

QEvent::Type PropertyListEvent::PropertyListEventType = QEvent::None;

}  // namespace inviwo
<commit_msg>QtWidgets: focus fix<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2012-2021 Inviwo Foundation
 * All rights reserved.
 *
 * 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.
 *
 * 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.
 *
 *********************************************************************************/

#include <modules/qtwidgets/propertylistwidget.h>

#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/properties/propertywidgetfactory.h>
#include <inviwo/core/processors/processor.h>
#include <inviwo/core/network/processornetwork.h>
#include <inviwo/core/network/processornetworkevaluator.h>
#include <inviwo/core/properties/propertywidgetfactory.h>
#include <inviwo/core/util/rendercontext.h>

#include <modules/qtwidgets/properties/collapsiblegroupboxwidgetqt.h>
#include <modules/qtwidgets/properties/propertywidgetqt.h>

#include <modules/qtwidgets/inviwoqtutils.h>
#include <warn/push>
#include <warn/ignore/all>
#include <QLabel>
#include <QScrollArea>
#include <QVBoxLayout>
#include <QSignalMapper>
#include <QSettings>
#include <QStyle>
#include <QStyleOption>
#include <QPainter>
#include <warn/pop>

namespace inviwo {

PropertyListFrame::PropertyListFrame(QWidget* parent, PropertyWidgetFactory* factory)
    : QWidget(parent), listLayout_{new QVBoxLayout()}, factory_{factory} {

    QSizePolicy sp(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
    sp.setVerticalStretch(0);
    sp.setHorizontalStretch(1);
    QWidget::setSizePolicy(sp);

    setLayout(listLayout_);

    const auto space = utilqt::refSpacePx(this);
    listLayout_->setAlignment(Qt::AlignTop);
#ifdef __APPLE__
    // Add some space for the scrollbar on mac
    listLayout_->setContentsMargins(0, space, 10, space);
#else
    listLayout_->setContentsMargins(0, space, 0, space);
#endif
    listLayout_->setSpacing(space);
    listLayout_->setSizeConstraint(QLayout::SetMinAndMaxSize);
}

QSize PropertyListFrame::sizeHint() const {
    QSize size = layout()->minimumSize();
    size.setHeight(parentWidget()->width());
    return size;
}

QSize PropertyListFrame::minimumSizeHint() const {
    QSize size = layout()->minimumSize();
    size.setWidth(parentWidget()->width());
    return size;
}

void PropertyListFrame::paintEvent(QPaintEvent*) {
    QStyleOption opt;
    opt.initFrom(this);
    QPainter p(this);
    style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
}

void PropertyListFrame::add(Processor* processor) {
    setUpdatesEnabled(false);
    listLayout_->setEnabled(false);
    util::OnScopeExit enableUpdates([&]() {
        listLayout_->setEnabled(true);
        setUpdatesEnabled(true);
    });

    if (auto widget = get(processor)) {
        widget->show();
    }
}

void PropertyListFrame::hide(Processor* processor) {
    auto it = processorMap_.find(processor);
    if (it != processorMap_.end()) it->second->hide();
}

void PropertyListFrame::remove(Processor* processor) {
    auto it = processorMap_.find(processor);
    if (it != processorMap_.end()) {
        it->second->hide();
        listLayout_->removeWidget(it->second);
        delete it->second;
        processorMap_.erase(it);
    }
}

void PropertyListFrame::add(Property* property) {
    setUpdatesEnabled(false);
    listLayout_->setEnabled(false);
    util::OnScopeExit enableUpdates([&]() {
        listLayout_->setEnabled(true);
        setUpdatesEnabled(true);
    });

    if (auto widget = get(property)) {
        widget->show();
    }
}
void PropertyListFrame::hide(Property* property) {
    auto it = propertyMap_.find(property);
    if (it != propertyMap_.end()) it->second->hide();
}
void PropertyListFrame::remove(Property* property) {
    auto it = propertyMap_.find(property);
    if (it != propertyMap_.end()) {
        it->second->hide();
        listLayout_->removeWidget(it->second);
        delete it->second;
        propertyMap_.erase(it);
    }
}

void PropertyListFrame::clear() {
    for (auto&& [p, w] : processorMap_) {
        w->hide();
        listLayout_->removeWidget(w);
        delete w;
    }
    processorMap_.clear();

    for (auto&& [p, w] : propertyMap_) {
        w->hide();
        listLayout_->removeWidget(w);
        delete w;
    }
    propertyMap_.clear();
}

QWidget* PropertyListFrame::get(Processor* processor) {
    // check if processor widget has been already generated
    auto it = processorMap_.find(processor);
    if (it != processorMap_.end()) {
        return it->second;
    } else {
        return create(processor);
    }
}

QWidget* PropertyListFrame::create(Processor* processor) {
    // create property widget and store it in the map
    auto widget = new CollapsibleGroupBoxWidgetQt(processor);
    widget->hide();
    listLayout_->insertWidget(-1, widget, 0, Qt::AlignTop);
    for (auto prop : processor->getProperties()) {
        widget->addProperty(prop);
    }
    processorMap_[processor] = widget;
    processor->getNetwork()->addObserver(this);
    return widget;
}

QWidget* PropertyListFrame::get(Property* property) {
    // check if processor widget has been already generated
    auto it = propertyMap_.find(property);
    if (it != propertyMap_.end()) {
        return it->second;
    } else {
        return create(property);
    }
}
QWidget* PropertyListFrame::create(Property* property) {
    // create property widget and store it in the map
    if (auto widget = static_cast<PropertyWidgetQt*>(factory_->create(property).release())) {
        widget->hide();
        listLayout_->insertWidget(-1, widget, 0, Qt::AlignTop);
        widget->initState();
        propertyMap_[property] = widget;
        property->getOwner()->addObserver(this);
        RenderContext::getPtr()->activateDefaultRenderContext();
        return widget;
    }
    return nullptr;
}

void PropertyListFrame::onProcessorNetworkWillRemoveProcessor(Processor* processor) {
    remove(processor);
}
void PropertyListFrame::onWillRemoveProperty(Property* property, size_t) { remove(property); }

PropertyListWidget::PropertyListWidget(QWidget* parent, InviwoApplication* app)
    : InviwoDockWidget(tr("Properties"), parent, "PropertyListWidget"), app_{app} {

    setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
    resize(utilqt::emToPx(this, QSizeF(45, 80)));  // default size

    QSizePolicy sp(QSizePolicy::Fixed, QSizePolicy::MinimumExpanding);
    sp.setVerticalStretch(1);
    sp.setHorizontalStretch(1);
    setSizePolicy(sp);

    const auto space = utilqt::refSpacePx(this);

    scrollArea_ = new QScrollArea(this);
    scrollArea_->setWidgetResizable(true);
    scrollArea_->setMinimumWidth(utilqt::emToPx(this, 30));
    scrollArea_->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
#ifdef __APPLE__
    // Scrollbars are overlayed in different way on mac...
    scrollArea_->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
#else
    scrollArea_->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
#endif
    scrollArea_->setFrameShape(QFrame::NoFrame);
    scrollArea_->setContentsMargins(0, space, 0, space);

    frame_ = new PropertyListFrame(this, app->getPropertyWidgetFactory());
    scrollArea_->setWidget(frame_);
    setWidget(scrollArea_);

    app->getProcessorNetworkEvaluator()->addObserver(this);
}

PropertyListWidget::~PropertyListWidget() = default;

void PropertyListWidget::addProcessorProperties(Processor* processor) {
    frame_->add(processor);
    QWidget::raise();  // Put this tab in front
}

void PropertyListWidget::removeProcessorProperties(Processor* processor) {
    frame_->hide(processor);
}

void PropertyListWidget::removeAndDeleteProcessorProperties(Processor* processor) {
    frame_->remove(processor);
}

void PropertyListWidget::addPropertyWidgets(Property* property) {
    frame_->add(property);
    QWidget::raise();  // Put this tab in front
}
void PropertyListWidget::removePropertyWidgets(Property* property) { frame_->hide(property); }
void PropertyListWidget::removeAndDeletePropertyWidgets(Property* property) {
    frame_->remove(property);
}

bool PropertyListWidget::event(QEvent* e) {
    // The network editor will post these events.
    if (e->type() == PropertyListEvent::type()) {
        PropertyListEvent* ple = static_cast<PropertyListEvent*>(e);
        ple->accept();

        auto nw = app_->getProcessorNetwork();
        Processor* p(nw->getProcessorByIdentifier(ple->processorId_));
        if (!p) return true;

        switch (ple->action_) {
            case PropertyListEvent::Action::Add: {
                addProcessorProperties(p);
                break;
            }
            case PropertyListEvent::Action::Remove: {
                removeProcessorProperties(p);
                break;
            }
        }
        return true;

    } else {
        return InviwoDockWidget::event(e);
    }
}

void PropertyListWidget::onProcessorNetworkEvaluationBegin() { setUpdatesEnabled(false); }

void PropertyListWidget::onProcessorNetworkEvaluationEnd() { setUpdatesEnabled(true); }

PropertyListEvent::PropertyListEvent(Action action, std::string processorId)
    : QEvent(PropertyListEvent::type()), action_(action), processorId_(processorId) {}

QEvent::Type PropertyListEvent::type() {
    if (PropertyListEventType == QEvent::None) {
        PropertyListEventType = static_cast<QEvent::Type>(QEvent::registerEventType());
    }
    return PropertyListEventType;
}

QEvent::Type PropertyListEvent::PropertyListEventType = QEvent::None;

}  // namespace inviwo
<|endoftext|>


<commit_before>/*****************************************************************\
           __
          / /
		 / /                     __  __
		/ /______    _______    / / / / ________   __       __
	   / ______  \  /_____  \  / / / / / _____  | / /      / /
	  / /      | / _______| / / / / / / /____/ / / /      / /
	 / /      / / / _____  / / / / / / _______/ / /      / /
	/ /      / / / /____/ / / / / / / |______  / |______/ /
   /_/      /_/ |________/ / / / /  \_______/  \_______  /
                          /_/ /_/                     / /
			                                         / /
		       High Level Game Framework            /_/

  ---------------------------------------------------------------

  Copyright (c) 2007-2011 - Rodrigo Braz Monteiro.
  This file is subject to the terms of halley_license.txt.

\*****************************************************************/

#include "input/input_virtual.h"
#include "input/input_manual.h"
#include <set>
#include <algorithm>

using namespace Halley;

InputVirtual::InputVirtual(int nButtons, int nAxes)
	: lastDeviceFrozen(false)
	, repeatDelayFirst(0.20f)
	, repeatDelayHold(0.10f)
{
	buttons.resize(nButtons);
	axes.resize(nAxes);
}

bool InputVirtual::isEnabled() const
{
	for (auto& d: getAllDevices()) {
		if (d->isEnabled()) {
			return true;
		}
	}
	return false;
}

size_t InputVirtual::getNumberHats()
{
	return 0;
}

std::shared_ptr<InputDevice> InputVirtual::getHat(int)
{
	return std::shared_ptr<InputDevice>();
}

size_t InputVirtual::getNumberButtons()
{
	return buttons.size();
}

size_t InputVirtual::getNumberAxes()
{
	return axes.size();
}

bool InputVirtual::isAnyButtonPressed()
{
	for (size_t j=0; j < buttons.size(); j++) {
		auto& binds = buttons[j];
		for (size_t i=0; i<binds.size(); i++) {
			Bind& bind = binds[i];
			if (bind.device->isAnyButtonPressed()) {
				return true;
			}
		}
	}
	return false;
}

bool InputVirtual::isAnyButtonReleased()
{
	for (size_t j=0; j < buttons.size(); j++) {
		auto& binds = buttons[j];
		for (size_t i=0; i<binds.size(); i++) {
			Bind& bind = binds[i];
			if (bind.device->isAnyButtonReleased()) {
				return true;
			}
		}
	}
	return false;
}

bool InputVirtual::isAnyButtonDown()
{
	for (size_t j=0; j < buttons.size(); j++) {
		auto& binds = buttons[j];
		for (size_t i=0; i<binds.size(); i++) {
			Bind& bind = binds[i];
			if (bind.device->isAnyButtonDown()) {
				return true;
			}
		}
	}
	return false;
}

bool InputVirtual::isButtonPressed(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		if (bind.device->isButtonPressed(bind.a)) {
			return true;
		}
	}
	return false;
}

bool InputVirtual::isButtonPressedRepeat(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		if (bind.device->isButtonPressedRepeat(bind.a)) {
			return true;
		}
	}
	return false;
}

bool InputVirtual::isButtonReleased(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		if (bind.device->isButtonReleased(bind.a)) {
			return true;
		}
	}
	return false;
}

bool InputVirtual::isButtonDown(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		if (bind.device->isButtonDown(bind.a)) {
			return true;
		}
	}
	return false;
}

void InputVirtual::clearButton(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		bind.device->clearButton(bind.a);
	}
}

void InputVirtual::clearButtonPress(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		bind.device->clearButtonPress(bind.a);
	}
}

void InputVirtual::clearButtonRelease(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		bind.device->clearButtonRelease(bind.a);
	}
}

float InputVirtual::getAxis(int n)
{
	auto& binds = axes.at(n).binds;
	float value = 0;

	for (size_t i=0; i<binds.size(); i++) {
		Bind& b = binds[i];
		if (b.isAxisEmulation) {
			int left = b.device->isButtonDown(b.a) ? 1 : 0;
			int right = b.device->isButtonDown(b.b) ? 1 : 0;
			value += right - left;
		} else {
			value += b.device->getAxis(b.a);
		}
	}

	return value;
}

int InputVirtual::getAxisRepeat(int n)
{
	return axes.at(n).curRepeatValue;
}

void InputVirtual::bindButton(int n, spInputDevice device, int deviceN)
{
	if (!lastDevice) {
		setLastDevice(device.get());
	}
	buttons.at(n).push_back(Bind(device, deviceN, false));
}

void InputVirtual::bindAxis(int n, spInputDevice device, int deviceN)
{
	if (!lastDevice) {
		setLastDevice(device.get());
	}
	axes.at(n).binds.push_back(Bind(device, deviceN, true));
}

void InputVirtual::bindAxisButton(int n, spInputDevice device, int negativeButton, int positiveButton)
{
	if (!lastDevice) {
		setLastDevice(device.get());
	}
	axes.at(n).binds.push_back(Bind(device, negativeButton, positiveButton, true));
}

void InputVirtual::bindVibrationOverride(spInputDevice joy)
{
	vibrationOverride = joy;
}

void InputVirtual::unbindButton(int n)
{
	buttons.at(n).clear();
}

void InputVirtual::unbindAxis(int n)
{
	axes.at(n).binds.clear();
}

void InputVirtual::clearBindings()
{
	for (size_t i=0; i<buttons.size(); i++) {
		buttons[i].clear();
	}
	for (size_t i=0; i<axes.size(); i++) {
		axes[i].binds.clear();
	}
	vibrationOverride = spInputDevice();
}

void InputVirtual::vibrate(spInputVibration vib)
{
	auto dev = vibrationOverride ? vibrationOverride.get() : lastDevice;
	if (dev) {
		dev->vibrate(vib);
	}
}

void InputVirtual::stopVibrating()
{
	auto dev = vibrationOverride ? vibrationOverride.get() : lastDevice;
	if (dev) {
		dev->stopVibrating();
	}
}

Vector2f InputVirtual::getPosition() const
{
	return position;
}

void InputVirtual::setPosition(Vector2f pos)
{
	position = pos;
}

void InputVirtual::setPositionLimits(Rect4f limits)
{
	positionLimits = limits;
}

void InputVirtual::setPositionLimits()
{
	positionLimits.reset();
}

int InputVirtual::getWheelMove() const
{
	int val = 0;
	for (auto& w: wheels) {
		val += w->getWheelMove();
	}
	return val;
}

void InputVirtual::bindHat(int leftRight, int upDown, spInputDevice hat)
{
	bindAxisButton(leftRight, hat, 3, 1);
	bindAxisButton(upDown, hat, 0, 2);
}

void InputVirtual::bindPosition(spInputDevice device)
{
	positions.push_back(PositionBindData(device));
}

void InputVirtual::bindPositionRelative(spInputDevice device, int axisX, int axisY, float speed)
{
	positions.push_back(PositionBindData(device, axisX, axisY, speed));
}

void InputVirtual::bindWheel(spInputDevice device)
{
	wheels.push_back(device);
}

String InputVirtual::getButtonName(int code)
{
	auto& binds = buttons.at(code);
	if (binds.size() > 0) {
		Bind& bind = binds[0];
		return bind.device->getButtonName(bind.a);
	} else {
		return "-";
	}
}

void InputVirtual::update(Time t)
{
	updateLastDevice();

	for (size_t i = 0; i < axes.size(); i++) {
		auto& axis = axes[i];

		axis.curRepeatValue = 0;

		float curVal = getAxis(int(i));
		int intVal = curVal > 0.30f ? 1 : (curVal < -0.30f ? -1 : 0);

		auto& timeSinceRepeat = axis.timeSinceRepeat;
		auto& lastVal = axis.lastRepeatedValue;

		if (lastVal != intVal) {
			timeSinceRepeat = std::max(repeatDelayFirst, repeatDelayHold);
			axis.numRepeats = 0;
		}

		if (intVal != 0) {
			Time threshold = axis.numRepeats == 1 ? repeatDelayFirst : repeatDelayHold;
			timeSinceRepeat += t * fabs(curVal);
			if (timeSinceRepeat >= threshold) {
				axis.curRepeatValue = intVal;
				axis.numRepeats++;
				timeSinceRepeat = 0;
			}
		}

		lastVal = intVal;
	}

	for (auto& pos: positions) {
		if (pos.direct) {
			auto posNow = pos.device->getPosition();
			if ((pos.lastRead - posNow).squaredLength() > 0.001f) {
				pos.lastRead = posNow;
				position = posNow;
			}
		} else {
			Vector2f delta(pos.device->getAxis(pos.axisX), pos.device->getAxis(pos.axisY));
			position += delta * float(pos.speed * t);
		}
	}
	if (positionLimits) {
		position = positionLimits.get().getClosestPoint(position);
	}
}

InputDevice* InputVirtual::getLastDevice() const
{
	return lastDevice;
}

void InputVirtual::updateLastDevice()
{
	if (!lastDeviceFrozen) {
		for (auto& buttonBinds: buttons) {
			for (auto& bind: buttonBinds) {
				if (bind.device && !std::dynamic_pointer_cast<InputManual>(bind.device)) {
					if (!bind.isAxisEmulation && bind.device->isButtonPressed(bind.a)) {
						setLastDevice(bind.device.get());
						return;
					}
				}
			}
		}
		for (auto& axisBind: axes) {
			for (auto& bind: axisBind.binds) {
				if (bind.device && !std::dynamic_pointer_cast<InputManual>(bind.device)) {
					if ((!bind.isAxisEmulation && fabs(bind.device->getAxis(bind.a)) > 0.1f)
						|| (bind.isAxisEmulation && bind.device->isButtonDown(bind.a))
						|| (bind.isAxisEmulation && bind.device->isButtonDown(bind.b))) {
						setLastDevice(bind.device.get());
						return;
					}
				}
			}
		}
	}
}

InputVirtual::Bind::Bind(spInputDevice d, int n, bool axis)
	: device(d)
	, a(n)
	, b(0)
	, isAxis(axis)
	, isAxisEmulation(false)
{}

InputVirtual::Bind::Bind(spInputDevice d, int _a, int _b, bool axis)
	: device(d)
	, a(_a)
	, b(_b)
	, isAxis(axis)
	, isAxisEmulation(true)
{}

InputVirtual::AxisData::AxisData()
{}

InputVirtual::AxisData::AxisData(Vector<Bind>& b)
	: binds(b)
{}

InputVirtual::PositionBindData::PositionBindData()
{}

InputVirtual::PositionBindData::PositionBindData(spInputDevice device)
	: device(device)
	, direct(true)
{}

InputVirtual::PositionBindData::PositionBindData(spInputDevice device, int axisX, int axisY, float speed)
	: device(device)
	, axisX(axisX)
	, axisY(axisY)
	, speed(speed)
{}

std::set<spInputDevice> InputVirtual::getAllDevices() const
{
	std::set<spInputDevice> devices;

	for (auto& axisBind: axes) {
		for (auto& bind: axisBind.binds) {
			if (bind.device) {
				devices.insert(bind.device);
			}
		}
	}
	for (auto& buttonBinds: buttons) {
		for (auto& bind: buttonBinds) {
			if (bind.device) {
				devices.insert(bind.device);
			}
		}
	}

	return devices;
}

void InputVirtual::setLastDeviceFreeze(bool frozen)
{
	lastDeviceFrozen = frozen;
}

void InputVirtual::setRepeat(float first, float hold)
{
	repeatDelayFirst = first;
	repeatDelayHold = hold;
}

JoystickType InputVirtual::getJoystickType() const
{
	if (lastDevice) {
		return lastDevice->getJoystickType();
	} else {
		return JoystickType::None;
	}
}

void InputVirtual::setLastDevice(InputDevice* device)
{
	auto parent = device->getParent();
	if (parent) {
		setLastDevice(parent);
	} else {
		lastDevice = device;
	}
}
<commit_msg>Lower analogue stick sensitivity.<commit_after>/*****************************************************************\
           __
          / /
		 / /                     __  __
		/ /______    _______    / / / / ________   __       __
	   / ______  \  /_____  \  / / / / / _____  | / /      / /
	  / /      | / _______| / / / / / / /____/ / / /      / /
	 / /      / / / _____  / / / / / / _______/ / /      / /
	/ /      / / / /____/ / / / / / / |______  / |______/ /
   /_/      /_/ |________/ / / / /  \_______/  \_______  /
                          /_/ /_/                     / /
			                                         / /
		       High Level Game Framework            /_/

  ---------------------------------------------------------------

  Copyright (c) 2007-2011 - Rodrigo Braz Monteiro.
  This file is subject to the terms of halley_license.txt.

\*****************************************************************/

#include "input/input_virtual.h"
#include "input/input_manual.h"
#include <set>
#include <algorithm>

using namespace Halley;

InputVirtual::InputVirtual(int nButtons, int nAxes)
	: lastDeviceFrozen(false)
	, repeatDelayFirst(0.20f)
	, repeatDelayHold(0.10f)
{
	buttons.resize(nButtons);
	axes.resize(nAxes);
}

bool InputVirtual::isEnabled() const
{
	for (auto& d: getAllDevices()) {
		if (d->isEnabled()) {
			return true;
		}
	}
	return false;
}

size_t InputVirtual::getNumberHats()
{
	return 0;
}

std::shared_ptr<InputDevice> InputVirtual::getHat(int)
{
	return std::shared_ptr<InputDevice>();
}

size_t InputVirtual::getNumberButtons()
{
	return buttons.size();
}

size_t InputVirtual::getNumberAxes()
{
	return axes.size();
}

bool InputVirtual::isAnyButtonPressed()
{
	for (size_t j=0; j < buttons.size(); j++) {
		auto& binds = buttons[j];
		for (size_t i=0; i<binds.size(); i++) {
			Bind& bind = binds[i];
			if (bind.device->isAnyButtonPressed()) {
				return true;
			}
		}
	}
	return false;
}

bool InputVirtual::isAnyButtonReleased()
{
	for (size_t j=0; j < buttons.size(); j++) {
		auto& binds = buttons[j];
		for (size_t i=0; i<binds.size(); i++) {
			Bind& bind = binds[i];
			if (bind.device->isAnyButtonReleased()) {
				return true;
			}
		}
	}
	return false;
}

bool InputVirtual::isAnyButtonDown()
{
	for (size_t j=0; j < buttons.size(); j++) {
		auto& binds = buttons[j];
		for (size_t i=0; i<binds.size(); i++) {
			Bind& bind = binds[i];
			if (bind.device->isAnyButtonDown()) {
				return true;
			}
		}
	}
	return false;
}

bool InputVirtual::isButtonPressed(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		if (bind.device->isButtonPressed(bind.a)) {
			return true;
		}
	}
	return false;
}

bool InputVirtual::isButtonPressedRepeat(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		if (bind.device->isButtonPressedRepeat(bind.a)) {
			return true;
		}
	}
	return false;
}

bool InputVirtual::isButtonReleased(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		if (bind.device->isButtonReleased(bind.a)) {
			return true;
		}
	}
	return false;
}

bool InputVirtual::isButtonDown(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		if (bind.device->isButtonDown(bind.a)) {
			return true;
		}
	}
	return false;
}

void InputVirtual::clearButton(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		bind.device->clearButton(bind.a);
	}
}

void InputVirtual::clearButtonPress(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		bind.device->clearButtonPress(bind.a);
	}
}

void InputVirtual::clearButtonRelease(int code)
{
	auto& binds = buttons.at(code);
	for (size_t i=0; i<binds.size(); i++) {
		Bind& bind = binds[i];
		bind.device->clearButtonRelease(bind.a);
	}
}

float InputVirtual::getAxis(int n)
{
	auto& binds = axes.at(n).binds;
	float value = 0;

	for (size_t i=0; i<binds.size(); i++) {
		Bind& b = binds[i];
		if (b.isAxisEmulation) {
			int left = b.device->isButtonDown(b.a) ? 1 : 0;
			int right = b.device->isButtonDown(b.b) ? 1 : 0;
			value += right - left;
		} else {
			value += b.device->getAxis(b.a);
		}
	}

	return value;
}

int InputVirtual::getAxisRepeat(int n)
{
	return axes.at(n).curRepeatValue;
}

void InputVirtual::bindButton(int n, spInputDevice device, int deviceN)
{
	if (!lastDevice) {
		setLastDevice(device.get());
	}
	buttons.at(n).push_back(Bind(device, deviceN, false));
}

void InputVirtual::bindAxis(int n, spInputDevice device, int deviceN)
{
	if (!lastDevice) {
		setLastDevice(device.get());
	}
	axes.at(n).binds.push_back(Bind(device, deviceN, true));
}

void InputVirtual::bindAxisButton(int n, spInputDevice device, int negativeButton, int positiveButton)
{
	if (!lastDevice) {
		setLastDevice(device.get());
	}
	axes.at(n).binds.push_back(Bind(device, negativeButton, positiveButton, true));
}

void InputVirtual::bindVibrationOverride(spInputDevice joy)
{
	vibrationOverride = joy;
}

void InputVirtual::unbindButton(int n)
{
	buttons.at(n).clear();
}

void InputVirtual::unbindAxis(int n)
{
	axes.at(n).binds.clear();
}

void InputVirtual::clearBindings()
{
	for (size_t i=0; i<buttons.size(); i++) {
		buttons[i].clear();
	}
	for (size_t i=0; i<axes.size(); i++) {
		axes[i].binds.clear();
	}
	vibrationOverride = spInputDevice();
}

void InputVirtual::vibrate(spInputVibration vib)
{
	auto dev = vibrationOverride ? vibrationOverride.get() : lastDevice;
	if (dev) {
		dev->vibrate(vib);
	}
}

void InputVirtual::stopVibrating()
{
	auto dev = vibrationOverride ? vibrationOverride.get() : lastDevice;
	if (dev) {
		dev->stopVibrating();
	}
}

Vector2f InputVirtual::getPosition() const
{
	return position;
}

void InputVirtual::setPosition(Vector2f pos)
{
	position = pos;
}

void InputVirtual::setPositionLimits(Rect4f limits)
{
	positionLimits = limits;
}

void InputVirtual::setPositionLimits()
{
	positionLimits.reset();
}

int InputVirtual::getWheelMove() const
{
	int val = 0;
	for (auto& w: wheels) {
		val += w->getWheelMove();
	}
	return val;
}

void InputVirtual::bindHat(int leftRight, int upDown, spInputDevice hat)
{
	bindAxisButton(leftRight, hat, 3, 1);
	bindAxisButton(upDown, hat, 0, 2);
}

void InputVirtual::bindPosition(spInputDevice device)
{
	positions.push_back(PositionBindData(device));
}

void InputVirtual::bindPositionRelative(spInputDevice device, int axisX, int axisY, float speed)
{
	positions.push_back(PositionBindData(device, axisX, axisY, speed));
}

void InputVirtual::bindWheel(spInputDevice device)
{
	wheels.push_back(device);
}

String InputVirtual::getButtonName(int code)
{
	auto& binds = buttons.at(code);
	if (binds.size() > 0) {
		Bind& bind = binds[0];
		return bind.device->getButtonName(bind.a);
	} else {
		return "-";
	}
}

void InputVirtual::update(Time t)
{
	updateLastDevice();

	for (size_t i = 0; i < axes.size(); i++) {
		auto& axis = axes[i];

		axis.curRepeatValue = 0;

		float curVal = getAxis(int(i));
		int intVal = curVal > 0.50f ? 1 : (curVal < -0.50f ? -1 : 0);

		auto& timeSinceRepeat = axis.timeSinceRepeat;
		auto& lastVal = axis.lastRepeatedValue;

		if (lastVal != intVal) {
			timeSinceRepeat = std::max(repeatDelayFirst, repeatDelayHold);
			axis.numRepeats = 0;
		}

		if (intVal != 0) {
			Time threshold = axis.numRepeats == 1 ? repeatDelayFirst : repeatDelayHold;
			timeSinceRepeat += t * fabs(curVal);
			if (timeSinceRepeat >= threshold) {
				axis.curRepeatValue = intVal;
				axis.numRepeats++;
				timeSinceRepeat = 0;
			}
		}

		lastVal = intVal;
	}

	for (auto& pos: positions) {
		if (pos.direct) {
			auto posNow = pos.device->getPosition();
			if ((pos.lastRead - posNow).squaredLength() > 0.001f) {
				pos.lastRead = posNow;
				position = posNow;
			}
		} else {
			Vector2f delta(pos.device->getAxis(pos.axisX), pos.device->getAxis(pos.axisY));
			position += delta * float(pos.speed * t);
		}
	}
	if (positionLimits) {
		position = positionLimits.get().getClosestPoint(position);
	}
}

InputDevice* InputVirtual::getLastDevice() const
{
	return lastDevice;
}

void InputVirtual::updateLastDevice()
{
	if (!lastDeviceFrozen) {
		for (auto& buttonBinds: buttons) {
			for (auto& bind: buttonBinds) {
				if (bind.device && !std::dynamic_pointer_cast<InputManual>(bind.device)) {
					if (!bind.isAxisEmulation && bind.device->isButtonPressed(bind.a)) {
						setLastDevice(bind.device.get());
						return;
					}
				}
			}
		}
		for (auto& axisBind: axes) {
			for (auto& bind: axisBind.binds) {
				if (bind.device && !std::dynamic_pointer_cast<InputManual>(bind.device)) {
					if ((!bind.isAxisEmulation && fabs(bind.device->getAxis(bind.a)) > 0.1f)
						|| (bind.isAxisEmulation && bind.device->isButtonDown(bind.a))
						|| (bind.isAxisEmulation && bind.device->isButtonDown(bind.b))) {
						setLastDevice(bind.device.get());
						return;
					}
				}
			}
		}
	}
}

InputVirtual::Bind::Bind(spInputDevice d, int n, bool axis)
	: device(d)
	, a(n)
	, b(0)
	, isAxis(axis)
	, isAxisEmulation(false)
{}

InputVirtual::Bind::Bind(spInputDevice d, int _a, int _b, bool axis)
	: device(d)
	, a(_a)
	, b(_b)
	, isAxis(axis)
	, isAxisEmulation(true)
{}

InputVirtual::AxisData::AxisData()
{}

InputVirtual::AxisData::AxisData(Vector<Bind>& b)
	: binds(b)
{}

InputVirtual::PositionBindData::PositionBindData()
{}

InputVirtual::PositionBindData::PositionBindData(spInputDevice device)
	: device(device)
	, direct(true)
{}

InputVirtual::PositionBindData::PositionBindData(spInputDevice device, int axisX, int axisY, float speed)
	: device(device)
	, axisX(axisX)
	, axisY(axisY)
	, speed(speed)
{}

std::set<spInputDevice> InputVirtual::getAllDevices() const
{
	std::set<spInputDevice> devices;

	for (auto& axisBind: axes) {
		for (auto& bind: axisBind.binds) {
			if (bind.device) {
				devices.insert(bind.device);
			}
		}
	}
	for (auto& buttonBinds: buttons) {
		for (auto& bind: buttonBinds) {
			if (bind.device) {
				devices.insert(bind.device);
			}
		}
	}

	return devices;
}

void InputVirtual::setLastDeviceFreeze(bool frozen)
{
	lastDeviceFrozen = frozen;
}

void InputVirtual::setRepeat(float first, float hold)
{
	repeatDelayFirst = first;
	repeatDelayHold = hold;
}

JoystickType InputVirtual::getJoystickType() const
{
	if (lastDevice) {
		return lastDevice->getJoystickType();
	} else {
		return JoystickType::None;
	}
}

void InputVirtual::setLastDevice(InputDevice* device)
{
	auto parent = device->getParent();
	if (parent) {
		setLastDevice(parent);
	} else {
		lastDevice = device;
	}
}
<|endoftext|>


<commit_before>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/profiler/convert/xplane_to_step_events.h"

#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/profiler/utils/metadata_matcher.h"
#include "tensorflow/core/profiler/utils/trace_utils.h"
#include "tensorflow/core/profiler/utils/xplane_schema.h"

namespace tensorflow {
namespace profiler {
namespace {

// Returns true if the given event_name is a step marker.
inline bool IsStepMarker(absl::string_view event_name) {
  return (str_util::StartsWith(event_name, "train") ||
          str_util::StartsWith(event_name, "test") ||
          str_util::StartsWith(event_name, "TraceContext")) &&
         !str_util::StrContains(event_name, "/");
}

// Returns true if the given event_name should be considered as real computation
// on CPU.
inline bool IsRealCpuCompute(absl::string_view event_name) {
  bool not_real = str_util::StartsWith(event_name, "EagerExecute") ||
                  str_util::StartsWith(event_name, "EagerLocalExecute") ||
                  str_util::StartsWith(event_name, "EagerKernelExecute") ||
                  str_util::StartsWith(event_name, "FunctionRun") ||
                  IsStepMarker(event_name);
  return !not_real;
}

}  // namespace

StepEvents ConvertHostThreadsXLineToStepEvents(
    const XLineVisitor& line, bool use_device_step_events,
    const StepEvents& device_step_events) {
  StepEvents result;
  line.ForEachEvent([&](const XEventVisitor& event) {
    int64 correlation_id = -1;
    int64 group_id = -1;
    event.ForEachStat([&](const XStatVisitor& stat) {
      if (stat.Type() == StatType::kCorrelationId) {
        correlation_id = stat.IntValue();
      } else if (stat.Type() == StatType::kGroupId) {
        group_id = stat.IntValue();
      }
    });
    if (group_id < 0) return;
    // Don't add events when either (1) it excludes device step events or
    // (2) it has a device and that the group_id (i.e. step number) already
    // appears on the device. This will filter out all cpu events that do not
    // correspond to any steps executed on the device.
    if (!use_device_step_events ||
        device_step_events.find(group_id) == device_step_events.end())
      return;
    Timespan timespan = Timespan(event.TimestampPs(), event.DurationPs());
    if (IsStepMarker(event.Name())) {
      result[group_id].AddMarker(
          StepMarker(/*device=*/false, event.Name(), timespan));
    } else if (IsRealCpuCompute(event.Name())) {
      EventTypeSpan event_type_span(
          ClassifyCpuEvent(event.Name(), correlation_id), timespan);
      result[group_id].AddEvent(event_type_span);
    }
  });
  return result;
}

StepEvents ConvertHostThreadsXPlaneToStepEvents(
    const XPlane& host_trace, bool use_device_step_events,
    const StepEvents& device_step_events) {
  StepEvents result;
  XPlaneVisitor plane(&host_trace);
  plane.ForEachLine([&](const XLineVisitor& line) {
    CombineStepEvents(ConvertHostThreadsXLineToStepEvents(
                          line, use_device_step_events, device_step_events),
                      &result);
  });
  return result;
}

StepEvents ConvertDeviceTraceXLineToStepEvents(const XLineVisitor& line) {
  int64 correlation_id = -1;
  int64 group_id = -1;
  StepEvents result;
  line.ForEachEvent([&](const XEventVisitor& event) {
    event.ForEachStat([&](const XStatVisitor& stat) {
      if (stat.Type() == StatType::kCorrelationId) {
        correlation_id = stat.IntValue();
      } else if (stat.Type() == StatType::kGroupId) {
        group_id = stat.IntValue();
      }
    });
    if (correlation_id >= 0 && group_id >= 0) {
      EventTypeSpan event_type_span(
          ClassifyGpuEvent(event.Name()),
          Timespan(event.TimestampPs(), event.DurationPs()));
      result[group_id].AddEvent(event_type_span);
    }
  });
  return result;
}

StepEvents ConvertDeviceTraceXPlaneToStepEvents(const XPlane& device_trace) {
  StepEvents result;
  XPlaneVisitor plane(&device_trace);
  plane.ForEachLine([&](const XLineVisitor& line) {
    if (IsDerivedThreadId(line.Id())) return;
    CombineStepEvents(ConvertDeviceTraceXLineToStepEvents(line), &result);
  });
  return result;
}

}  // namespace profiler
}  // namespace tensorflow
<commit_msg>Fix the CPU events filtering logic.<commit_after>/* Copyright 2020 The TensorFlow Authors. All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/

#include "tensorflow/core/profiler/convert/xplane_to_step_events.h"

#include "tensorflow/core/lib/strings/str_util.h"
#include "tensorflow/core/profiler/utils/metadata_matcher.h"
#include "tensorflow/core/profiler/utils/trace_utils.h"
#include "tensorflow/core/profiler/utils/xplane_schema.h"

namespace tensorflow {
namespace profiler {
namespace {

// Returns true if the given event_name is a step marker.
inline bool IsStepMarker(absl::string_view event_name) {
  return (str_util::StartsWith(event_name, "train") ||
          str_util::StartsWith(event_name, "test") ||
          str_util::StartsWith(event_name, "TraceContext")) &&
         !str_util::StrContains(event_name, "/");
}

// Returns true if the given event_name should be considered as real computation
// on CPU.
inline bool IsRealCpuCompute(absl::string_view event_name) {
  bool not_real = str_util::StartsWith(event_name, "EagerExecute") ||
                  str_util::StartsWith(event_name, "EagerLocalExecute") ||
                  str_util::StartsWith(event_name, "EagerKernelExecute") ||
                  str_util::StartsWith(event_name, "FunctionRun") ||
                  IsStepMarker(event_name);
  return !not_real;
}

}  // namespace

StepEvents ConvertHostThreadsXLineToStepEvents(
    const XLineVisitor& line, bool use_device_step_events,
    const StepEvents& device_step_events) {
  StepEvents result;
  line.ForEachEvent([&](const XEventVisitor& event) {
    int64 correlation_id = -1;
    int64 group_id = -1;
    event.ForEachStat([&](const XStatVisitor& stat) {
      if (stat.Type() == StatType::kCorrelationId) {
        correlation_id = stat.IntValue();
      } else if (stat.Type() == StatType::kGroupId) {
        group_id = stat.IntValue();
      }
    });
    if (group_id < 0) return;
    // Don't add CPU events when (1) it includes device step events and (2) it
    // doesn't have a device and that the group_id (i.e. step number) already
    // appears on the device. This will filter out all cpu events that do not
    // correspond to any steps executed on the device.
    if (use_device_step_events &&
        device_step_events.find(group_id) == device_step_events.end())
      return;
    Timespan timespan = Timespan(event.TimestampPs(), event.DurationPs());
    if (IsStepMarker(event.Name())) {
      result[group_id].AddMarker(
          StepMarker(/*device=*/false, event.Name(), timespan));
    } else if (IsRealCpuCompute(event.Name())) {
      EventTypeSpan event_type_span(
          ClassifyCpuEvent(event.Name(), correlation_id), timespan);
      result[group_id].AddEvent(event_type_span);
    }
  });
  return result;
}

StepEvents ConvertHostThreadsXPlaneToStepEvents(
    const XPlane& host_trace, bool use_device_step_events,
    const StepEvents& device_step_events) {
  StepEvents result;
  XPlaneVisitor plane(&host_trace);
  plane.ForEachLine([&](const XLineVisitor& line) {
    CombineStepEvents(ConvertHostThreadsXLineToStepEvents(
                          line, use_device_step_events, device_step_events),
                      &result);
  });
  return result;
}

StepEvents ConvertDeviceTraceXLineToStepEvents(const XLineVisitor& line) {
  int64 correlation_id = -1;
  int64 group_id = -1;
  StepEvents result;
  line.ForEachEvent([&](const XEventVisitor& event) {
    event.ForEachStat([&](const XStatVisitor& stat) {
      if (stat.Type() == StatType::kCorrelationId) {
        correlation_id = stat.IntValue();
      } else if (stat.Type() == StatType::kGroupId) {
        group_id = stat.IntValue();
      }
    });
    if (correlation_id >= 0 && group_id >= 0) {
      EventTypeSpan event_type_span(
          ClassifyGpuEvent(event.Name()),
          Timespan(event.TimestampPs(), event.DurationPs()));
      result[group_id].AddEvent(event_type_span);
    }
  });
  return result;
}

StepEvents ConvertDeviceTraceXPlaneToStepEvents(const XPlane& device_trace) {
  StepEvents result;
  XPlaneVisitor plane(&device_trace);
  plane.ForEachLine([&](const XLineVisitor& line) {
    if (IsDerivedThreadId(line.Id())) return;
    CombineStepEvents(ConvertDeviceTraceXLineToStepEvents(line), &result);
  });
  return result;
}

}  // namespace profiler
}  // namespace tensorflow
<|endoftext|>


<commit_before>#include <iostream>
#include <iomanip>
#include <algorithm>
#include <sstream>
#include <stdexcept>
#include <ctime>

#include "kapi.hpp"
#include "libjson/libjson.h"

using namespace std;
using namespace Kraken;

//------------------------------------------------------------------------------
// deals with Candlesticks
struct Record {
   vector<double> prices;
   double volume;
   time_t timestamp;

   Record(time_t t)
      :timestamp(t) {}

   // add a record
   void add(double p, double v) {
      prices.push_back(p);
      volume += v;
   }

   double low() const { return *min_element(prices.begin(), prices.end()); }
   double high() const { return *max_element(prices.begin(), prices.end()); }

   double open() const { return prices.front(); }
   double close() const { return prices.back(); }

private:
   // disable default constructor
   Record();
};

//------------------------------------------------------------------------------
// prints out a vector of records:
void print_records(const vector<Record>& records)
{
   double ha_open, ha_close, ha_low, ha_high;

   // print out records
   for (int i=0; i<records.size(); ++i) {
      // http://stockcharts.com/help/doku.php?id=chart_school:
      // chart_analysis:heikin_ashi

      // The Heikin-Ashi Open is the average of the prior Heikin-Ashi
      // candlestick open plus the close of the prior Heikin-Ashi
      // candlestick.
      if (i == 0)
	 ha_open = (records[0].open() + records[0].close()) / 2;
      else
	 ha_open = (ha_open + ha_close) / 2;

      // The Heikin-Ashi Close is simply an average of the open,
      // high, low and close for the current period.
      ha_close = (records[i].open() + records[i].high() +
		  records[i].low() + records[i].close()) / 4;

      // The Heikin-Ashi High is the maximum of three data points:
      // the current period's high, the current Heikin-Ashi
      // candlestick open or the current Heikin-Ashi candlestick close.
      ha_high = max(records[i].high(), max(ha_open, ha_close));

      // The Heikin-Ashi low is the minimum of three data points:
      // the current period's low, the current Heikin-Ashi
      // candlestick open or the current Heikin-Ashi candlestick close.
      ha_low = min(records[i].low(), min(ha_open, ha_close));

      //struct tm timeinfo;
      //localtime_r(&records[i].timestamp, &timeinfo);

      //char buffer[20];
      //strftime(buffer, 20, "%T %z", &timeinfo);
      cout << records[i].timestamp << "   "
	   << fixed << setprecision(9)
	   << records[i].volume << "   "
	   << fixed << right << setprecision(5)
	   << ha_open  << "   "
	   << ha_low   << "   "
	   << ha_high  << "   "
	   << ha_close << endl;
   }

}

//------------------------------------------------------------------------------

int main()
{
   curl_global_init(CURL_GLOBAL_ALL);

   try {
      KAPI kapi;
      KAPI::Input in;

      // get recent trades
      in.insert(make_pair("pair", "XXBTZEUR"));

      string json_trades = kapi.public_method("Trades", in);
      JSONNode root = libjson::parse(json_trades);

      // check for errors, if they're present an
      // exception will be thrown
      if (!root.at("error").empty()) {
	 ostringstream oss;
	 oss << "Kraken response contains errors: ";

	 // append errors to output string stream
	 for (JSONNode::iterator it = root["error"].begin();
	      it != root["error"].end(); ++it)
	    oss << endl << " * " << libjson::to_std_string(it->as_string());

	 throw runtime_error(oss.str());
      }
      else {
	 // format the output in columns: time, order, price and volume
	 JSONNode result_node = root.at("result")[0];

	 JSONNode::const_iterator it = result_node.begin();
	 time_t last_hour = 0;

	 vector<Record> records;

	 // now group prices by hour
	 for (; it != result_node.end(); ++it) {
	    const double price  = (*it)[0].as_float();
	    const double volume = (*it)[1].as_float();
	    const time_t time   = (*it)[2].as_int();
	    const char order    = (*it)[3].as_string()[0];

	    // a new group if needed
	    time_t hour = time - time % 3600;
	    if (hour != last_hour) {
	       last_hour = hour;
	       records.push_back(Record(hour));
	    }

	    records.back().add(price, volume);
	 }

	 print_records(records);
      }

   }
   catch(exception& e) {
      cerr << "Error: " << e.what() << endl;
   }
   catch(...) {
      cerr << "Unknow exception." << endl;
   }

   curl_global_cleanup();
   return 0;
}
<commit_msg>Revert "kmarketdata prints out HA candlesticks data"<commit_after>#include <iostream>
#include <iomanip>
#include <sstream>
#include <stdexcept>
#include <ctime>

#include "kapi.hpp"
#include "libjson/libjson.h"

using namespace std;
using namespace Kraken;

//------------------------------------------------------------------------------

int main()
{
   curl_global_init(CURL_GLOBAL_ALL);

   try {
      KAPI kapi;
      KAPI::Input in;

      // get recent trades
      in.insert(make_pair("pair", "XXBTZEUR"));

      string json_trades = kapi.public_method("Trades", in);
      JSONNode root = libjson::parse(json_trades);

      // check for errors, if they're present an
      // exception will be thrown
      if (!root.at("error").empty()) {
	 ostringstream oss;
	 oss << "Kraken response contains errors: ";

	 // append errors to output string stream
	 for (JSONNode::iterator it = root["error"].begin();
	      it != root["error"].end(); ++it)
	    oss << endl << " * " << libjson::to_std_string(it->as_string());

	 throw runtime_error(oss.str());
      }
      else {
	 // format the output in columns: time, order, price and volume
	 JSONNode result_node = root.at("result")[0];

	 for (JSONNode::const_iterator it = result_node.begin();
	      it != result_node.end(); ++it) {
	    const double price  = (*it)[0].as_float();
	    const double volume = (*it)[1].as_float();
	    const time_t time   = (*it)[2].as_int();
	    const char order    = (*it)[3].as_string()[0];

	    struct tm timeinfo;
	    localtime_r(&time, &timeinfo);

	    char buffer[20];
	    strftime(buffer, 20, "%T", &timeinfo);

	    cout << left << setw(12) << buffer << "   "
		 << left << setw(4) << (order=='b'?"buy":"sell") << "   "
		 << fixed << right
		 << setprecision(5) << price << "   "
		 << setprecision(9) << volume << endl;
	 }
      }

   }
   catch(exception& e) {
      cerr << "Error: " << e.what() << endl;
   }
   catch(...) {
      cerr << "Unknow exception." << endl;
   }

   curl_global_cleanup();
   return 0;
}
<|endoftext|>


<commit_before>#include <iostream>

int main()
{
    std::cout << "hello world\n";
    return 0;
}
<commit_msg>deleted prova.cpp<commit_after><|endoftext|>