Skip to content

Instantly share code, notes, and snippets.

@heisters
Last active April 18, 2017 23:02
Show Gist options
  • Save heisters/4764fd11cab2eee2dc69 to your computer and use it in GitHub Desktop.
Save heisters/4764fd11cab2eee2dc69 to your computer and use it in GitHub Desktop.
Cinder class for managing configuration with defaults, a UI, and persistence
#include "Config.h"
#include "cinder/app/App.h"
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace ci;
Config::Config( const ci::fs::path &path ) :
mPath( path ),
mJson( app::loadAsset( path ) )
{
}
Config::~Config()
{
}
struct to_json_visitor : boost::static_visitor<> {
to_json_visitor( JsonTree &json ) : json( json ) {}
JsonTree &json;
template< typename T >
void operator()( T* const ptr ) const
{
json = JsonTree( json.getKey(), *ptr );
}
};
void Config::save()
{
for ( const auto& setting : mSettingPointers ) {
const auto& k = setting.first;
JsonTree j = mJson.getChild( k );
boost::apply_visitor( to_json_visitor( j ), setting.second );
mJson.getChild( k ) = j;
}
mJson.write( app::getAssetPath( mPath ) );
}
JsonTree* Config::ensurePath( const string &key )
{
deque< string > paths;
boost::split( paths, key, boost::is_any_of( "." ) );
JsonTree *t = &mJson;
for ( const auto& p : paths ) {
t->hasChild( p ) ? t->getChild( p ) : t->addChild( JsonTree::makeObject( p ) );
t = &t->getChild( p );
}
return t;
}
JsonTree& Config::operator[]( const std::string &relativePath )
{
return mJson[ relativePath ];
}
const JsonTree& Config::operator[]( const std::string &relativePath ) const
{
return mJson[ relativePath ];
}
#pragma once
#include "cinder/Json.h"
#include "cinder/Color.h"
#include "cinder/Vector.h"
#include <boost/variant.hpp>
class Config {
private:
typedef boost::variant<
int32_t*,
float*,
bool*,
std::string*
>
variant_t;
public:
Config( const ci::fs::path &path );
~Config();
void save();
// Binds a config key to a variable pointer.
template< typename T >
Config& operator()( const std::string &key, T *setting )
{
mSettingPointers[ key ] = setting;
if ( mJson.hasChild( key ) ) {
auto lvalue = *setting;
*setting = mJson.getChild( key ).getValue< decltype( lvalue ) >();
}
// create paths that don't exist, after the values are set
ensurePath( key );
return *this;
}
ci::JsonTree& operator[]( const std::string &relativePath );
const ci::JsonTree& operator[]( const std::string &relativePath ) const;
bool hasKey( const std::string &key ) const { return mJson.hasChild( key ); }
private:
ci::JsonTree* ensurePath( const std::string &key );
std::map< std::string, variant_t > mSettingPointers;
ci::fs::path mPath;
ci::JsonTree mJson;
};
inline ci::Colorf colorfFromJson( const ci::JsonTree& json )
{
return ci::Colorf( json.getValueAtIndex< float >( 0 ), json.getValueAtIndex< float >( 1 ), json.getValueAtIndex< float >( 2 ) );
}
inline ci::vec3 vec3FromJson( const ci::JsonTree& json )
{
return ci::vec3( json.getValueAtIndex< float >( 0 ), json.getValueAtIndex< float >( 1 ), json.getValueAtIndex< float >( 2 ) );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment