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

#include <osg/Notify>
#include <osg/MatrixTransform>
#include <osg/ShapeDrawable>
#include <osg/PositionAttitudeTransform>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osg/Geode>
#include <osg/LightSource>
#include <osg/TexGenNode>

#include <osgUtil/Optimizer>

#include <osgDB/Registry>
#include <osgDB/ReadFile>

#include <osgViewer/Viewer>

// for the grid data..
#include "../osghangglide/terrain_coords.h"

osg::Image* createSpotLightImage(const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
{
    osg::Image* image = new osg::Image;
    image->allocateImage(size,size,1,
                         GL_RGBA,GL_UNSIGNED_BYTE);

    float mid = (float(size)-1)*0.5f;
    float div = 2.0f/float(size);
    for(unsigned int r=0;r<size;++r)
    {
        unsigned char* ptr = image->data(0,r,0);
        for(unsigned int c=0;c<size;++c)
        {
            float dx = (float(c) - mid)*div;
            float dy = (float(r) - mid)*div;
            float pr = powf(1.0f-sqrtf(dx*dx+dy*dy),power);
            if (pr<0.0f) pr=0.0f;
            osg::Vec4 color = centerColour*r+backgroudColour*(1.0f-pr);
            *ptr++ = (unsigned char)((color[0])*255.0f);
            *ptr++ = (unsigned char)((color[1])*255.0f);
            *ptr++ = (unsigned char)((color[2])*255.0f);
            *ptr++ = (unsigned char)((color[3])*255.0f);
        }
    }
    return image;

    //return osgDB::readImageFile("spot.dds");
}

osg::StateSet* createSpotLightDecoratorState(unsigned int lightNum, unsigned int textureUnit)
{
    osg::StateSet* stateset = new osg::StateSet;

    stateset->setMode(GL_LIGHT0+lightNum, osg::StateAttribute::ON);

    osg::Vec4 centerColour(1.0f,1.0f,1.0f,1.0f);
    osg::Vec4 ambientColour(0.05f,0.05f,0.05f,1.0f);

    // set up spot light texture
    osg::Texture2D* texture = new osg::Texture2D();
    texture->setImage(createSpotLightImage(centerColour, ambientColour, 64, 1.0));
    texture->setBorderColor(osg::Vec4(ambientColour));
    texture->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_BORDER);
    texture->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_BORDER);
    texture->setWrap(osg::Texture::WRAP_R,osg::Texture::CLAMP_TO_BORDER);

    stateset->setTextureAttributeAndModes(textureUnit, texture, osg::StateAttribute::ON);

    // set up tex gens
    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_S, osg::StateAttribute::ON);
    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_T, osg::StateAttribute::ON);
    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_R, osg::StateAttribute::ON);
    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_Q, osg::StateAttribute::ON);

    return stateset;
}

osg::Node* createSpotLightNode(const osg::Vec3& position, const osg::Vec3& direction, float angle, unsigned int lightNum, unsigned int textureUnit)
{
    osg::Group* group = new osg::Group;

    // create light source.
    osg::LightSource* lightsource = new osg::LightSource;
    osg::Light* light = lightsource->getLight();
    light->setLightNum(lightNum);
    light->setPosition(osg::Vec4(position,1.0f));
    light->setAmbient(osg::Vec4(0.00f,0.00f,0.05f,1.0f));
    light->setDiffuse(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
    group->addChild(lightsource);

    // create tex gen.

    osg::Vec3 up(0.0f,0.0f,1.0f);
    up = (direction ^ up) ^ direction;
    up.normalize();

    osg::TexGenNode* texgenNode = new osg::TexGenNode;
    texgenNode->setTextureUnit(textureUnit);
    osg::TexGen* texgen = texgenNode->getTexGen();
    texgen->setMode(osg::TexGen::EYE_LINEAR);
    texgen->setPlanesFromMatrix(osg::Matrixd::lookAt(position, position+direction, up)*
                                osg::Matrixd::perspective(angle,1.0,0.1,100)*
                                osg::Matrixd::translate(1.0,1.0,1.0)*
                                osg::Matrixd::scale(0.5,0.5,0.5));

    group->addChild(texgenNode);

    return group;

}

osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime)
{
    // set up the animation path
    osg::AnimationPath* animationPath = new osg::AnimationPath;
    animationPath->setLoopMode(osg::AnimationPath::LOOP);

    int numSamples = 40;
    float yaw = 0.0f;
    float yaw_delta = 2.0f*osg::PI/((float)numSamples-1.0f);
    float roll = osg::inDegrees(30.0f);

    double time=0.0f;
    double time_delta = looptime/(double)numSamples;
    for(int i=0;i<numSamples;++i)
    {
        osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f));
        osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0))*osg::Quat(-(yaw+osg::inDegrees(90.0f)),osg::Vec3(0.0,0.0,1.0)));

        animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));

        yaw += yaw_delta;
        time += time_delta;

    }
    return animationPath;
}

osg::Node* createBase(const osg::Vec3& center,float radius)
{

    osg::Geode* geode = new osg::Geode;

    // set up the texture of the base.
    osg::StateSet* stateset = new osg::StateSet();
    osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile("Images/lz.rgb");
    if (image)
    {
        osg::Texture2D* texture = new osg::Texture2D;
        texture->setImage(image);
        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
    }

    geode->setStateSet( stateset );

    osg::HeightField* grid = new osg::HeightField;
    grid->allocate(38,39);
    grid->setOrigin(center+osg::Vec3(-radius,-radius,0.0f));
    grid->setXInterval(radius*2.0f/(float)(38-1));
    grid->setYInterval(radius*2.0f/(float)(39-1));

    float minHeight = FLT_MAX;
    float maxHeight = -FLT_MAX;

    unsigned int r;
    for(r=0;r<39;++r)
    {
        for(unsigned int c=0;c<38;++c)
        {
            float h = vertex[r+c*39][2];
            if (h>maxHeight) maxHeight=h;
            if (h<minHeight) minHeight=h;
        }
    }

    float hieghtScale = radius*0.5f/(maxHeight-minHeight);
    float hieghtOffset = -(minHeight+maxHeight)*0.5f;

    for(r=0;r<39;++r)
    {
        for(unsigned int c=0;c<38;++c)
        {
            float h = vertex[r+c*39][2];
            grid->setHeight(c,r,(h+hieghtOffset)*hieghtScale);
        }
    }

    geode->addDrawable(new osg::ShapeDrawable(grid));

    osg::Group* group = new osg::Group;
    group->addChild(geode);

    return group;

}

osg::Node* createMovingModel(const osg::Vec3& center, float radius)
{
    float animationLength = 10.0f;

    osg::AnimationPath* animationPath = createAnimationPath(center,radius,animationLength);

    osg::Group* model = new osg::Group;

    osg::ref_ptr<osg::Node> cessna = osgDB::readRefNodeFile("cessna.osgt");
    if (cessna)
    {
        const osg::BoundingSphere& bs = cessna->getBound();

        float size = radius/bs.radius()*0.3f;
        osg::MatrixTransform* positioned = new osg::MatrixTransform;
        positioned->setDataVariance(osg::Object::STATIC);
        positioned->setMatrix(osg::Matrix::translate(-bs.center())*
                              osg::Matrix::scale(size,size,size)*
                              osg::Matrix::rotate(osg::inDegrees(180.0f),0.0f,0.0f,2.0f));

        positioned->addChild(cessna);

        osg::MatrixTransform* xform = new osg::MatrixTransform;
        xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0));
        xform->addChild(positioned);

        xform->addChild(createSpotLightNode(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(0.0f,1.0f,-1.0f), 60.0f, 0, 1));

        model->addChild(xform);
    }

    return model;
}

osg::Node* createModel()
{
    osg::Vec3 center(0.0f,0.0f,0.0f);
    float radius = 100.0f;

    // the shadower model
    osg::Node* shadower = createMovingModel(center,radius*0.5f);

    // the shadowed model
    osg::Node* shadowed = createBase(center-osg::Vec3(0.0f,0.0f,radius*0.1),radius);

    // combine the models together to create one which has the shadower and the shadowed with the required callback.
    osg::Group* root = new osg::Group;

    root->setStateSet(createSpotLightDecoratorState(0,1));

    root->addChild(shadower);
    root->addChild(shadowed);

    return root;
}

int main(int, char **)
{
    // construct the viewer.
    osgViewer::Viewer viewer;

    // add the spoit light model to the viewer
    viewer.setSceneData( createModel() );

    // run the viewer main frame loop.
    return viewer.run();
}
<commit_msg>Fixed spotlight colour mixing<commit_after>/* OpenSceneGraph example, osgspotlight.
*
*  Permission is hereby granted, free of charge, to any person obtaining a copy
*  of this software and associated documentation files (the "Software"), to deal
*  in the Software without restriction, including without limitation the rights
*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
*  copies of the Software, and to permit persons to whom the Software is
*  furnished to do so, subject to the following conditions:
*
*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
*  THE SOFTWARE.
*/

#include <osg/Notify>
#include <osg/MatrixTransform>
#include <osg/ShapeDrawable>
#include <osg/PositionAttitudeTransform>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osg/Geode>
#include <osg/LightSource>
#include <osg/TexGenNode>

#include <osgUtil/Optimizer>

#include <osgDB/Registry>
#include <osgDB/ReadFile>

#include <osgViewer/Viewer>

// for the grid data..
#include "../osghangglide/terrain_coords.h"

osg::Image* createSpotLightImage(const osg::Vec4& centerColour, const osg::Vec4& backgroudColour, unsigned int size, float power)
{
    osg::Image* image = new osg::Image;
    image->allocateImage(size,size,1,
                         GL_RGBA,GL_UNSIGNED_BYTE);

    float mid = (float(size)-1)*0.5f;
    float div = 2.0f/float(size);
    for(unsigned int r=0;r<size;++r)
    {
        unsigned char* ptr = image->data(0,r,0);
        for(unsigned int c=0;c<size;++c)
        {
            float dx = (float(c) - mid)*div;
            float dy = (float(r) - mid)*div;
            float pr = powf(1.0f-sqrtf(dx*dx+dy*dy),power);
            if (pr<0.0f) pr=0.0f;
            osg::Vec4 color = centerColour*pr+backgroudColour*(1.0f-pr);
            *ptr++ = (unsigned char)((color[0])*255.0f);
            *ptr++ = (unsigned char)((color[1])*255.0f);
            *ptr++ = (unsigned char)((color[2])*255.0f);
            *ptr++ = (unsigned char)((color[3])*255.0f);
        }
    }
    return image;

    //return osgDB::readImageFile("spot.dds");
}

osg::StateSet* createSpotLightDecoratorState(unsigned int lightNum, unsigned int textureUnit)
{
    osg::StateSet* stateset = new osg::StateSet;

    stateset->setMode(GL_LIGHT0+lightNum, osg::StateAttribute::ON);

    osg::Vec4 centerColour(1.0f,1.0f,1.0f,1.0f);
    osg::Vec4 ambientColour(0.05f,0.05f,0.05f,1.0f);

    // set up spot light texture
    osg::Texture2D* texture = new osg::Texture2D();
    texture->setImage(createSpotLightImage(centerColour, ambientColour, 64, 1.0));
    texture->setBorderColor(osg::Vec4(ambientColour));
    texture->setWrap(osg::Texture::WRAP_S,osg::Texture::CLAMP_TO_BORDER);
    texture->setWrap(osg::Texture::WRAP_T,osg::Texture::CLAMP_TO_BORDER);
    texture->setWrap(osg::Texture::WRAP_R,osg::Texture::CLAMP_TO_BORDER);

    stateset->setTextureAttributeAndModes(textureUnit, texture, osg::StateAttribute::ON);

    // set up tex gens
    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_S, osg::StateAttribute::ON);
    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_T, osg::StateAttribute::ON);
    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_R, osg::StateAttribute::ON);
    stateset->setTextureMode(textureUnit, GL_TEXTURE_GEN_Q, osg::StateAttribute::ON);

    return stateset;
}

osg::Node* createSpotLightNode(const osg::Vec3& position, const osg::Vec3& direction, float angle, unsigned int lightNum, unsigned int textureUnit)
{
    osg::Group* group = new osg::Group;

    // create light source.
    osg::LightSource* lightsource = new osg::LightSource;
    osg::Light* light = lightsource->getLight();
    light->setLightNum(lightNum);
    light->setPosition(osg::Vec4(position,1.0f));
    light->setAmbient(osg::Vec4(0.00f,0.00f,0.05f,1.0f));
    light->setDiffuse(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
    group->addChild(lightsource);

    // create tex gen.

    osg::Vec3 up(0.0f,0.0f,1.0f);
    up = (direction ^ up) ^ direction;
    up.normalize();

    osg::TexGenNode* texgenNode = new osg::TexGenNode;
    texgenNode->setTextureUnit(textureUnit);
    osg::TexGen* texgen = texgenNode->getTexGen();
    texgen->setMode(osg::TexGen::EYE_LINEAR);
    texgen->setPlanesFromMatrix(osg::Matrixd::lookAt(position, position+direction, up)*
                                osg::Matrixd::perspective(angle,1.0,0.1,100)*
                                osg::Matrixd::translate(1.0,1.0,1.0)*
                                osg::Matrixd::scale(0.5,0.5,0.5));

    group->addChild(texgenNode);

    return group;

}

osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime)
{
    // set up the animation path
    osg::AnimationPath* animationPath = new osg::AnimationPath;
    animationPath->setLoopMode(osg::AnimationPath::LOOP);

    int numSamples = 40;
    float yaw = 0.0f;
    float yaw_delta = 2.0f*osg::PI/((float)numSamples-1.0f);
    float roll = osg::inDegrees(30.0f);

    double time=0.0f;
    double time_delta = looptime/(double)numSamples;
    for(int i=0;i<numSamples;++i)
    {
        osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f));
        osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0))*osg::Quat(-(yaw+osg::inDegrees(90.0f)),osg::Vec3(0.0,0.0,1.0)));

        animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));

        yaw += yaw_delta;
        time += time_delta;

    }
    return animationPath;
}

osg::Node* createBase(const osg::Vec3& center,float radius)
{

    osg::Geode* geode = new osg::Geode;

    // set up the texture of the base.
    osg::StateSet* stateset = new osg::StateSet();
    osg::ref_ptr<osg::Image> image = osgDB::readRefImageFile("Images/lz.rgb");
    if (image)
    {
        osg::Texture2D* texture = new osg::Texture2D;
        texture->setImage(image);
        stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
    }

    geode->setStateSet( stateset );

    osg::HeightField* grid = new osg::HeightField;
    grid->allocate(38,39);
    grid->setOrigin(center+osg::Vec3(-radius,-radius,0.0f));
    grid->setXInterval(radius*2.0f/(float)(38-1));
    grid->setYInterval(radius*2.0f/(float)(39-1));

    float minHeight = FLT_MAX;
    float maxHeight = -FLT_MAX;

    unsigned int r;
    for(r=0;r<39;++r)
    {
        for(unsigned int c=0;c<38;++c)
        {
            float h = vertex[r+c*39][2];
            if (h>maxHeight) maxHeight=h;
            if (h<minHeight) minHeight=h;
        }
    }

    float hieghtScale = radius*0.5f/(maxHeight-minHeight);
    float hieghtOffset = -(minHeight+maxHeight)*0.5f;

    for(r=0;r<39;++r)
    {
        for(unsigned int c=0;c<38;++c)
        {
            float h = vertex[r+c*39][2];
            grid->setHeight(c,r,(h+hieghtOffset)*hieghtScale);
        }
    }

    geode->addDrawable(new osg::ShapeDrawable(grid));

    osg::Group* group = new osg::Group;
    group->addChild(geode);

    return group;

}

osg::Node* createMovingModel(const osg::Vec3& center, float radius)
{
    float animationLength = 10.0f;

    osg::AnimationPath* animationPath = createAnimationPath(center,radius,animationLength);

    osg::Group* model = new osg::Group;

    osg::ref_ptr<osg::Node> cessna = osgDB::readRefNodeFile("cessna.osgt");
    if (cessna)
    {
        const osg::BoundingSphere& bs = cessna->getBound();

        float size = radius/bs.radius()*0.3f;
        osg::MatrixTransform* positioned = new osg::MatrixTransform;
        positioned->setDataVariance(osg::Object::STATIC);
        positioned->setMatrix(osg::Matrix::translate(-bs.center())*
                              osg::Matrix::scale(size,size,size)*
                              osg::Matrix::rotate(osg::inDegrees(180.0f),0.0f,0.0f,2.0f));

        positioned->addChild(cessna);

        osg::MatrixTransform* xform = new osg::MatrixTransform;
        xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0));
        xform->addChild(positioned);

        xform->addChild(createSpotLightNode(osg::Vec3(0.0f,0.0f,0.0f), osg::Vec3(0.0f,1.0f,-1.0f), 60.0f, 0, 1));

        model->addChild(xform);
    }

    return model;
}

osg::Node* createModel()
{
    osg::Vec3 center(0.0f,0.0f,0.0f);
    float radius = 100.0f;

    // the shadower model
    osg::Node* shadower = createMovingModel(center,radius*0.5f);

    // the shadowed model
    osg::Node* shadowed = createBase(center-osg::Vec3(0.0f,0.0f,radius*0.1),radius);

    // combine the models together to create one which has the shadower and the shadowed with the required callback.
    osg::Group* root = new osg::Group;

    root->setStateSet(createSpotLightDecoratorState(0,1));

    root->addChild(shadower);
    root->addChild(shadowed);

    return root;
}

int main(int, char **)
{
    // construct the viewer.
    osgViewer::Viewer viewer;

    // add the spoit light model to the viewer
    viewer.setSceneData( createModel() );

    // run the viewer main frame loop.
    return viewer.run();
}
<|endoftext|>


<commit_before>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include <visionaray/math/constants.h>

namespace visionaray
{

//-------------------------------------------------------------------------------------------------
// point_light members
//

template <typename T>
template <typename U>
VSNRAY_FUNC
inline vector<3, U> point_light<T>::intensity(vector<3, U> const& pos) const
{
    U att(1.0);

#if 1 // use attenuation
    auto dist = length(vector<3, U>(position_) - pos);
    att = U(
        1.0 / (constant_attenuation_
             + linear_attenuation_    * dist
             + quadratic_attenuation_ * dist * dist)
        );
#endif

    return vector<3, U>(cl_ * kl_) * att;
}

template <typename T>
template <typename Generator, typename U>
VSNRAY_FUNC
inline light_sample<U> point_light<T>::sample(vector<3, U> const& reference_point, Generator& gen) const
{
    VSNRAY_UNUSED(reference_point);

    light_sample<U> result;

    auto pos = position();

    result.dir = pos - reference_point;
    result.dist = length(result.dir);
    result.intensity = intensity(vector<3, U>(pos)) * constants::pi<U>();
    result.normal = normalize( vector<3, U>(
            gen.next() * U(2.0) - U(1.0),
            gen.next() * U(2.0) - U(1.0),
            gen.next() * U(2.0) - U(1.0)
            ) );
    result.area = U(1.0);
    result.delta_light = true;

    return result;
}

template <typename T>
VSNRAY_FUNC
inline vector<3, T> point_light<T>::position() const
{
    return position_;
}

template <typename T>
VSNRAY_FUNC
inline T point_light<T>::constant_attenuation() const
{
    return constant_attenuation_;
}

template <typename T>
VSNRAY_FUNC
inline T point_light<T>::linear_attenuation() const
{
    return linear_attenuation_;
}

template <typename T>
VSNRAY_FUNC
inline T point_light<T>::quadratic_attenuation() const
{
    return quadratic_attenuation_;
}

template <typename T>
VSNRAY_FUNC
inline void point_light<T>::set_cl(vector<3, T> const& cl)
{
    cl_ = cl;
}

template <typename T>
VSNRAY_FUNC
inline void point_light<T>::set_kl(T kl)
{
    kl_ = kl;
}

template <typename T>
VSNRAY_FUNC
inline void point_light<T>::set_position(vector<3, T> const& pos)
{
    position_ = pos;
}

template <typename t>
VSNRAY_FUNC
inline void point_light<t>::set_constant_attenuation(t att)
{
    constant_attenuation_ = att;
}

template <typename t>
VSNRAY_FUNC
inline void point_light<t>::set_linear_attenuation(t att)
{
    linear_attenuation_ = att;
}

template <typename t>
VSNRAY_FUNC
inline void point_light<t>::set_quadratic_attenuation(t att)
{
    quadratic_attenuation_ = att;
}

} // visionaray
<commit_msg>Fewer relative paths<commit_after>// This file is distributed under the MIT license.
// See the LICENSE file for details.

#include "../math/constants.h"

namespace visionaray
{

//-------------------------------------------------------------------------------------------------
// point_light members
//

template <typename T>
template <typename U>
VSNRAY_FUNC
inline vector<3, U> point_light<T>::intensity(vector<3, U> const& pos) const
{
    U att(1.0);

#if 1 // use attenuation
    auto dist = length(vector<3, U>(position_) - pos);
    att = U(
        1.0 / (constant_attenuation_
             + linear_attenuation_    * dist
             + quadratic_attenuation_ * dist * dist)
        );
#endif

    return vector<3, U>(cl_ * kl_) * att;
}

template <typename T>
template <typename Generator, typename U>
VSNRAY_FUNC
inline light_sample<U> point_light<T>::sample(vector<3, U> const& reference_point, Generator& gen) const
{
    VSNRAY_UNUSED(reference_point);

    light_sample<U> result;

    auto pos = position();

    result.dir = pos - reference_point;
    result.dist = length(result.dir);
    result.intensity = intensity(vector<3, U>(pos)) * constants::pi<U>();
    result.normal = normalize( vector<3, U>(
            gen.next() * U(2.0) - U(1.0),
            gen.next() * U(2.0) - U(1.0),
            gen.next() * U(2.0) - U(1.0)
            ) );
    result.area = U(1.0);
    result.delta_light = true;

    return result;
}

template <typename T>
VSNRAY_FUNC
inline vector<3, T> point_light<T>::position() const
{
    return position_;
}

template <typename T>
VSNRAY_FUNC
inline T point_light<T>::constant_attenuation() const
{
    return constant_attenuation_;
}

template <typename T>
VSNRAY_FUNC
inline T point_light<T>::linear_attenuation() const
{
    return linear_attenuation_;
}

template <typename T>
VSNRAY_FUNC
inline T point_light<T>::quadratic_attenuation() const
{
    return quadratic_attenuation_;
}

template <typename T>
VSNRAY_FUNC
inline void point_light<T>::set_cl(vector<3, T> const& cl)
{
    cl_ = cl;
}

template <typename T>
VSNRAY_FUNC
inline void point_light<T>::set_kl(T kl)
{
    kl_ = kl;
}

template <typename T>
VSNRAY_FUNC
inline void point_light<T>::set_position(vector<3, T> const& pos)
{
    position_ = pos;
}

template <typename t>
VSNRAY_FUNC
inline void point_light<t>::set_constant_attenuation(t att)
{
    constant_attenuation_ = att;
}

template <typename t>
VSNRAY_FUNC
inline void point_light<t>::set_linear_attenuation(t att)
{
    linear_attenuation_ = att;
}

template <typename t>
VSNRAY_FUNC
inline void point_light<t>::set_quadratic_attenuation(t att)
{
    quadratic_attenuation_ = att;
}

} // visionaray
<|endoftext|>


<commit_before>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2013-2017 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/properties/collapsiblegroupboxwidgetqt.h>
#include <modules/qtwidgets/properties/compositepropertywidgetqt.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/properties/property.h>
#include <inviwo/core/util/settings/systemsettings.h>
#include <inviwo/core/properties/propertywidgetfactory.h>
#include <inviwo/core/network/processornetwork.h>
#include <modules/qtwidgets/editablelabelqt.h>

#include <warn/push>
#include <warn/ignore/all>
#include <QLineEdit>
#include <QToolButton>
#include <QGroupBox>
#include <QPushButton>
#include <QGridLayout>
#include <QLabel>
#include <QCheckBox>
#include <warn/pop>

namespace inviwo {

CollapsibleGroupBoxWidgetQt::CollapsibleGroupBoxWidgetQt(std::string displayName, bool isCheckable)
    : PropertyWidgetQt()
    , PropertyOwnerObserver()
    , displayName_(displayName)
    , collapsed_(false)
    , checked_(false)
    , propertyOwner_(nullptr)
    , showIfEmpty_(false)
    , checkable_(isCheckable) {
    setObjectName("CompositeWidget");

    generateWidget();
    updateFromProperty();
}

CollapsibleGroupBoxWidgetQt::CollapsibleGroupBoxWidgetQt(Property* property, bool isCheckable)
    : PropertyWidgetQt(property)
    , PropertyOwnerObserver()
    , displayName_(property->getDisplayName())
    , collapsed_(false)
    , checked_(false)
    , propertyOwner_(nullptr)
    , showIfEmpty_(false)
    , checkable_(isCheckable) {
    setObjectName("CompositeWidget");

    generateWidget();
    updateFromProperty();
}

void CollapsibleGroupBoxWidgetQt::generateWidget() {
    propertyWidgetGroupLayout_ = new QGridLayout();
    propertyWidgetGroupLayout_->setAlignment(Qt::AlignTop);
    propertyWidgetGroupLayout_->setContentsMargins(
        PropertyWidgetQt::spacing, PropertyWidgetQt::spacing, 0, PropertyWidgetQt::spacing);
    propertyWidgetGroupLayout_->setHorizontalSpacing(0);
    propertyWidgetGroupLayout_->setVerticalSpacing(PropertyWidgetQt::spacing);

    propertyWidgetGroup_ = new QWidget(this);
    propertyWidgetGroup_->setObjectName("CompositeContents");
    propertyWidgetGroup_->setLayout(propertyWidgetGroupLayout_);

    defaultLabel_ = new QLabel("No properties available");

    propertyWidgetGroupLayout_->addWidget(defaultLabel_, 0, 0);
    propertyWidgetGroupLayout_->addItem(
        new QSpacerItem(PropertyWidgetQt::spacing, 1, QSizePolicy::Fixed), 0, 1);
    propertyWidgetGroupLayout_->setColumnStretch(0, 1);
    propertyWidgetGroupLayout_->setColumnStretch(1, 0);

    btnCollapse_ = new QToolButton(this);
    btnCollapse_->setObjectName("collapseButton");
    btnCollapse_->setIcon(QIcon(":/stylesheets/images/arrow_lighter_down.png"));
    connect(btnCollapse_, &QToolButton::clicked, this,
            &CollapsibleGroupBoxWidgetQt::toggleCollapsed);

    if (property_) {
        label_ = new EditableLabelQt(this, property_, false);
    } else {
        label_ = new EditableLabelQt(this, displayName_, false);
    }
    label_->setObjectName("compositeLabel");
    QSizePolicy labelPol = label_->sizePolicy();
    labelPol.setHorizontalStretch(10);
    label_->setSizePolicy(labelPol);
    connect(label_, &EditableLabelQt::textChanged, this, [&](){setDisplayName(label_->getText());});

    QToolButton* resetButton = new QToolButton(this);
    resetButton->setIconSize(QSize(20, 20));
    resetButton->setObjectName("resetButton");
    connect(resetButton, &QToolButton::clicked, this, [&]() { property_->resetToDefaultState(); });
    resetButton->setToolTip(tr("Reset the group of properties to its default state"));

    checkBox_ = new QCheckBox(this);
    checkBox_->setMinimumSize(5, 5);
    checkBox_->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
    checkBox_->setChecked(checked_);
    checkBox_->setVisible(checkable_);

    QObject::connect(checkBox_, &QCheckBox::clicked, this,
                     [&]() { setChecked(checkBox_->isChecked()); });

    QHBoxLayout* heading = new QHBoxLayout();
    heading->setContentsMargins(0, 0, 0, 0);
    heading->setSpacing(PropertyWidgetQt::spacing);
    heading->addWidget(btnCollapse_);
    heading->addWidget(label_);
    heading->addStretch(1);
    heading->addWidget(checkBox_);
    heading->addWidget(resetButton);

    QVBoxLayout* layout = new QVBoxLayout();
    setSpacingAndMargins(layout);
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);
    layout->addLayout(heading);
    layout->addWidget(propertyWidgetGroup_);

    // Adjust the margins when using a border, i.e. margin >= border width.
    // Otherwise the border might be overdrawn by children.
    this->setContentsMargins(margin, margin, margin, margin);

    this->setLayout(layout);
}

QSize CollapsibleGroupBoxWidgetQt::sizeHint() const {
    QSize size = layout()->sizeHint();
    size.setWidth(std::max(PropertyWidgetQt::minimumWidth, size.width()));
    return size;
}

QSize CollapsibleGroupBoxWidgetQt::minimumSizeHint() const {
    QSize size = layout()->sizeHint();
    QSize minSize = layout()->minimumSize();
    size.setWidth(std::max(PropertyWidgetQt::minimumWidth, minSize.width()));
    return size;
}

void CollapsibleGroupBoxWidgetQt::addProperty(Property* prop) {
    properties_.push_back(prop);

    auto factory = InviwoApplication::getPtr()->getPropertyWidgetFactory();
    if (auto propertyWidget = static_cast<PropertyWidgetQt*>(factory->create(prop).release())) {
        if (auto collapsibleWidget = dynamic_cast<CollapsibleGroupBoxWidgetQt*>(propertyWidget)) {
            collapsibleWidget->setNestedDepth(this->getNestedDepth() + 1);
            // make the collapsible widget go all the way to the right border
            propertyWidgetGroupLayout_->addWidget(propertyWidget,
                                                  propertyWidgetGroupLayout_->rowCount(), 0, 1, -1);
        } else {  // not a collapsible widget
            propertyWidget->setNestedDepth(this->getNestedDepth());
            // property widget should only be added to the left column of the layout
            propertyWidgetGroupLayout_->addWidget(propertyWidget,
                                                  propertyWidgetGroupLayout_->rowCount(), 0);
        }

        propertyWidgets_.push_back(propertyWidget);
        prop->registerWidget(propertyWidget);
        connect(propertyWidget, &PropertyWidgetQt::updateSemantics, this,
                &CollapsibleGroupBoxWidgetQt::updatePropertyWidgetSemantics);

        propertyWidget->setParentPropertyWidget(this, getBaseContainer());
        propertyWidget->initState();

    } else {
        LogWarn("Could not find a widget for property: " << prop->getClassIdentifier());
    }
}

std::string CollapsibleGroupBoxWidgetQt::getDisplayName() const { return displayName_; }

void CollapsibleGroupBoxWidgetQt::setDisplayName(const std::string& displayName) {
    displayName_ = displayName;
    if (propertyOwner_) {
        if (Processor* p = dynamic_cast<Processor*>(propertyOwner_)) {
            try {
                p->setIdentifier(displayName);
            } catch(Exception& e) {
                label_->setText(p->getIdentifier());
                LogWarn(e.getMessage());
            }
        }
    }
}

const std::vector<Property*>& CollapsibleGroupBoxWidgetQt::getProperties() { return properties_; }

void CollapsibleGroupBoxWidgetQt::toggleCollapsed() { setCollapsed(!isCollapsed()); }

bool CollapsibleGroupBoxWidgetQt::isCollapsed() const { return collapsed_; }

bool CollapsibleGroupBoxWidgetQt::isChecked() const { return checked_; }

void CollapsibleGroupBoxWidgetQt::setChecked(bool checked) {
    if (!checkable_) {
        return;
    }

    checked_ = checked;
    // update checkbox
    checkBox_->setChecked(checked_);
}

bool CollapsibleGroupBoxWidgetQt::isCheckable() const { return checkable_; }

void CollapsibleGroupBoxWidgetQt::setCheckable(bool checkable) {
    if (checkable_ == checkable) {
        return;
    }

    checkable_ = checkable;
    // update header
    checkBox_->setVisible(checkable_);
}

void CollapsibleGroupBoxWidgetQt::setVisible(bool visible) {
    bool empty = util::all_of(properties_, [](Property* w) { return !w->getVisible(); });
    defaultLabel_->setVisible(empty);

    if (showIfEmpty_ || !empty) {
        PropertyWidgetQt::setVisible(visible);
    } else {
        PropertyWidgetQt::setVisible(false);
    }
}

void CollapsibleGroupBoxWidgetQt::setCollapsed(bool collapse) {
    setUpdatesEnabled(false);
    if (collapsed_ && !collapse) {
        propertyWidgetGroup_->show();
        btnCollapse_->setIcon(QIcon(":/stylesheets/images/arrow_lighter_down.png"));
    } else if (!collapsed_ && collapse) {
        propertyWidgetGroup_->hide();
        btnCollapse_->setIcon(QIcon(":/stylesheets/images/arrow_lighter_right.png"));
    }
    collapsed_ = collapse;
    setUpdatesEnabled(true);
}

void CollapsibleGroupBoxWidgetQt::updatePropertyWidgetSemantics(PropertyWidgetQt* widget) {
    setUpdatesEnabled(false);
    Property* prop = widget->getProperty();

    auto pit = std::find(properties_.begin(), properties_.end(), prop);
    auto wit = std::find(propertyWidgets_.begin(), propertyWidgets_.end(), widget);

    if (pit != properties_.end() && wit != propertyWidgets_.end()) {
        auto factory = InviwoApplication::getPtr()->getPropertyWidgetFactory();
        if (auto newWidget = static_cast<PropertyWidgetQt*>(factory->create(prop).release())) {
            prop->deregisterWidget(widget);

#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
            propertyWidgetGroupLayout_->replaceWidget(widget, newWidget,
                                                      Qt::FindDirectChildrenOnly);
#else
            int layoutPosition = propertyWidgetGroupLayout_->indexOf(widget);
            propertyWidgetGroupLayout_->removeWidget(widget);
            propertyWidgetGroupLayout_->addWidget(newWidget, layoutPosition, 0);
#endif  // QT_VERSION >= 5.2
            widget->deleteLater();

            prop->registerWidget(newWidget);
            // Replace the item in propertyWidgets_;
            *wit = newWidget;

            connect(newWidget, SIGNAL(updateSemantics(PropertyWidgetQt*)), this,
                    SLOT(updatePropertyWidgetSemantics(PropertyWidgetQt*)));

            newWidget->setNestedDepth(this->getNestedDepth());
            newWidget->setParentPropertyWidget(this, getBaseContainer());
            newWidget->initState();

        } else {
            LogWarn("Could not change semantic for property: " << prop->getClassIdentifier());
        }
    }
    setUpdatesEnabled(true);
}

void CollapsibleGroupBoxWidgetQt::onDidAddProperty(Property* prop, size_t index) {
    setUpdatesEnabled(false);
    std::vector<Property*>::iterator insertPoint = properties_.begin() + index;
    if (insertPoint != properties_.end()) ++insertPoint;

    properties_.insert(insertPoint, prop);

    auto factory = InviwoApplication::getPtr()->getPropertyWidgetFactory();
    if (auto propertyWidget = static_cast<PropertyWidgetQt*>(factory->create(prop).release())) {
        const int insertPos = static_cast<int>(index) + 1;

        if (auto collapsibleWidget = dynamic_cast<CollapsibleGroupBoxWidgetQt*>(propertyWidget)) {
            collapsibleWidget->setNestedDepth(this->getNestedDepth() + 1);
            // make the collapsible widget go all the way to the right border
            propertyWidgetGroupLayout_->addWidget(propertyWidget, insertPos, 0, 1, -1);

        } else {  // not a collapsible widget
            propertyWidget->setNestedDepth(this->getNestedDepth());
            // property widget should only be added to the left column of the layout
            propertyWidgetGroupLayout_->addWidget(propertyWidget, insertPos, 0);
        }

        auto widgetInsertPoint = propertyWidgets_.begin() + index;
        if (widgetInsertPoint != propertyWidgets_.end()) ++widgetInsertPoint;

        propertyWidgets_.insert(widgetInsertPoint, propertyWidget);
        prop->registerWidget(propertyWidget);
        connect(propertyWidget, SIGNAL(updateSemantics(PropertyWidgetQt*)), this,
                SLOT(updatePropertyWidgetSemantics(PropertyWidgetQt*)));

        propertyWidget->setParentPropertyWidget(this, getBaseContainer());
        propertyWidget->initState();

    } else {
        LogWarn("Could not find a widget for property: " << prop->getClassIdentifier());
    }
    setUpdatesEnabled(true);
}

void CollapsibleGroupBoxWidgetQt::onWillRemoveProperty(Property* prop, size_t index) {
    PropertyWidgetQt* propertyWidget = propertyWidgets_[index];

    propertyWidgetGroupLayout_->removeWidget(propertyWidget);
    propertyWidgets_.erase(propertyWidgets_.begin() + index);
    properties_.erase(properties_.begin() + index);
    propertyWidget->deleteLater();
}

void CollapsibleGroupBoxWidgetQt::onProcessorIdentifierChange(Processor* processor) {
    displayName_ = processor->getIdentifier();
    label_->setText(processor->getIdentifier());
}

void CollapsibleGroupBoxWidgetQt::setPropertyOwner(PropertyOwner* propertyOwner) {
    propertyOwner_ = propertyOwner;
}

PropertyOwner* CollapsibleGroupBoxWidgetQt::getPropertyOwner() const { return propertyOwner_; }

const std::vector<PropertyWidgetQt*>& CollapsibleGroupBoxWidgetQt::getPropertyWidgets() {
    return propertyWidgets_;
}

void CollapsibleGroupBoxWidgetQt::setShowIfEmpty(bool val) { showIfEmpty_ = val; }
}  // namespace
<commit_msg>QtWidgets: Prevent crash CollapsibleGroupBoxWidgetQt when reseting a processors and not a property, closes inviwo/inviwo-dev#1673<commit_after>/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2013-2017 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/properties/collapsiblegroupboxwidgetqt.h>
#include <modules/qtwidgets/properties/compositepropertywidgetqt.h>
#include <inviwo/core/common/inviwoapplication.h>
#include <inviwo/core/properties/property.h>
#include <inviwo/core/util/settings/systemsettings.h>
#include <inviwo/core/properties/propertywidgetfactory.h>
#include <inviwo/core/network/processornetwork.h>
#include <modules/qtwidgets/editablelabelqt.h>

#include <warn/push>
#include <warn/ignore/all>
#include <QLineEdit>
#include <QToolButton>
#include <QGroupBox>
#include <QPushButton>
#include <QGridLayout>
#include <QLabel>
#include <QCheckBox>
#include <warn/pop>

namespace inviwo {

CollapsibleGroupBoxWidgetQt::CollapsibleGroupBoxWidgetQt(std::string displayName, bool isCheckable)
    : PropertyWidgetQt()
    , PropertyOwnerObserver()
    , displayName_(displayName)
    , collapsed_(false)
    , checked_(false)
    , propertyOwner_(nullptr)
    , showIfEmpty_(false)
    , checkable_(isCheckable) {
    setObjectName("CompositeWidget");

    generateWidget();
    updateFromProperty();
}

CollapsibleGroupBoxWidgetQt::CollapsibleGroupBoxWidgetQt(Property* property, bool isCheckable)
    : PropertyWidgetQt(property)
    , PropertyOwnerObserver()
    , displayName_(property->getDisplayName())
    , collapsed_(false)
    , checked_(false)
    , propertyOwner_(nullptr)
    , showIfEmpty_(false)
    , checkable_(isCheckable) {
    setObjectName("CompositeWidget");

    generateWidget();
    updateFromProperty();
}

void CollapsibleGroupBoxWidgetQt::generateWidget() {
    propertyWidgetGroupLayout_ = new QGridLayout();
    propertyWidgetGroupLayout_->setAlignment(Qt::AlignTop);
    propertyWidgetGroupLayout_->setContentsMargins(
        PropertyWidgetQt::spacing, PropertyWidgetQt::spacing, 0, PropertyWidgetQt::spacing);
    propertyWidgetGroupLayout_->setHorizontalSpacing(0);
    propertyWidgetGroupLayout_->setVerticalSpacing(PropertyWidgetQt::spacing);

    propertyWidgetGroup_ = new QWidget(this);
    propertyWidgetGroup_->setObjectName("CompositeContents");
    propertyWidgetGroup_->setLayout(propertyWidgetGroupLayout_);

    defaultLabel_ = new QLabel("No properties available");

    propertyWidgetGroupLayout_->addWidget(defaultLabel_, 0, 0);
    propertyWidgetGroupLayout_->addItem(
        new QSpacerItem(PropertyWidgetQt::spacing, 1, QSizePolicy::Fixed), 0, 1);
    propertyWidgetGroupLayout_->setColumnStretch(0, 1);
    propertyWidgetGroupLayout_->setColumnStretch(1, 0);

    btnCollapse_ = new QToolButton(this);
    btnCollapse_->setObjectName("collapseButton");
    btnCollapse_->setIcon(QIcon(":/stylesheets/images/arrow_lighter_down.png"));
    connect(btnCollapse_, &QToolButton::clicked, this,
            &CollapsibleGroupBoxWidgetQt::toggleCollapsed);

    if (property_) {
        label_ = new EditableLabelQt(this, property_, false);
    } else {
        label_ = new EditableLabelQt(this, displayName_, false);
    }
    label_->setObjectName("compositeLabel");
    QSizePolicy labelPol = label_->sizePolicy();
    labelPol.setHorizontalStretch(10);
    label_->setSizePolicy(labelPol);
    connect(label_, &EditableLabelQt::textChanged, this, [&](){setDisplayName(label_->getText());});

    QToolButton* resetButton = new QToolButton(this);
    resetButton->setIconSize(QSize(20, 20));
    resetButton->setObjectName("resetButton");
    connect(resetButton, &QToolButton::clicked, this, [&]() {
        if (property_) {
            property_->resetToDefaultState();
        } else if (auto processor = dynamic_cast<Processor*>(propertyOwner_)) {
            processor->resetAllPoperties();
        }
    });

    resetButton->setToolTip(tr("Reset the group of properties to its default state"));

    checkBox_ = new QCheckBox(this);
    checkBox_->setMinimumSize(5, 5);
    checkBox_->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred));
    checkBox_->setChecked(checked_);
    checkBox_->setVisible(checkable_);

    QObject::connect(checkBox_, &QCheckBox::clicked, this,
                     [&]() { setChecked(checkBox_->isChecked()); });

    QHBoxLayout* heading = new QHBoxLayout();
    heading->setContentsMargins(0, 0, 0, 0);
    heading->setSpacing(PropertyWidgetQt::spacing);
    heading->addWidget(btnCollapse_);
    heading->addWidget(label_);
    heading->addStretch(1);
    heading->addWidget(checkBox_);
    heading->addWidget(resetButton);

    QVBoxLayout* layout = new QVBoxLayout();
    setSpacingAndMargins(layout);
    layout->setContentsMargins(0, 0, 0, 0);
    layout->setSpacing(0);
    layout->addLayout(heading);
    layout->addWidget(propertyWidgetGroup_);

    // Adjust the margins when using a border, i.e. margin >= border width.
    // Otherwise the border might be overdrawn by children.
    this->setContentsMargins(margin, margin, margin, margin);

    this->setLayout(layout);
}

QSize CollapsibleGroupBoxWidgetQt::sizeHint() const {
    QSize size = layout()->sizeHint();
    size.setWidth(std::max(PropertyWidgetQt::minimumWidth, size.width()));
    return size;
}

QSize CollapsibleGroupBoxWidgetQt::minimumSizeHint() const {
    QSize size = layout()->sizeHint();
    QSize minSize = layout()->minimumSize();
    size.setWidth(std::max(PropertyWidgetQt::minimumWidth, minSize.width()));
    return size;
}

void CollapsibleGroupBoxWidgetQt::addProperty(Property* prop) {
    properties_.push_back(prop);

    auto factory = InviwoApplication::getPtr()->getPropertyWidgetFactory();
    if (auto propertyWidget = static_cast<PropertyWidgetQt*>(factory->create(prop).release())) {
        if (auto collapsibleWidget = dynamic_cast<CollapsibleGroupBoxWidgetQt*>(propertyWidget)) {
            collapsibleWidget->setNestedDepth(this->getNestedDepth() + 1);
            // make the collapsible widget go all the way to the right border
            propertyWidgetGroupLayout_->addWidget(propertyWidget,
                                                  propertyWidgetGroupLayout_->rowCount(), 0, 1, -1);
        } else {  // not a collapsible widget
            propertyWidget->setNestedDepth(this->getNestedDepth());
            // property widget should only be added to the left column of the layout
            propertyWidgetGroupLayout_->addWidget(propertyWidget,
                                                  propertyWidgetGroupLayout_->rowCount(), 0);
        }

        propertyWidgets_.push_back(propertyWidget);
        prop->registerWidget(propertyWidget);
        connect(propertyWidget, &PropertyWidgetQt::updateSemantics, this,
                &CollapsibleGroupBoxWidgetQt::updatePropertyWidgetSemantics);

        propertyWidget->setParentPropertyWidget(this, getBaseContainer());
        propertyWidget->initState();

    } else {
        LogWarn("Could not find a widget for property: " << prop->getClassIdentifier());
    }
}

std::string CollapsibleGroupBoxWidgetQt::getDisplayName() const { return displayName_; }

void CollapsibleGroupBoxWidgetQt::setDisplayName(const std::string& displayName) {
    displayName_ = displayName;
    if (propertyOwner_) {
        if (Processor* p = dynamic_cast<Processor*>(propertyOwner_)) {
            try {
                p->setIdentifier(displayName);
            } catch(Exception& e) {
                label_->setText(p->getIdentifier());
                LogWarn(e.getMessage());
            }
        }
    }
}

const std::vector<Property*>& CollapsibleGroupBoxWidgetQt::getProperties() { return properties_; }

void CollapsibleGroupBoxWidgetQt::toggleCollapsed() { setCollapsed(!isCollapsed()); }

bool CollapsibleGroupBoxWidgetQt::isCollapsed() const { return collapsed_; }

bool CollapsibleGroupBoxWidgetQt::isChecked() const { return checked_; }

void CollapsibleGroupBoxWidgetQt::setChecked(bool checked) {
    if (!checkable_) {
        return;
    }

    checked_ = checked;
    // update checkbox
    checkBox_->setChecked(checked_);
}

bool CollapsibleGroupBoxWidgetQt::isCheckable() const { return checkable_; }

void CollapsibleGroupBoxWidgetQt::setCheckable(bool checkable) {
    if (checkable_ == checkable) {
        return;
    }

    checkable_ = checkable;
    // update header
    checkBox_->setVisible(checkable_);
}

void CollapsibleGroupBoxWidgetQt::setVisible(bool visible) {
    bool empty = util::all_of(properties_, [](Property* w) { return !w->getVisible(); });
    defaultLabel_->setVisible(empty);

    if (showIfEmpty_ || !empty) {
        PropertyWidgetQt::setVisible(visible);
    } else {
        PropertyWidgetQt::setVisible(false);
    }
}

void CollapsibleGroupBoxWidgetQt::setCollapsed(bool collapse) {
    setUpdatesEnabled(false);
    if (collapsed_ && !collapse) {
        propertyWidgetGroup_->show();
        btnCollapse_->setIcon(QIcon(":/stylesheets/images/arrow_lighter_down.png"));
    } else if (!collapsed_ && collapse) {
        propertyWidgetGroup_->hide();
        btnCollapse_->setIcon(QIcon(":/stylesheets/images/arrow_lighter_right.png"));
    }
    collapsed_ = collapse;
    setUpdatesEnabled(true);
}

void CollapsibleGroupBoxWidgetQt::updatePropertyWidgetSemantics(PropertyWidgetQt* widget) {
    setUpdatesEnabled(false);
    Property* prop = widget->getProperty();

    auto pit = std::find(properties_.begin(), properties_.end(), prop);
    auto wit = std::find(propertyWidgets_.begin(), propertyWidgets_.end(), widget);

    if (pit != properties_.end() && wit != propertyWidgets_.end()) {
        auto factory = InviwoApplication::getPtr()->getPropertyWidgetFactory();
        if (auto newWidget = static_cast<PropertyWidgetQt*>(factory->create(prop).release())) {
            prop->deregisterWidget(widget);

#if (QT_VERSION >= QT_VERSION_CHECK(5, 2, 0))
            propertyWidgetGroupLayout_->replaceWidget(widget, newWidget,
                                                      Qt::FindDirectChildrenOnly);
#else
            int layoutPosition = propertyWidgetGroupLayout_->indexOf(widget);
            propertyWidgetGroupLayout_->removeWidget(widget);
            propertyWidgetGroupLayout_->addWidget(newWidget, layoutPosition, 0);
#endif  // QT_VERSION >= 5.2
            widget->deleteLater();

            prop->registerWidget(newWidget);
            // Replace the item in propertyWidgets_;
            *wit = newWidget;

            connect(newWidget, SIGNAL(updateSemantics(PropertyWidgetQt*)), this,
                    SLOT(updatePropertyWidgetSemantics(PropertyWidgetQt*)));

            newWidget->setNestedDepth(this->getNestedDepth());
            newWidget->setParentPropertyWidget(this, getBaseContainer());
            newWidget->initState();

        } else {
            LogWarn("Could not change semantic for property: " << prop->getClassIdentifier());
        }
    }
    setUpdatesEnabled(true);
}

void CollapsibleGroupBoxWidgetQt::onDidAddProperty(Property* prop, size_t index) {
    setUpdatesEnabled(false);
    std::vector<Property*>::iterator insertPoint = properties_.begin() + index;
    if (insertPoint != properties_.end()) ++insertPoint;

    properties_.insert(insertPoint, prop);

    auto factory = InviwoApplication::getPtr()->getPropertyWidgetFactory();
    if (auto propertyWidget = static_cast<PropertyWidgetQt*>(factory->create(prop).release())) {
        const int insertPos = static_cast<int>(index) + 1;

        if (auto collapsibleWidget = dynamic_cast<CollapsibleGroupBoxWidgetQt*>(propertyWidget)) {
            collapsibleWidget->setNestedDepth(this->getNestedDepth() + 1);
            // make the collapsible widget go all the way to the right border
            propertyWidgetGroupLayout_->addWidget(propertyWidget, insertPos, 0, 1, -1);

        } else {  // not a collapsible widget
            propertyWidget->setNestedDepth(this->getNestedDepth());
            // property widget should only be added to the left column of the layout
            propertyWidgetGroupLayout_->addWidget(propertyWidget, insertPos, 0);
        }

        auto widgetInsertPoint = propertyWidgets_.begin() + index;
        if (widgetInsertPoint != propertyWidgets_.end()) ++widgetInsertPoint;

        propertyWidgets_.insert(widgetInsertPoint, propertyWidget);
        prop->registerWidget(propertyWidget);
        connect(propertyWidget, SIGNAL(updateSemantics(PropertyWidgetQt*)), this,
                SLOT(updatePropertyWidgetSemantics(PropertyWidgetQt*)));

        propertyWidget->setParentPropertyWidget(this, getBaseContainer());
        propertyWidget->initState();

    } else {
        LogWarn("Could not find a widget for property: " << prop->getClassIdentifier());
    }
    setUpdatesEnabled(true);
}

void CollapsibleGroupBoxWidgetQt::onWillRemoveProperty(Property* prop, size_t index) {
    PropertyWidgetQt* propertyWidget = propertyWidgets_[index];

    propertyWidgetGroupLayout_->removeWidget(propertyWidget);
    propertyWidgets_.erase(propertyWidgets_.begin() + index);
    properties_.erase(properties_.begin() + index);
    propertyWidget->deleteLater();
}

void CollapsibleGroupBoxWidgetQt::onProcessorIdentifierChange(Processor* processor) {
    displayName_ = processor->getIdentifier();
    label_->setText(processor->getIdentifier());
}

void CollapsibleGroupBoxWidgetQt::setPropertyOwner(PropertyOwner* propertyOwner) {
    propertyOwner_ = propertyOwner;
}

PropertyOwner* CollapsibleGroupBoxWidgetQt::getPropertyOwner() const { return propertyOwner_; }

const std::vector<PropertyWidgetQt*>& CollapsibleGroupBoxWidgetQt::getPropertyWidgets() {
    return propertyWidgets_;
}

void CollapsibleGroupBoxWidgetQt::setShowIfEmpty(bool val) { showIfEmpty_ = val; }
}  // namespace
<|endoftext|>


<commit_before>// Copyright (c) 2015, Matthew Malensek.
// Distributed under the BSD 2-Clause License (see LICENSE.txt for details)

#include "3RVX.h"

#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "Wtsapi32.lib")

#include <Windows.h>
#include <ctime>
#include <gdiplus.h>
#include <iostream>
#include <Wtsapi32.h>

#include "DisplayManager.h"
#include "HotkeyManager.h"
#include "Logger.h"
#include "OSD/BrightnessOSD.h"
#include "OSD/EjectOSD.h"
#include "OSD/VolumeOSD.h"
#include "Settings.h"
#include "Skin/SkinManager.h"

int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR lpCmdLine, _In_ int nShowCmd) {

    Logger::Start();

    QCLOG(L"  _____ ______     ____  _______ ");
    QCLOG(L" |___ /|  _ \\ \\   / /\\ \\/ /___ / ");
    QCLOG(L"   |_ \\| |_) \\ \\ / /  \\  /  |_ \\ ");
    QCLOG(L"  ___) |  _ < \\ V /   /  \\ ___) |");
    QCLOG(L" |____/|_| \\_\\ \\_/   /_/\\_\\____/ ");
    QCLOG(L"");

    QCLOG(L"Starting up...");

    HANDLE mutex;
    mutex = CreateMutex(NULL, FALSE, L"Local\\3RVX");
    if (GetLastError() == ERROR_ALREADY_EXISTS) {
        if (mutex) {
            ReleaseMutex(mutex);
        }

        CLOG(L"A previous instance of the program is already running.\n"
            L"Requesting Settings dialog.");
        _3RVX::Message(_3RVX::MSG_SETTINGS, NULL);

#if defined(ENABLE_3RVX_LOG) && (defined(ENABLE_3RVX_LOGTOFILE) == FALSE)
        CLOG(L"Press [enter] to terminate");
        std::cin.get();
#endif

        return EXIT_SUCCESS;
    }

    CLOG(L"App directory: %s", Settings::AppDir().c_str());

    using namespace Gdiplus;
    ULONG_PTR gdiplusToken;
    GdiplusStartupInput gdiplusStartupInput;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    _3RVX mainWnd(hInstance);

    HRESULT hr = CoInitializeEx(NULL,
        COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    if (hr != S_OK) {
        CLOG(L"Failed to initialize the COM library.");
        return EXIT_FAILURE;
    }

    /* Tell the program to initialize */
    PostMessage(mainWnd.Handle(), _3RVX::WM_3RVX_CTRL, _3RVX::MSG_LOAD, NULL);

    /* Register for session change notifications */
    WTSRegisterSessionNotification(mainWnd.Handle(), NOTIFY_FOR_THIS_SESSION);

    /* Start the event loop */
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    GdiplusShutdown(gdiplusToken);
    CoUninitialize();

    Logger::Stop();

    return (int) msg.wParam;
}

_3RVX::_3RVX(HINSTANCE hInstance) :
Window(_3RVX::CLASS_3RVX, _3RVX::CLASS_3RVX, hInstance) {
}

void _3RVX::Initialize() {
    CLOG(L"Initializing...");

    delete _vOSD;
    delete _eOSD;
    delete _bOSD;

    Settings *settings = Settings::Instance();
    settings->Load();

    KillTimer(Window::Handle(), TIMER_FIRSTUPDATE);
    KillTimer(Window::Handle(), TIMER_UPDATE);
    if (settings->AutomaticUpdates()) {
        SetTimer(
            Window::Handle(),
            TIMER_FIRSTUPDATE,
            FIRSTUPDATE_INTERVAL,
            NULL);
    }

    SkinManager::Instance()->LoadSkin(settings->SkinXML());

    DisplayManager::UpdateMonitorMap();

    /* OSDs */
    _eOSD = new EjectOSD();
    _vOSD = new VolumeOSD();
    _bOSD = new BrightnessOSD();

    _osds.clear();
    _osds.push_back(_eOSD);
    _osds.push_back(_vOSD);
    _osds.push_back(_bOSD);

    /* Hotkey setup */
    if (_hkManager != NULL) {
        _hkManager->Shutdown();
    }
    _hkManager = HotkeyManager::Instance(Handle());

    _hotkeys = Settings::Instance()->Hotkeys();
    for (auto it = _hotkeys.begin(); it != _hotkeys.end(); ++it) {
        /* Enable arg caching */
        it->second.EnableArgCache();

        int combination = it->first;
        _hkManager->Register(combination);
    }
}

void _3RVX::ProcessHotkeys(HotkeyInfo &hki) {
    switch (hki.action) {
    case HotkeyInfo::IncreaseVolume:
    case HotkeyInfo::DecreaseVolume:
    case HotkeyInfo::SetVolume:
    case HotkeyInfo::Mute:
    case HotkeyInfo::VolumeSlider:
        if (_vOSD) {
            _vOSD->ProcessHotkeys(hki);
        }
        break;

    case HotkeyInfo::EjectDrive:
    case HotkeyInfo::EjectLastDisk:
        if (_eOSD) {
            _eOSD->ProcessHotkeys(hki);
        }
        break;

    case HotkeyInfo::IncreaseBrightness:
    case HotkeyInfo::DecreaseBrightness:
    case HotkeyInfo::SetBrightness:
        if (_bOSD) {
            _bOSD->ProcessHotkeys(hki);
        }
        break;

    case HotkeyInfo::MediaKey:
    case HotkeyInfo::VirtualKey:
        _kbHotkeyProcessor.ProcessHotkeys(hki);
        break;

    case HotkeyInfo::Run:
        if (hki.HasArgs()) {
            ShellExecute(NULL, L"open", hki.args[0].c_str(),
                NULL, NULL, SW_SHOWNORMAL);
        }
        break;

    case HotkeyInfo::DisableOSD:
        ToggleOSDs();
        break;

    case HotkeyInfo::Settings:
        ShellExecute(NULL, L"open", Settings::SettingsApp().c_str(),
            NULL, NULL, SW_SHOWNORMAL);
        break;

    case HotkeyInfo::Exit:
        SendMessage(Handle(), WM_CLOSE, NULL, NULL);
        break;
    }
}

void _3RVX::ToggleOSDs() {
    _eOSD->Enabled(!(_eOSD->Enabled()));
    _vOSD->Enabled(!(_vOSD->Enabled()));
    _bOSD->Enabled(!(_bOSD->Enabled()));
}

LRESULT _3RVX::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
    case WM_HOTKEY: {
        CLOG(L"Hotkey: %d", (int) wParam);
        HotkeyInfo hki = _hotkeys[(int) wParam];
        ProcessHotkeys(hki);
        break;
    }

    case WM_WTSSESSION_CHANGE: {
        CLOG(L"Detected session change");
        break;
    }

    case WM_CLOSE: {
        CLOG(L"Shutting down");
        HotkeyManager::Instance()->Shutdown();
        _vOSD->HideIcon();
        break;
    }

    case WM_DESTROY: {
        PostQuitMessage(0);
        break;
    }

    case WM_TIMER:
        if (wParam == TIMER_FIRSTUPDATE || wParam == TIMER_UPDATE) {
            CLOG(L"Received updater timer notification");
            Settings *settings = Settings::Instance();
            long long checkTime = settings->LastUpdateCheck();
            if ((std::time(nullptr) - checkTime) > (UPDATE_INTERVAL / 1000)) {
                /* Enough time has elapsed since the last update check */
                std::wstring settingsApp = Settings::SettingsApp();
                CLOG(L"Launching update task: %s %s",
                    settingsApp.c_str(), L"-update");
                ShellExecute(NULL, L"open",
                    Settings::SettingsApp().c_str(), L"-update", NULL, SW_HIDE);
            }

            if (wParam == TIMER_FIRSTUPDATE) {
                CLOG(L"Starting long-term update timer");
                /* If this was the first update check (30 min after launch),
                 * then kill the first update timer and start the main timer
                 * (checks on 24-hour intervals) */
                KillTimer(Window::Handle(), TIMER_FIRSTUPDATE);
                SetTimer(Window::Handle(), TIMER_UPDATE,
                    UPDATE_INTERVAL, NULL);
            }
        }
        break;
    }

    if (message == _3RVX::WM_3RVX_CTRL) {
        switch (wParam) {
        case _3RVX::MSG_LOAD:
            Initialize();
            break;

        case _3RVX::MSG_SETTINGS:
            Settings::LaunchSettingsApp();
            break;

        case _3RVX::MSG_HIDEOSD:
            int except = (OSDType) lParam;
            switch (except) {
            case Volume:
                if (_eOSD) { _eOSD->Hide(); }
                if (_bOSD) { _bOSD->Hide(); }
                break;

            case Eject:
                if (_vOSD) { _vOSD->Hide(); }
                if (_bOSD) { _bOSD->Hide(); }
                break;

            case Brightness:
                if (_vOSD) { _vOSD->Hide(); }
                if (_eOSD) { _eOSD->Hide(); }
            }

            break;
        }
    }

    return Window::WndProc(hWnd, message, wParam, lParam);
}
<commit_msg>Refactor ToggleOSDs<commit_after>// Copyright (c) 2015, Matthew Malensek.
// Distributed under the BSD 2-Clause License (see LICENSE.txt for details)

#include "3RVX.h"

#pragma comment(lib, "gdiplus.lib")
#pragma comment(lib, "Wtsapi32.lib")

#include <Windows.h>
#include <ctime>
#include <gdiplus.h>
#include <iostream>
#include <Wtsapi32.h>

#include "DisplayManager.h"
#include "HotkeyManager.h"
#include "Logger.h"
#include "OSD/BrightnessOSD.h"
#include "OSD/EjectOSD.h"
#include "OSD/VolumeOSD.h"
#include "Settings.h"
#include "Skin/SkinManager.h"

int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
    _In_ LPWSTR lpCmdLine, _In_ int nShowCmd) {

    Logger::Start();

    QCLOG(L"  _____ ______     ____  _______ ");
    QCLOG(L" |___ /|  _ \\ \\   / /\\ \\/ /___ / ");
    QCLOG(L"   |_ \\| |_) \\ \\ / /  \\  /  |_ \\ ");
    QCLOG(L"  ___) |  _ < \\ V /   /  \\ ___) |");
    QCLOG(L" |____/|_| \\_\\ \\_/   /_/\\_\\____/ ");
    QCLOG(L"");

    QCLOG(L"Starting up...");

    HANDLE mutex;
    mutex = CreateMutex(NULL, FALSE, L"Local\\3RVX");
    if (GetLastError() == ERROR_ALREADY_EXISTS) {
        if (mutex) {
            ReleaseMutex(mutex);
        }

        CLOG(L"A previous instance of the program is already running.\n"
            L"Requesting Settings dialog.");
        _3RVX::Message(_3RVX::MSG_SETTINGS, NULL);

#if defined(ENABLE_3RVX_LOG) && (defined(ENABLE_3RVX_LOGTOFILE) == FALSE)
        CLOG(L"Press [enter] to terminate");
        std::cin.get();
#endif

        return EXIT_SUCCESS;
    }

    CLOG(L"App directory: %s", Settings::AppDir().c_str());

    using namespace Gdiplus;
    ULONG_PTR gdiplusToken;
    GdiplusStartupInput gdiplusStartupInput;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

    _3RVX mainWnd(hInstance);

    HRESULT hr = CoInitializeEx(NULL,
        COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
    if (hr != S_OK) {
        CLOG(L"Failed to initialize the COM library.");
        return EXIT_FAILURE;
    }

    /* Tell the program to initialize */
    PostMessage(mainWnd.Handle(), _3RVX::WM_3RVX_CTRL, _3RVX::MSG_LOAD, NULL);

    /* Register for session change notifications */
    WTSRegisterSessionNotification(mainWnd.Handle(), NOTIFY_FOR_THIS_SESSION);

    /* Start the event loop */
    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    GdiplusShutdown(gdiplusToken);
    CoUninitialize();

    Logger::Stop();

    return (int) msg.wParam;
}

_3RVX::_3RVX(HINSTANCE hInstance) :
Window(_3RVX::CLASS_3RVX, _3RVX::CLASS_3RVX, hInstance) {
}

void _3RVX::Initialize() {
    CLOG(L"Initializing...");

    delete _vOSD;
    delete _eOSD;
    delete _bOSD;

    Settings *settings = Settings::Instance();
    settings->Load();

    KillTimer(Window::Handle(), TIMER_FIRSTUPDATE);
    KillTimer(Window::Handle(), TIMER_UPDATE);
    if (settings->AutomaticUpdates()) {
        SetTimer(
            Window::Handle(),
            TIMER_FIRSTUPDATE,
            FIRSTUPDATE_INTERVAL,
            NULL);
    }

    SkinManager::Instance()->LoadSkin(settings->SkinXML());

    DisplayManager::UpdateMonitorMap();

    /* OSDs */
    _eOSD = new EjectOSD();
    _vOSD = new VolumeOSD();
    _bOSD = new BrightnessOSD();

    _osds.clear();
    _osds.push_back(_eOSD);
    _osds.push_back(_vOSD);
    _osds.push_back(_bOSD);

    /* Hotkey setup */
    if (_hkManager != NULL) {
        _hkManager->Shutdown();
    }
    _hkManager = HotkeyManager::Instance(Handle());

    _hotkeys = Settings::Instance()->Hotkeys();
    for (auto it = _hotkeys.begin(); it != _hotkeys.end(); ++it) {
        /* Enable arg caching */
        it->second.EnableArgCache();

        int combination = it->first;
        _hkManager->Register(combination);
    }
}

void _3RVX::ProcessHotkeys(HotkeyInfo &hki) {
    switch (hki.action) {
    case HotkeyInfo::IncreaseVolume:
    case HotkeyInfo::DecreaseVolume:
    case HotkeyInfo::SetVolume:
    case HotkeyInfo::Mute:
    case HotkeyInfo::VolumeSlider:
        if (_vOSD) {
            _vOSD->ProcessHotkeys(hki);
        }
        break;

    case HotkeyInfo::EjectDrive:
    case HotkeyInfo::EjectLastDisk:
        if (_eOSD) {
            _eOSD->ProcessHotkeys(hki);
        }
        break;

    case HotkeyInfo::IncreaseBrightness:
    case HotkeyInfo::DecreaseBrightness:
    case HotkeyInfo::SetBrightness:
        if (_bOSD) {
            _bOSD->ProcessHotkeys(hki);
        }
        break;

    case HotkeyInfo::MediaKey:
    case HotkeyInfo::VirtualKey:
        _kbHotkeyProcessor.ProcessHotkeys(hki);
        break;

    case HotkeyInfo::Run:
        if (hki.HasArgs()) {
            ShellExecute(NULL, L"open", hki.args[0].c_str(),
                NULL, NULL, SW_SHOWNORMAL);
        }
        break;

    case HotkeyInfo::DisableOSD:
        ToggleOSDs();
        break;

    case HotkeyInfo::Settings:
        ShellExecute(NULL, L"open", Settings::SettingsApp().c_str(),
            NULL, NULL, SW_SHOWNORMAL);
        break;

    case HotkeyInfo::Exit:
        SendMessage(Handle(), WM_CLOSE, NULL, NULL);
        break;
    }
}

void _3RVX::ToggleOSDs() {
    for (OSD *osd : _osds) {
        osd->Enabled(!(osd->Enabled()));
    }
}

LRESULT _3RVX::WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
    switch (message) {
    case WM_HOTKEY: {
        CLOG(L"Hotkey: %d", (int) wParam);
        HotkeyInfo hki = _hotkeys[(int) wParam];
        ProcessHotkeys(hki);
        break;
    }

    case WM_WTSSESSION_CHANGE: {
        CLOG(L"Detected session change");
        break;
    }

    case WM_CLOSE: {
        CLOG(L"Shutting down");
        HotkeyManager::Instance()->Shutdown();
        _vOSD->HideIcon();
        break;
    }

    case WM_DESTROY: {
        PostQuitMessage(0);
        break;
    }

    case WM_TIMER:
        if (wParam == TIMER_FIRSTUPDATE || wParam == TIMER_UPDATE) {
            CLOG(L"Received updater timer notification");
            Settings *settings = Settings::Instance();
            long long checkTime = settings->LastUpdateCheck();
            if ((std::time(nullptr) - checkTime) > (UPDATE_INTERVAL / 1000)) {
                /* Enough time has elapsed since the last update check */
                std::wstring settingsApp = Settings::SettingsApp();
                CLOG(L"Launching update task: %s %s",
                    settingsApp.c_str(), L"-update");
                ShellExecute(NULL, L"open",
                    Settings::SettingsApp().c_str(), L"-update", NULL, SW_HIDE);
            }

            if (wParam == TIMER_FIRSTUPDATE) {
                CLOG(L"Starting long-term update timer");
                /* If this was the first update check (30 min after launch),
                 * then kill the first update timer and start the main timer
                 * (checks on 24-hour intervals) */
                KillTimer(Window::Handle(), TIMER_FIRSTUPDATE);
                SetTimer(Window::Handle(), TIMER_UPDATE,
                    UPDATE_INTERVAL, NULL);
            }
        }
        break;
    }

    if (message == _3RVX::WM_3RVX_CTRL) {
        switch (wParam) {
        case _3RVX::MSG_LOAD:
            Initialize();
            break;

        case _3RVX::MSG_SETTINGS:
            Settings::LaunchSettingsApp();
            break;

        case _3RVX::MSG_HIDEOSD:
            int except = (OSDType) lParam;
            switch (except) {
            case Volume:
                if (_eOSD) { _eOSD->Hide(); }
                if (_bOSD) { _bOSD->Hide(); }
                break;

            case Eject:
                if (_vOSD) { _vOSD->Hide(); }
                if (_bOSD) { _bOSD->Hide(); }
                break;

            case Brightness:
                if (_vOSD) { _vOSD->Hide(); }
                if (_eOSD) { _eOSD->Hide(); }
            }

            break;
        }
    }

    return Window::WndProc(hWnd, message, wParam, lParam);
}
<|endoftext|>


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

  Library:   CTK

  Copyright (c) Kitware Inc.

  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.commontk.org/LICENSE

  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.

=========================================================================*/

// Qt includes
#include <QAction>
#include <QApplication>
#include <QDebug>
#include <QIcon>
#include <QMenu>
#include <QStandardItem>
#include <QStyle>
#include <QTimer>
#include <QTreeView>

// CTK includes
#include "ctkActionsWidget.h"

// STD includes
#include <cstdlib>
#include <iostream>

//-----------------------------------------------------------------------------
int ctkActionsWidgetTest1(int argc, char* argv[])
{
  QApplication app(argc, argv);

  ctkActionsWidget* actionsWidget = new ctkActionsWidget(0);
  actionsWidget->show();
  QWidget widget;
  QIcon informationIcon = actionsWidget->style()->standardIcon(QStyle::SP_MessageBoxInformation);

  actionsWidget->addAction(new QAction(0));
  actionsWidget->addAction(new QAction(qApp));
  actionsWidget->clear();
  actionsWidget->addAction(new QAction("Action Text", qApp));
  actionsWidget->addAction(new QAction(informationIcon, "Action Text2", qApp));

  actionsWidget->addAction(new QAction(0), "category 1");
  actionsWidget->addAction(new QAction(qApp), "category 1");
  actionsWidget->addAction(new QAction("Action Text3", &widget), "category 1");
  actionsWidget->addAction(new QAction(informationIcon, "Action Text4", qApp), "category 1");

  actionsWidget->addAction(new QAction(0), "category 2");
  actionsWidget->addAction(new QAction(qApp), "category 3");
  actionsWidget->addAction(new QAction("Action Text5", &widget), "category 4");
  actionsWidget->addAction(new QAction(informationIcon, "Action Text6", qApp), "category 5");

  if (actionsWidget->groupItem("category 1") == 0 ||
      actionsWidget->groupItem("category 1")->rowCount() != 4)
    {
    qDebug() << "Invalid Category 1";
    return EXIT_FAILURE;
    }

  // check shortcut
  QAction* action = new QAction("custom action", 0);
  action->setShortcut(Qt::Key_F1);
  action->setToolTip("custom tooltip");
  actionsWidget->addAction(action);
  QStandardItem* actionItem = actionsWidget->model()->item(7);
  if (!actionItem || actionItem->text() != "custom action")
    {
    qDebug() << "Invalid custom action" << (actionItem ? actionItem->text() : "NaN");
    return EXIT_FAILURE;
    }
  // check update on change
  action->setText("new custom action");
  QStandardItem* changedActionItem = actionsWidget->model()->item(7);
  if (changedActionItem != actionItem ||
      changedActionItem->text() != "new custom action")
    {
    qDebug() << "Invalid action update" << changedActionItem->text();
    return EXIT_FAILURE;
    }
  widget.addAction(action);

  QList<QAction*> actions;
  actions << new QAction("group action 1",qApp);
  actions << new QAction("group action 2",qApp);
  actions << new QAction("group action 3",qApp);
  actions << new QAction("group action 4",qApp);
  actions << new QAction("group action 5",qApp);
  actionsWidget->addActions(actions,"category 6");

  QMenu menu;
  actionsWidget->addAction(menu.addAction("&menu action"), "menu category");
  actionsWidget->addAction(menu.addSeparator(), "menu category");
  actionsWidget->addAction(menu.addMenu("submenu action")->menuAction(), "menu category");
  qDebug()<<"filter";
  actionsWidget->setActionsWithNoShortcutVisible(false);
  qDebug()<<"endfilter";

  QModelIndexList actionTextActions = actionsWidget->view()->model()->match(
    QModelIndex(), Qt::DisplayRole, QString("Action Text"), -1,
    Qt::MatchStartsWith | Qt::MatchWrap |Qt::MatchRecursive);

  if (actionsWidget->areActionsWithNoShortcutVisible() != false ||
      actionTextActions.count() != 0)
    {
    qDebug() << "ctkActionsWidget::setActionsWithNoShortcutVisible failed: actionTextActions.count()";
    return EXIT_FAILURE;
    }

  actionsWidget->setActionsWithNoShortcutVisible(true);

  actionsWidget->setMenuActionsVisible(false);

  // make sure the submenu action is hidden
  QModelIndexList submenuActions = actionsWidget->view()->model()->match(
    QModelIndex(), Qt::DisplayRole, QString("submenu action"), -1,
    Qt::MatchExactly | Qt::MatchWrap |Qt::MatchRecursive);
  if (actionsWidget->areMenuActionsVisible() != false ||
      submenuActions.count() != 0)
    {
    qDebug() << "ctkActionsWidget search failed" << submenuActions.count();
    return EXIT_FAILURE;
    }

  actionsWidget->setMenuActionsVisible(true);

  if (argc < 2 || QString(argv[1]) != "-I" )
    {
    QTimer::singleShot(200, &app, SLOT(quit()));
    }

  return app.exec();
}
<commit_msg>Memory leak in ctkActionsWidgetTest1<commit_after>/*=========================================================================

  Library:   CTK

  Copyright (c) Kitware Inc.

  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.commontk.org/LICENSE

  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.

=========================================================================*/

// Qt includes
#include <QAction>
#include <QApplication>
#include <QDebug>
#include <QIcon>
#include <QMenu>
#include <QStandardItem>
#include <QStyle>
#include <QTimer>
#include <QTreeView>

// CTK includes
#include "ctkActionsWidget.h"

// STD includes
#include <cstdlib>
#include <iostream>

//-----------------------------------------------------------------------------
int ctkActionsWidgetTest1(int argc, char* argv[])
{
  QApplication app(argc, argv);

  ctkActionsWidget actionsWidget(0);
  actionsWidget.show();

  QWidget widget;
  QIcon informationIcon = actionsWidget.style()->standardIcon(QStyle::SP_MessageBoxInformation);

  actionsWidget.addAction(new QAction(0));
  actionsWidget.addAction(new QAction(qApp));
  actionsWidget.clear();
  actionsWidget.addAction(new QAction("Action Text", qApp));
  actionsWidget.addAction(new QAction(informationIcon, "Action Text2", qApp));

  actionsWidget.addAction(new QAction(0), "category 1");
  actionsWidget.addAction(new QAction(qApp), "category 1");
  actionsWidget.addAction(new QAction("Action Text3", &widget), "category 1");
  actionsWidget.addAction(new QAction(informationIcon, "Action Text4", qApp), "category 1");

  actionsWidget.addAction(new QAction(0), "category 2");
  actionsWidget.addAction(new QAction(qApp), "category 3");
  actionsWidget.addAction(new QAction("Action Text5", &widget), "category 4");
  actionsWidget.addAction(new QAction(informationIcon, "Action Text6", qApp), "category 5");

  if (actionsWidget.groupItem("category 1") == 0 ||
      actionsWidget.groupItem("category 1")->rowCount() != 4)
    {
    qDebug() << "Invalid Category 1";
    return EXIT_FAILURE;
    }

  // check shortcut
  QAction* action = new QAction("custom action", 0);
  action->setShortcut(Qt::Key_F1);
  action->setToolTip("custom tooltip");
  actionsWidget.addAction(action);
  QStandardItem* actionItem = actionsWidget.model()->item(7);
  if (!actionItem || actionItem->text() != "custom action")
    {
    qDebug() << "Invalid custom action" << (actionItem ? actionItem->text() : "NaN");
    return EXIT_FAILURE;
    }
  // check update on change
  action->setText("new custom action");
  QStandardItem* changedActionItem = actionsWidget.model()->item(7);
  if (changedActionItem != actionItem ||
      changedActionItem->text() != "new custom action")
    {
    qDebug() << "Invalid action update" << changedActionItem->text();
    return EXIT_FAILURE;
    }
  widget.addAction(action);

  QList<QAction*> actions;
  actions << new QAction("group action 1",qApp);
  actions << new QAction("group action 2",qApp);
  actions << new QAction("group action 3",qApp);
  actions << new QAction("group action 4",qApp);
  actions << new QAction("group action 5",qApp);
  actionsWidget.addActions(actions,"category 6");

  QMenu menu;
  actionsWidget.addAction(menu.addAction("&menu action"), "menu category");
  actionsWidget.addAction(menu.addSeparator(), "menu category");
  actionsWidget.addAction(menu.addMenu("submenu action")->menuAction(), "menu category");

  actionsWidget.setActionsWithNoShortcutVisible(false);

  QModelIndexList actionTextActions = actionsWidget.view()->model()->match(
    QModelIndex(), Qt::DisplayRole, QString("Action Text"), -1,
    Qt::MatchStartsWith | Qt::MatchWrap |Qt::MatchRecursive);

  if (actionsWidget.areActionsWithNoShortcutVisible() != false ||
      actionTextActions.count() != 0)
    {
    qDebug() << "ctkActionsWidget::setActionsWithNoShortcutVisible failed: actionTextActions.count()";
    return EXIT_FAILURE;
    }

  actionsWidget.setActionsWithNoShortcutVisible(true);

  actionsWidget.setMenuActionsVisible(false);

  // make sure the submenu action is hidden
  QModelIndexList submenuActions = actionsWidget.view()->model()->match(
    QModelIndex(), Qt::DisplayRole, QString("submenu action"), -1,
    Qt::MatchExactly | Qt::MatchWrap |Qt::MatchRecursive);
  if (actionsWidget.areMenuActionsVisible() != false ||
      submenuActions.count() != 0)
    {
    qDebug() << "ctkActionsWidget search failed" << submenuActions.count();
    return EXIT_FAILURE;
    }

  actionsWidget.setMenuActionsVisible(true);

  if (argc < 2 || QString(argv[1]) != "-I" )
    {
    QTimer::singleShot(200, &app, SLOT(quit()));
    }

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


<commit_before>/*
 * Copyright 2015 Cloudius Systems
 */

#ifndef API_API_HH_
#define API_API_HH_

#include "http/httpd.hh"
#include "database.hh"
#include <boost/lexical_cast.hpp>
namespace api {

struct http_context {
    http_server_control http_server;
    distributed<database>& db;
    http_context(distributed<database>& _db) : db(_db) {}
};

future<> set_server(http_context& ctx);

template<class T>
std::vector<sstring> container_to_vec(const T& container) {
    std::vector<sstring> res;
    for (auto i : container) {
        res.push_back(boost::lexical_cast<sstring>(i));
    }
    return res;
}

}

#endif /* API_API_HH_ */
<commit_msg>api: fix string containing space cause boost execption<commit_after>/*
 * Copyright 2015 Cloudius Systems
 */

#ifndef API_API_HH_
#define API_API_HH_

#include "http/httpd.hh"
#include "database.hh"
#include <boost/lexical_cast.hpp>
namespace api {

struct http_context {
    http_server_control http_server;
    distributed<database>& db;
    http_context(distributed<database>& _db) : db(_db) {}
};

future<> set_server(http_context& ctx);

template<class T>
std::vector<sstring> container_to_vec(const T& container) {
    std::vector<sstring> res;
    for (auto i : container) {
        res.push_back(boost::lexical_cast<std::string>(i));
    }
    return res;
}

}

#endif /* API_API_HH_ */
<|endoftext|>


<commit_before>/*
 Print.cpp - Base class that provides print() and println()
 Copyright (c) 2008 David A. Mellis.  All right reserved.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

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

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

 Modified 23 November 2006 by David A. Mellis
 Modified 03 August 2015 by Chuck Todd
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "Arduino.h"

#include "Print.h"

// Public Methods //////////////////////////////////////////////////////////////

/* default implementation: may be overridden */
size_t Print::write(const uint8_t *buffer, size_t size)
{
  size_t n = 0;
  while (size--) {
    if (write(*buffer++)) n++;
    else break;
  }
  return n;
}

size_t Print::print(const __FlashStringHelper *ifsh)
{
  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  size_t n = 0;
  while (1) {
    unsigned char c = pgm_read_byte(p++);
    if (c == 0) break;
    if (write(c)) n++;
    else break;
  }
  return n;
}

size_t Print::print(const String &s)
{
  return write(s.c_str(), s.length());
}

size_t Print::print(const char str[])
{
  return write(str);
}

size_t Print::print(char c)
{
  return write(c);
}

size_t Print::print(unsigned char b, int base)
{
  return print((unsigned long) b, base);
}

size_t Print::print(int n, int base)
{
  return print((long) n, base);
}

size_t Print::print(unsigned int n, int base)
{
  return print((unsigned long) n, base);
}

size_t Print::print(long n, int base)
{
  if (base == 0) {
    return write(n);
  } else if (base == 10) {
    if (n < 0) {
      int t = print('-');
      n = -n;
      return printNumber(n, 10) + t;
    }
    return printNumber(n, 10);
  } else {
    return printNumber(n, base);
  }
}

size_t Print::print(unsigned long n, int base)
{
  if (base == 0) return write(n);
  else return printNumber(n, base);
}

size_t Print::print(double n, int digits)
{
  return printFloat(n, digits);
}

size_t Print::println(const __FlashStringHelper *ifsh)
{
  size_t n = print(ifsh);
  n += println();
  return n;
}

size_t Print::print(const Printable& x)
{
  return x.printTo(*this);
}

size_t Print::println(void)
{
  return write("\r\n");
}

size_t Print::println(const String &s)
{
  size_t n = print(s);
  n += println();
  return n;
}

size_t Print::println(const char c[])
{
  size_t n = print(c);
  n += println();
  return n;
}

size_t Print::println(char c)
{
  size_t n = print(c);
  n += println();
  return n;
}

size_t Print::println(unsigned char b, int base)
{
  size_t n = print(b, base);
  n += println();
  return n;
}

size_t Print::println(int num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(unsigned int num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(long num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(unsigned long num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(double num, int digits)
{
  size_t n = print(num, digits);
  n += println();
  return n;
}

size_t Print::println(const Printable& x)
{
  size_t n = print(x);
  n += println();
  return n;
}

// Private Methods /////////////////////////////////////////////////////////////

size_t Print::printNumber(unsigned long n, uint8_t base) {
  char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
  char *str = &buf[sizeof(buf) - 1];

  *str = '\0';

  // prevent crash if called with base == 1
  if (base < 2) base = 10;

  do {
    unsigned long m = n;
    n /= base;
    char c = m - base * n;
    *--str = c < 10 ? c + '0' : c + 'A' - 10;
  } while(n);

  return write(str);
}

size_t Print::printFloat(double number, uint8_t digits)
{
  size_t n = 0;

  if (isnan(number)) return print("nan");
  if (isinf(number)) return print("inf");
  if (number > 4294967040.0) return print ("ovf");  // constant determined empirically
  if (number <-4294967040.0) return print ("ovf");  // constant determined empirically

  // Handle negative numbers
  if (number < 0.0)
  {
     n += print('-');
     number = -number;
  }

  // Round correctly so that print(1.999, 2) prints as "2.00"
  double rounding = 0.5;
  for (uint8_t i=0; i<digits; ++i)
    rounding /= 10.0;

  number += rounding;

  // Extract the integer part of the number and print it
  unsigned long int_part = (unsigned long)number;
  double remainder = number - (double)int_part;
  n += print(int_part);

  // Print the decimal point, but only if there are digits beyond
  if (digits > 0) {
    n += print(".");
  }

  // Extract digits from the remainder one at a time
  while (digits-- > 0)
  {
    remainder *= 10.0;
    int toPrint = int(remainder);
    n += print(toPrint);
    remainder -= toPrint;
  }

  return n;
}
<commit_msg>huh? i guess it's just 'modulo'. let's save even more<commit_after>/*
 Print.cpp - Base class that provides print() and println()
 Copyright (c) 2008 David A. Mellis.  All right reserved.

 This library is free software; you can redistribute it and/or
 modify it under the terms of the GNU Lesser General Public
 License as published by the Free Software Foundation; either
 version 2.1 of the License, or (at your option) any later version.

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

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

 Modified 23 November 2006 by David A. Mellis
 Modified 03 August 2015 by Chuck Todd
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "Arduino.h"

#include "Print.h"

// Public Methods //////////////////////////////////////////////////////////////

/* default implementation: may be overridden */
size_t Print::write(const uint8_t *buffer, size_t size)
{
  size_t n = 0;
  while (size--) {
    if (write(*buffer++)) n++;
    else break;
  }
  return n;
}

size_t Print::print(const __FlashStringHelper *ifsh)
{
  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  size_t n = 0;
  while (1) {
    unsigned char c = pgm_read_byte(p++);
    if (c == 0) break;
    if (write(c)) n++;
    else break;
  }
  return n;
}

size_t Print::print(const String &s)
{
  return write(s.c_str(), s.length());
}

size_t Print::print(const char str[])
{
  return write(str);
}

size_t Print::print(char c)
{
  return write(c);
}

size_t Print::print(unsigned char b, int base)
{
  return print((unsigned long) b, base);
}

size_t Print::print(int n, int base)
{
  return print((long) n, base);
}

size_t Print::print(unsigned int n, int base)
{
  return print((unsigned long) n, base);
}

size_t Print::print(long n, int base)
{
  if (base == 0) {
    return write(n);
  } else if (base == 10) {
    if (n < 0) {
      int t = print('-');
      n = -n;
      return printNumber(n, 10) + t;
    }
    return printNumber(n, 10);
  } else {
    return printNumber(n, base);
  }
}

size_t Print::print(unsigned long n, int base)
{
  if (base == 0) return write(n);
  else return printNumber(n, base);
}

size_t Print::print(double n, int digits)
{
  return printFloat(n, digits);
}

size_t Print::println(const __FlashStringHelper *ifsh)
{
  size_t n = print(ifsh);
  n += println();
  return n;
}

size_t Print::print(const Printable& x)
{
  return x.printTo(*this);
}

size_t Print::println(void)
{
  return write("\r\n");
}

size_t Print::println(const String &s)
{
  size_t n = print(s);
  n += println();
  return n;
}

size_t Print::println(const char c[])
{
  size_t n = print(c);
  n += println();
  return n;
}

size_t Print::println(char c)
{
  size_t n = print(c);
  n += println();
  return n;
}

size_t Print::println(unsigned char b, int base)
{
  size_t n = print(b, base);
  n += println();
  return n;
}

size_t Print::println(int num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(unsigned int num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(long num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(unsigned long num, int base)
{
  size_t n = print(num, base);
  n += println();
  return n;
}

size_t Print::println(double num, int digits)
{
  size_t n = print(num, digits);
  n += println();
  return n;
}

size_t Print::println(const Printable& x)
{
  size_t n = print(x);
  n += println();
  return n;
}

// Private Methods /////////////////////////////////////////////////////////////

size_t Print::printNumber(unsigned long n, uint8_t base)
{
  char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
  char *str = &buf[sizeof(buf) - 1];

  *str = '\0';

  // prevent crash if called with base == 1
  if (base < 2) base = 10;

  do {
    char c = n % base;
    n /= base;

    *--str = c < 10 ? c + '0' : c + 'A' - 10;
  } while(n);

  return write(str);
}

size_t Print::printFloat(double number, uint8_t digits)
{
  size_t n = 0;

  if (isnan(number)) return print("nan");
  if (isinf(number)) return print("inf");
  if (number > 4294967040.0) return print ("ovf");  // constant determined empirically
  if (number <-4294967040.0) return print ("ovf");  // constant determined empirically

  // Handle negative numbers
  if (number < 0.0)
  {
     n += print('-');
     number = -number;
  }

  // Round correctly so that print(1.999, 2) prints as "2.00"
  double rounding = 0.5;
  for (uint8_t i=0; i<digits; ++i)
    rounding /= 10.0;

  number += rounding;

  // Extract the integer part of the number and print it
  unsigned long int_part = (unsigned long)number;
  double remainder = number - (double)int_part;
  n += print(int_part);

  // Print the decimal point, but only if there are digits beyond
  if (digits > 0) {
    n += print(".");
  }

  // Extract digits from the remainder one at a time
  while (digits-- > 0)
  {
    remainder *= 10.0;
    int toPrint = int(remainder);
    n += print(toPrint);
    remainder -= toPrint;
  }

  return n;
}
<|endoftext|>