<commit_before>#include "command.hh"
#include "store-api.hh"
#include "local-fs-store.hh"
#include "derivations.hh"
#include "nixexpr.hh"
#include "profiles.hh"

#include <nlohmann/json.hpp>

extern char * * environ __attribute__((weak));

namespace nix {

RegisterCommand::Commands * RegisterCommand::commands = nullptr;

nix::Commands RegisterCommand::getCommandsFor(const std::vector<std::string> & prefix)
{
    nix::Commands res;
    for (auto & [name, command] : *RegisterCommand::commands)
        if (name.size() == prefix.size() + 1) {
            bool equal = true;
            for (size_t i = 0; i < prefix.size(); ++i)
                if (name[i] != prefix[i]) equal = false;
            if (equal)
                res.insert_or_assign(name[prefix.size()], command);
        }
    return res;
}

nlohmann::json NixMultiCommand::toJSON()
{
    // FIXME: use Command::toJSON() as well.
    return MultiCommand::toJSON();
}

StoreCommand::StoreCommand()
{
}

ref<Store> StoreCommand::getStore()
{
    if (!_store)
        _store = createStore();
    return ref<Store>(_store);
}

ref<Store> StoreCommand::createStore()
{
    return openStore();
}

void StoreCommand::run()
{
    run(getStore());
}

CopyCommand::CopyCommand()
{
    addFlag({
        .longName = "from",
        .description = "URL of the source Nix store.",
        .labels = {"store-uri"},
        .handler = {&srcUri},
    });

    addFlag({
        .longName = "to",
        .description = "URL of the destination Nix store.",
        .labels = {"store-uri"},
        .handler = {&dstUri},
    });
}

ref<Store> CopyCommand::createStore()
{
    return srcUri.empty() ? StoreCommand::createStore() : openStore(srcUri);
}

ref<Store> CopyCommand::getDstStore()
{
    if (srcUri.empty() && dstUri.empty())
        throw UsageError("you must pass '--from' and/or '--to'");

    return dstUri.empty() ? openStore() : openStore(dstUri);
}

EvalCommand::EvalCommand()
{
    addFlag({
        .longName = "debugger",
        .description = "start an interactive environment if evaluation fails",
        .handler = {&startReplOnEvalErrors, true},
    });
}

EvalCommand::~EvalCommand()
{
    if (evalState)
        evalState->printStats();
}

ref<Store> EvalCommand::getEvalStore()
{
    if (!evalStore)
        evalStore = evalStoreUrl ? openStore(*evalStoreUrl) : getStore();
    return ref<Store>(evalStore);
}

ref<EvalState> EvalCommand::getEvalState()
{
    if (!evalState) {
        evalState =
            #if HAVE_BOEHMGC
            std::allocate_shared<EvalState>(traceable_allocator<EvalState>(),
                searchPath, getEvalStore(), getStore())
            #else
            std::make_shared<EvalState>(
                searchPath, getEvalStore(), getStore())
            #endif
            ;
        if (startReplOnEvalErrors)
            debuggerHook = [evalState{ref<EvalState>(evalState)}](const Error * error, const Env & env, const Expr & expr) {
                // clear the screen.
                // std::cout << "\033[2J\033[1;1H";

                auto dts =
                    error && expr.getPos() ?
                          std::unique_ptr<DebugTraceStacker>(
                              new DebugTraceStacker(
                                  *evalState,
                                  DebugTrace
                                        {.pos = (error->info().errPos ? *error->info().errPos : *expr.getPos()),
                                         .expr = expr,
                                         .env = env,
                                         .hint = error->info().msg,
                                         .is_error = true
                                        }))
                          : nullptr;

                if (error)
                    printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what());

                // else
                // {
                //     auto iter = evalState->debugTraces.begin();
                //     if (iter != evalState->debugTraces.end()) {
                //           std::cout << "\n" << "… " << iter->hint.str() << "\n";

                //           if (iter->pos.has_value() && (*iter->pos)) {
                //               auto pos = iter->pos.value();
                //               std::cout << "\n";
                //               printAtPos(pos, std::cout);

                //               auto loc = getCodeLines(pos);
                //               if (loc.has_value()) {
                //                   std::cout << "\n";
                //                   printCodeLines(std::cout, "", pos, *loc);
                //                   std::cout << "\n";
                //             }
                //         }
                //     }
                // }

                if (expr.staticenv)
                {
                    auto vm = mapStaticEnvBindings(*expr.staticenv.get(), env);
                    runRepl(evalState, error, expr, *vm);
                }
            };
    }
    return ref<EvalState>(evalState);
}

BuiltPathsCommand::BuiltPathsCommand(bool recursive)
    : recursive(recursive)
{
    if (recursive)
        addFlag({
            .longName = "no-recursive",
            .description = "Apply operation to specified paths only.",
            .category = installablesCategory,
            .handler = {&this->recursive, false},
        });
    else
        addFlag({
            .longName = "recursive",
            .shortName = 'r',
            .description = "Apply operation to closure of the specified paths.",
            .category = installablesCategory,
            .handler = {&this->recursive, true},
        });

    addFlag({
        .longName = "all",
        .description = "Apply the operation to every store path.",
        .category = installablesCategory,
        .handler = {&all, true},
    });
}

void BuiltPathsCommand::run(ref<Store> store)
{
    BuiltPaths paths;
    if (all) {
        if (installables.size())
            throw UsageError("'--all' does not expect arguments");
        // XXX: Only uses opaque paths, ignores all the realisations
        for (auto & p : store->queryAllValidPaths())
            paths.push_back(BuiltPath::Opaque{p});
    } else {
        paths = toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
        if (recursive) {
            // XXX: This only computes the store path closure, ignoring
            // intermediate realisations
            StorePathSet pathsRoots, pathsClosure;
            for (auto & root : paths) {
                auto rootFromThis = root.outPaths();
                pathsRoots.insert(rootFromThis.begin(), rootFromThis.end());
            }
            store->computeFSClosure(pathsRoots, pathsClosure);
            for (auto & path : pathsClosure)
                paths.push_back(BuiltPath::Opaque{path});
        }
    }

    run(store, std::move(paths));
}

StorePathsCommand::StorePathsCommand(bool recursive)
    : BuiltPathsCommand(recursive)
{
}

void StorePathsCommand::run(ref<Store> store, BuiltPaths && paths)
{
    StorePathSet storePaths;
    for (auto & builtPath : paths)
        for (auto & p : builtPath.outPaths())
            storePaths.insert(p);

    auto sorted = store->topoSortPaths(storePaths);
    std::reverse(sorted.begin(), sorted.end());

    run(store, std::move(sorted));
}

void StorePathCommand::run(ref<Store> store, std::vector<StorePath> && storePaths)
{
    if (storePaths.size() != 1)
        throw UsageError("this command requires exactly one store path");

    run(store, *storePaths.begin());
}

Strings editorFor(const Pos & pos)
{
    auto editor = getEnv("EDITOR").value_or("cat");
    auto args = tokenizeString<Strings>(editor);
    if (pos.line > 0 && (
        editor.find("emacs") != std::string::npos ||
        editor.find("nano") != std::string::npos ||
        editor.find("vim") != std::string::npos))
        args.push_back(fmt("+%d", pos.line));
    args.push_back(pos.file);
    return args;
}

MixProfile::MixProfile()
{
    addFlag({
        .longName = "profile",
        .description = "The profile to update.",
        .labels = {"path"},
        .handler = {&profile},
        .completer = completePath
    });
}

void MixProfile::updateProfile(const StorePath & storePath)
{
    if (!profile) return;
    auto store = getStore().dynamic_pointer_cast<LocalFSStore>();
    if (!store) throw Error("'--profile' is not supported for this Nix store");
    auto profile2 = absPath(*profile);
    switchLink(profile2,
        createGeneration(
            ref<LocalFSStore>(store),
            profile2, storePath));
}

void MixProfile::updateProfile(const BuiltPaths & buildables)
{
    if (!profile) return;

    std::vector<StorePath> result;

    for (auto & buildable : buildables) {
        std::visit(overloaded {
            [&](const BuiltPath::Opaque & bo) {
                result.push_back(bo.path);
            },
            [&](const BuiltPath::Built & bfd) {
                for (auto & output : bfd.outputs) {
                    result.push_back(output.second);
                }
            },
        }, buildable.raw());
    }

    if (result.size() != 1)
        throw UsageError("'--profile' requires that the arguments produce a single store path, but there are %d", result.size());

    updateProfile(result[0]);
}

MixDefaultProfile::MixDefaultProfile()
{
    profile = getDefaultProfile();
}

MixEnvironment::MixEnvironment() : ignoreEnvironment(false)
{
    addFlag({
        .longName = "ignore-environment",
        .shortName = 'i',
        .description = "Clear the entire environment (except those specified with `--keep`).",
        .handler = {&ignoreEnvironment, true},
    });

    addFlag({
        .longName = "keep",
        .shortName = 'k',
        .description = "Keep the environment variable *name*.",
        .labels = {"name"},
        .handler = {[&](std::string s) { keep.insert(s); }},
    });

    addFlag({
        .longName = "unset",
        .shortName = 'u',
        .description = "Unset the environment variable *name*.",
        .labels = {"name"},
        .handler = {[&](std::string s) { unset.insert(s); }},
    });
}

void MixEnvironment::setEnviron() {
    if (ignoreEnvironment) {
        if (!unset.empty())
            throw UsageError("--unset does not make sense with --ignore-environment");

        for (const auto & var : keep) {
            auto val = getenv(var.c_str());
            if (val) stringsEnv.emplace_back(fmt("%s=%s", var.c_str(), val));
        }

        vectorEnv = stringsToCharPtrs(stringsEnv);
        environ = vectorEnv.data();
    } else {
        if (!keep.empty())
            throw UsageError("--keep does not make sense without --ignore-environment");

        for (const auto & var : unset)
            unsetenv(var.c_str());
    }
}

}
<commit_msg>free valmap on exit<commit_after>#include "command.hh"
#include "store-api.hh"
#include "local-fs-store.hh"
#include "derivations.hh"
#include "nixexpr.hh"
#include "profiles.hh"

#include <nlohmann/json.hpp>

extern char * * environ __attribute__((weak));

namespace nix {

RegisterCommand::Commands * RegisterCommand::commands = nullptr;

nix::Commands RegisterCommand::getCommandsFor(const std::vector<std::string> & prefix)
{
    nix::Commands res;
    for (auto & [name, command] : *RegisterCommand::commands)
        if (name.size() == prefix.size() + 1) {
            bool equal = true;
            for (size_t i = 0; i < prefix.size(); ++i)
                if (name[i] != prefix[i]) equal = false;
            if (equal)
                res.insert_or_assign(name[prefix.size()], command);
        }
    return res;
}

nlohmann::json NixMultiCommand::toJSON()
{
    // FIXME: use Command::toJSON() as well.
    return MultiCommand::toJSON();
}

StoreCommand::StoreCommand()
{
}

ref<Store> StoreCommand::getStore()
{
    if (!_store)
        _store = createStore();
    return ref<Store>(_store);
}

ref<Store> StoreCommand::createStore()
{
    return openStore();
}

void StoreCommand::run()
{
    run(getStore());
}

CopyCommand::CopyCommand()
{
    addFlag({
        .longName = "from",
        .description = "URL of the source Nix store.",
        .labels = {"store-uri"},
        .handler = {&srcUri},
    });

    addFlag({
        .longName = "to",
        .description = "URL of the destination Nix store.",
        .labels = {"store-uri"},
        .handler = {&dstUri},
    });
}

ref<Store> CopyCommand::createStore()
{
    return srcUri.empty() ? StoreCommand::createStore() : openStore(srcUri);
}

ref<Store> CopyCommand::getDstStore()
{
    if (srcUri.empty() && dstUri.empty())
        throw UsageError("you must pass '--from' and/or '--to'");

    return dstUri.empty() ? openStore() : openStore(dstUri);
}

EvalCommand::EvalCommand()
{
    addFlag({
        .longName = "debugger",
        .description = "start an interactive environment if evaluation fails",
        .handler = {&startReplOnEvalErrors, true},
    });
}

EvalCommand::~EvalCommand()
{
    if (evalState)
        evalState->printStats();
}

ref<Store> EvalCommand::getEvalStore()
{
    if (!evalStore)
        evalStore = evalStoreUrl ? openStore(*evalStoreUrl) : getStore();
    return ref<Store>(evalStore);
}

ref<EvalState> EvalCommand::getEvalState()
{
    if (!evalState) {
        evalState =
            #if HAVE_BOEHMGC
            std::allocate_shared<EvalState>(traceable_allocator<EvalState>(),
                searchPath, getEvalStore(), getStore())
            #else
            std::make_shared<EvalState>(
                searchPath, getEvalStore(), getStore())
            #endif
            ;
        if (startReplOnEvalErrors)
            debuggerHook = [evalState{ref<EvalState>(evalState)}](const Error * error, const Env & env, const Expr & expr) {
                // clear the screen.
                // std::cout << "\033[2J\033[1;1H";

                auto dts =
                    error && expr.getPos() ?
                          std::unique_ptr<DebugTraceStacker>(
                              new DebugTraceStacker(
                                  *evalState,
                                  DebugTrace
                                        {.pos = (error->info().errPos ? *error->info().errPos : *expr.getPos()),
                                         .expr = expr,
                                         .env = env,
                                         .hint = error->info().msg,
                                         .is_error = true
                                        }))
                          : nullptr;

                if (error)
                    printError("%s\n\n" ANSI_BOLD "Starting REPL to allow you to inspect the current state of the evaluator.\n" ANSI_NORMAL, error->what());

                // else
                // {
                //     auto iter = evalState->debugTraces.begin();
                //     if (iter != evalState->debugTraces.end()) {
                //           std::cout << "\n" << "… " << iter->hint.str() << "\n";

                //           if (iter->pos.has_value() && (*iter->pos)) {
                //               auto pos = iter->pos.value();
                //               std::cout << "\n";
                //               printAtPos(pos, std::cout);

                //               auto loc = getCodeLines(pos);
                //               if (loc.has_value()) {
                //                   std::cout << "\n";
                //                   printCodeLines(std::cout, "", pos, *loc);
                //                   std::cout << "\n";
                //             }
                //         }
                //     }
                // }

                if (expr.staticenv)
                {
                    std::unique_ptr<valmap> vm(mapStaticEnvBindings(*expr.staticenv.get(), env));
                    runRepl(evalState, error, expr, *vm);
                }
            };
    }
    return ref<EvalState>(evalState);
}

BuiltPathsCommand::BuiltPathsCommand(bool recursive)
    : recursive(recursive)
{
    if (recursive)
        addFlag({
            .longName = "no-recursive",
            .description = "Apply operation to specified paths only.",
            .category = installablesCategory,
            .handler = {&this->recursive, false},
        });
    else
        addFlag({
            .longName = "recursive",
            .shortName = 'r',
            .description = "Apply operation to closure of the specified paths.",
            .category = installablesCategory,
            .handler = {&this->recursive, true},
        });

    addFlag({
        .longName = "all",
        .description = "Apply the operation to every store path.",
        .category = installablesCategory,
        .handler = {&all, true},
    });
}

void BuiltPathsCommand::run(ref<Store> store)
{
    BuiltPaths paths;
    if (all) {
        if (installables.size())
            throw UsageError("'--all' does not expect arguments");
        // XXX: Only uses opaque paths, ignores all the realisations
        for (auto & p : store->queryAllValidPaths())
            paths.push_back(BuiltPath::Opaque{p});
    } else {
        paths = toBuiltPaths(getEvalStore(), store, realiseMode, operateOn, installables);
        if (recursive) {
            // XXX: This only computes the store path closure, ignoring
            // intermediate realisations
            StorePathSet pathsRoots, pathsClosure;
            for (auto & root : paths) {
                auto rootFromThis = root.outPaths();
                pathsRoots.insert(rootFromThis.begin(), rootFromThis.end());
            }
            store->computeFSClosure(pathsRoots, pathsClosure);
            for (auto & path : pathsClosure)
                paths.push_back(BuiltPath::Opaque{path});
        }
    }

    run(store, std::move(paths));
}

StorePathsCommand::StorePathsCommand(bool recursive)
    : BuiltPathsCommand(recursive)
{
}

void StorePathsCommand::run(ref<Store> store, BuiltPaths && paths)
{
    StorePathSet storePaths;
    for (auto & builtPath : paths)
        for (auto & p : builtPath.outPaths())
            storePaths.insert(p);

    auto sorted = store->topoSortPaths(storePaths);
    std::reverse(sorted.begin(), sorted.end());

    run(store, std::move(sorted));
}

void StorePathCommand::run(ref<Store> store, std::vector<StorePath> && storePaths)
{
    if (storePaths.size() != 1)
        throw UsageError("this command requires exactly one store path");

    run(store, *storePaths.begin());
}

Strings editorFor(const Pos & pos)
{
    auto editor = getEnv("EDITOR").value_or("cat");
    auto args = tokenizeString<Strings>(editor);
    if (pos.line > 0 && (
        editor.find("emacs") != std::string::npos ||
        editor.find("nano") != std::string::npos ||
        editor.find("vim") != std::string::npos))
        args.push_back(fmt("+%d", pos.line));
    args.push_back(pos.file);
    return args;
}

MixProfile::MixProfile()
{
    addFlag({
        .longName = "profile",
        .description = "The profile to update.",
        .labels = {"path"},
        .handler = {&profile},
        .completer = completePath
    });
}

void MixProfile::updateProfile(const StorePath & storePath)
{
    if (!profile) return;
    auto store = getStore().dynamic_pointer_cast<LocalFSStore>();
    if (!store) throw Error("'--profile' is not supported for this Nix store");
    auto profile2 = absPath(*profile);
    switchLink(profile2,
        createGeneration(
            ref<LocalFSStore>(store),
            profile2, storePath));
}

void MixProfile::updateProfile(const BuiltPaths & buildables)
{
    if (!profile) return;

    std::vector<StorePath> result;

    for (auto & buildable : buildables) {
        std::visit(overloaded {
            [&](const BuiltPath::Opaque & bo) {
                result.push_back(bo.path);
            },
            [&](const BuiltPath::Built & bfd) {
                for (auto & output : bfd.outputs) {
                    result.push_back(output.second);
                }
            },
        }, buildable.raw());
    }

    if (result.size() != 1)
        throw UsageError("'--profile' requires that the arguments produce a single store path, but there are %d", result.size());

    updateProfile(result[0]);
}

MixDefaultProfile::MixDefaultProfile()
{
    profile = getDefaultProfile();
}

MixEnvironment::MixEnvironment() : ignoreEnvironment(false)
{
    addFlag({
        .longName = "ignore-environment",
        .shortName = 'i',
        .description = "Clear the entire environment (except those specified with `--keep`).",
        .handler = {&ignoreEnvironment, true},
    });

    addFlag({
        .longName = "keep",
        .shortName = 'k',
        .description = "Keep the environment variable *name*.",
        .labels = {"name"},
        .handler = {[&](std::string s) { keep.insert(s); }},
    });

    addFlag({
        .longName = "unset",
        .shortName = 'u',
        .description = "Unset the environment variable *name*.",
        .labels = {"name"},
        .handler = {[&](std::string s) { unset.insert(s); }},
    });
}

void MixEnvironment::setEnviron() {
    if (ignoreEnvironment) {
        if (!unset.empty())
            throw UsageError("--unset does not make sense with --ignore-environment");

        for (const auto & var : keep) {
            auto val = getenv(var.c_str());
            if (val) stringsEnv.emplace_back(fmt("%s=%s", var.c_str(), val));
        }

        vectorEnv = stringsToCharPtrs(stringsEnv);
        environ = vectorEnv.data();
    } else {
        if (!keep.empty())
            throw UsageError("--keep does not make sense without --ignore-environment");

        for (const auto & var : unset)
            unsetenv(var.c_str());
    }
}

}
<|endoftext|>


<commit_before>#pragma once

namespace nix {

template<typename T> class BasicStore;
class StoreConfig;
typedef BasicStore<StoreConfig> Store;

}
<commit_msg>fixup! Make the store plugins more introspectable<commit_after><|endoftext|>


<commit_before>/*
 * File:   table.cc
 * Author: victorr
 *
 * Created on June 11, 2008, 1:48 PM
 */

#include <fstream>
#include <vector>
#include <boost/lexical_cast.hpp>
#include "tokenizer.h"
#include "table.h"
#include <stdexcept>

using namespace boost;

void Table::Load(string filename)
{
    ifstream in;
    in.open(filename.c_str());
    if(!in)
        throw runtime_error(string("error, cannot open file ") + filename);

    in >> *this;

    in.close();
}

void Table::Save(string filename) const
{
    ofstream out;
    out.open(filename.c_str());
    if(!out)
        throw runtime_error(string("error, cannot open file ") + filename);

    out << (*this);

    out.close();
}

void Table::clear(void)
{
    _x.clear();
    _y.clear();
    _flags.clear();
}

// TODO: this functon is weired, reading occours twice, cleanup!!
inline istream &operator>>(istream &in, Table& t)
{
    size_t N;
    bool bHasN=false;
    string line;

   t.clear();

    // read till the first data line
    while(getline(in, line)) {
        // remove comments and xmgrace stuff
        line = line.substr(0, line.find("#"));
        line = line.substr(0, line.find("@"));

        // tokenize string and put it to vector
        Tokenizer tok(line, " \t");
        vector<string> tokens;
        tok.ToVector(tokens);

        // skip empty lines
        if(tokens.size()==0) continue;

        // if first line is only 1 token, it's the size
        if(tokens.size() == 1) {
            N = lexical_cast<int>(tokens[0]);
            bHasN = true;
        }
        // it's the first data line with 2 or 3 entries
        else if(tokens.size() == 2) {
            t.push_back(lexical_cast<double>(tokens[0]), lexical_cast<double>(tokens[1]), 'i');
        }
        else if(tokens.size() > 3) {
            t.push_back(lexical_cast<double>(tokens[0]), lexical_cast<double>(tokens[1]), tokens[2].c_str()[0]);
        }
        else throw runtime_error("error, wrong table format");
    }

    // read the rest
    while(getline(in, line)) {
        // remove comments and xmgrace stuff
        line = line.substr(0, line.find("#"));
        line = line.substr(0, line.find("@"));

        // tokenize string and put it to vector
        Tokenizer tok(line, " \t");
        vector<string> tokens;
        tok.ToVector(tokens);

        // skip empty lines
        if(tokens.size()==0) continue;

        // it's a data line
        if(tokens.size() == 2) {
            t.push_back(lexical_cast<double>(tokens[0]), lexical_cast<double>(tokens[1]), 'i');
        }
        else if(tokens.size() > 3) {
            t.push_back(lexical_cast<double>(tokens[0]), lexical_cast<double>(tokens[1]), tokens[2].c_str()[0]);
        }
        // otherwise error
        else throw runtime_error("error, wrong table format");

        // was size given and did we read N values?
        if(bHasN)
            if(--N == 0) break;
    }

    return in;
}

void Table::GenerateGridSpacing(double min, double max, double spacing)
{
    int n = floor((max - min)/spacing + 1.000000001);
    resize(n);
    int i=0;
    for(double x=min; i<n; x+=spacing, ++i)
        _x[i] = x;
}

void Table::Smooth(int Nsmooth)
{
    while(Nsmooth-- > 0)
        for(int i=1; i<size()-1; ++i)
            _y[i] =0.25*(_y[i-1] + 2*_y[i] +  _y[i+1]);
}

<commit_msg>fixed a bug for reading tables i recently introduced<commit_after>/*
 * File:   table.cc
 * Author: victorr
 *
 * Created on June 11, 2008, 1:48 PM
 */

#include <fstream>
#include <vector>
#include <boost/lexical_cast.hpp>
#include "tokenizer.h"
#include "table.h"
#include <stdexcept>

using namespace boost;

void Table::Load(string filename)
{
    ifstream in;
    in.open(filename.c_str());
    if(!in)
        throw runtime_error(string("error, cannot open file ") + filename);

    in >> *this;

    in.close();
}

void Table::Save(string filename) const
{
    ofstream out;
    out.open(filename.c_str());
    if(!out)
        throw runtime_error(string("error, cannot open file ") + filename);

    out << (*this);

    out.close();
}

void Table::clear(void)
{
    _x.clear();
    _y.clear();
    _flags.clear();
}

// TODO: this functon is weired, reading occours twice, cleanup!!
inline istream &operator>>(istream &in, Table& t)
{
    size_t N;
    bool bHasN=false;
    string line;

   t.clear();

    // read till the first data line
    while(getline(in, line)) {
        // remove comments and xmgrace stuff
        line = line.substr(0, line.find("#"));
        line = line.substr(0, line.find("@"));

        // tokenize string and put it to vector
        Tokenizer tok(line, " \t");
        vector<string> tokens;
        tok.ToVector(tokens);

        // skip empty lines
        if(tokens.size()==0) continue;

        // if first line is only 1 token, it's the size
        if(tokens.size() == 1) {
            N = lexical_cast<int>(tokens[0]);
            bHasN = true;
        }
        // it's the first data line with 2 or 3 entries
        else if(tokens.size() == 2) {
            t.push_back(lexical_cast<double>(tokens[0]), lexical_cast<double>(tokens[1]), 'i');
        }
        else if(tokens.size() > 2) {
            t.push_back(lexical_cast<double>(tokens[0]), lexical_cast<double>(tokens[1]), tokens[2].c_str()[0]);
        }
        else throw runtime_error("error, wrong table format");
    }

    // read the rest
    while(getline(in, line)) {
        // remove comments and xmgrace stuff
        line = line.substr(0, line.find("#"));
        line = line.substr(0, line.find("@"));

        // tokenize string and put it to vector
        Tokenizer tok(line, " \t");
        vector<string> tokens;
        tok.ToVector(tokens);

        // skip empty lines
        if(tokens.size()==0) continue;

        // it's a data line
        if(tokens.size() == 2) {
            t.push_back(lexical_cast<double>(tokens[0]), lexical_cast<double>(tokens[1]), 'i');
        }
        else if(tokens.size() > 2) {
            t.push_back(lexical_cast<double>(tokens[0]), lexical_cast<double>(tokens[1]), tokens[2].c_str()[0]);
        }
        // otherwise error
        else throw runtime_error("error, wrong table format");

        // was size given and did we read N values?
        if(bHasN)
            if(--N == 0) break;
    }

    return in;
}

void Table::GenerateGridSpacing(double min, double max, double spacing)
{
    int n = floor((max - min)/spacing + 1.000000001);
    resize(n);
    int i=0;
    for(double x=min; i<n; x+=spacing, ++i)
        _x[i] = x;
}

void Table::Smooth(int Nsmooth)
{
    while(Nsmooth-- > 0)
        for(int i=1; i<size()-1; ++i)
            _y[i] =0.25*(_y[i-1] + 2*_y[i] +  _y[i+1]);
}

<|endoftext|>


<commit_before>#pragma once

#include <list>
#include <sdbusplus/exception.hpp>
#include <sdbusplus/server.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/message/types.hpp>
#include <sdbusplus/message/read.hpp>
#include <sdbusplus/utility/tuple_to_array.hpp>
#include <boost/any.hpp>
#include <boost/container/flat_map.hpp>

namespace sdbusplus
{
namespace asio
{

constexpr const char *PropertyNameAllowedCharacters =
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
class callback
{
  public:
    virtual int call(message::message &m) = 0;
};
class callback_set
{
  public:
    virtual int call(message::message &m) = 0;
    virtual int set(const boost::any &value) = 0;
};

template <typename CallbackType>
class callback_method_instance : public callback
{
  public:
    callback_method_instance(CallbackType &&func) : func_(std::move(func))
    {
    }
    int call(message::message &m) override
    {
        InputTupleType inputArgs;
        if (!utility::read_into_tuple(inputArgs, m))
        {
            return -EINVAL;
        }

        auto ret = m.new_method_return();
        callFunction<ResultType>(ret, inputArgs);
        ret.method_return();
        return 1;
    };

  private:
    using CallbackSignature = boost::callable_traits::args_t<CallbackType>;
    using InputTupleType =
        typename utility::decay_tuple<CallbackSignature>::type;
    using ResultType = boost::callable_traits::return_type_t<CallbackType>;
    CallbackType func_;
    template <typename T>
    std::enable_if_t<!std::is_void<T>::value, void>
        callFunction(message::message &m, InputTupleType &inputArgs)
    {
        ResultType r = std::experimental::apply(func_, inputArgs);
        m.append(r);
    }
    template <typename T>
    std::enable_if_t<std::is_void<T>::value, void>
        callFunction(message::message &m, InputTupleType &inputArgs)
    {
        std::experimental::apply(func_, inputArgs);
    }
};

template <typename PropertyType, typename CallbackType>
class callback_get_instance : public callback
{
  public:
    callback_get_instance(const std::shared_ptr<PropertyType> &value,
                          CallbackType &&func) :
        value_(value),
        func_(std::move(func))
    {
    }
    int call(message::message &m) override
    {
        auto r = func_(*value_);
        m.append(r);
        return 1;
    }

  private:
    std::shared_ptr<PropertyType> value_;
    CallbackType func_;
};

template <typename PropertyType, typename CallbackType>
class callback_set_instance : public callback_set
{
  public:
    callback_set_instance(const std::shared_ptr<PropertyType> &value,
                          CallbackType &&func) :
        value_(value),
        func_(std::move(func))
    {
    }
    int call(message::message &m) override
    {
        PropertyType input;
        m.read(input);

        return func_(input, *value_);
    }
    int set(const boost::any &value)
    {
        return func_(boost::any_cast<PropertyType>(value), *value_);
    }

  private:
    std::shared_ptr<PropertyType> value_;
    CallbackType func_;
};

enum class PropertyPermission
{
    readOnly,
    readWrite
};
class dbus_interface
{
  public:
    dbus_interface(std::shared_ptr<sdbusplus::asio::connection> conn,
                   const std::string &path, const std::string &name) :
        conn_(conn),
        path_(path), name_(name)

    {
        vtable_.emplace_back(vtable::start());
    }

    // default getter and setter
    template <typename PropertyType>
    bool register_property(
        const std::string &name, const PropertyType &property,
        PropertyPermission access = PropertyPermission::readOnly)
    {
        // can only register once
        if (initialized_)
        {
            return false;
        }
        if (name.find_first_not_of(PropertyNameAllowedCharacters) !=
            std::string::npos)
        {
            return false;
        }
        static const auto type =
            utility::tuple_to_array(message::types::type_id<PropertyType>());

        auto nameItr = propertyNames_.emplace(propertyNames_.end(), name);
        auto propertyPtr = std::make_shared<PropertyType>(property);

        callbacksGet_[name] = std::make_unique<callback_get_instance<
            PropertyType, std::function<PropertyType(const PropertyType &)>>>(
            propertyPtr, [](const PropertyType &value) { return value; });
        callbacksSet_[name] = std::make_unique<callback_set_instance<
            PropertyType,
            std::function<int(const PropertyType &, PropertyType &)>>>(
            propertyPtr, [](const PropertyType &req, PropertyType &old) {
                old = req;
                return 1;
            });

        if (access == PropertyPermission::readOnly)
        {
            vtable_.emplace_back(
                vtable::property(nameItr->c_str(), type.data(), get_handler,
                                 vtable::property_::emits_change));
        }
        else
        {
            vtable_.emplace_back(
                vtable::property(nameItr->c_str(), type.data(), get_handler,
                                 set_handler, vtable::property_::emits_change));
        }
        return true;
    }

    // custom setter, sets take an input property and respond with an int status
    template <typename PropertyType, typename CallbackType>
    bool register_property(const std::string &name,
                           const PropertyType &property,
                           CallbackType &&setFunction)
    {
        // can only register once
        if (initialized_)
        {
            return false;
        }
        if (name.find_first_not_of(PropertyNameAllowedCharacters) !=
            std::string::npos)
        {
            return false;
        }
        static const auto type =
            utility::tuple_to_array(message::types::type_id<PropertyType>());

        auto nameItr = propertyNames_.emplace(propertyNames_.end(), name);
        auto propertyPtr = std::make_shared<PropertyType>(property);

        callbacksGet_[name] = std::make_unique<callback_get_instance<
            PropertyType, std::function<PropertyType(const PropertyType &)>>>(
            propertyPtr, [](const PropertyType &value) { return value; });

        callbacksSet_[name] =
            std::make_unique<callback_set_instance<PropertyType, CallbackType>>(
                propertyPtr, std::move(setFunction));
        vtable_.emplace_back(vtable::property(nameItr->c_str(), type.data(),
                                              get_handler, set_handler,
                                              vtable::property_::emits_change));

        return true;
    }

    // custom getter and setter, gets take an input of void and respond with a
    // property. property is only passed for type deduction
    template <typename PropertyType, typename CallbackType,
              typename CallbackTypeGet>
    bool register_property(const std::string &name,
                           const PropertyType &property,
                           CallbackType &&setFunction,
                           CallbackTypeGet &&getFunction)
    {
        // can only register once
        if (initialized_)
        {
            return false;
        }
        if (name.find_first_not_of(PropertyNameAllowedCharacters) !=
            std::string::npos)
        {
            return false;
        }
        static const auto type =
            utility::tuple_to_array(message::types::type_id<PropertyType>());

        auto nameItr = propertyNames_.emplace(propertyNames_.end(), name);
        auto propertyPtr = std::make_shared<PropertyType>(property);

        callbacksGet_[name] = std::make_unique<
            callback_get_instance<PropertyType, CallbackTypeGet>>(
            propertyPtr, std::move(getFunction));
        callbacksSet_[name] =
            std::make_unique<callback_set_instance<PropertyType, CallbackType>>(
                propertyPtr, std::move(setFunction));

        vtable_.emplace_back(vtable::property(nameItr->c_str(), type.data(),
                                              get_handler, set_handler,
                                              vtable::property_::emits_change));

        return true;
    }
    template <typename PropertyType>
    bool set_property(const std::string &name, const PropertyType &value)
    {
        if (!initialized_)
        {
            return false;
        }
        auto func = callbacksSet_.find(name);
        if (func != callbacksSet_.end())
        {
            if (func->second->set(value) != 1)
            {
                return false;
            }
            signal_property(name);
            return true;
        }
        return false;
    }

    template <typename CallbackType>
    bool register_method(const std::string &name, CallbackType &&handler)
    {
        using CallbackSignature = boost::callable_traits::args_t<CallbackType>;
        using InputTupleType =
            typename utility::decay_tuple<CallbackSignature>::type;
        using ResultType = boost::callable_traits::return_type_t<CallbackType>;

        if (initialized_)
        {
            return false;
        }
        static const auto argType = utility::strip_ends(
            utility::tuple_to_array(message::types::type_id<InputTupleType>()));
        static const auto resultType =
            utility::tuple_to_array(message::types::type_id<ResultType>());

        auto nameItr = methodNames_.emplace(methodNames_.end(), name);

        callbacksMethod_[name] =
            std::make_unique<callback_method_instance<CallbackType>>(
                std::move(handler));

        vtable_.emplace_back(vtable::method(nameItr->c_str(), argType.data(),
                                            resultType.data(), method_handler));
        return true;
    }

    static int get_handler(sd_bus *bus, const char *path, const char *interface,
                           const char *property, sd_bus_message *reply,
                           void *userdata, sd_bus_error *error)
    {
        dbus_interface *data = static_cast<dbus_interface *>(userdata);
        auto func = data->callbacksGet_.find(property);
        auto mesg = message::message(reply);
        if (func != data->callbacksGet_.end())
        {
#ifdef __EXCEPTIONS
            try
            {
#endif
                return func->second->call(mesg);
#ifdef __EXCEPTIONS
            }

            catch (sdbusplus::exception_t &e)
            {
                sd_bus_error_set_const(error, e.name(), e.description());
                return -EINVAL;
            }
            catch (...)
            {
                // hit default error below
            }
#endif
        }
        sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS, NULL);
        return -EINVAL;
    }

    static int set_handler(sd_bus *bus, const char *path, const char *interface,
                           const char *property, sd_bus_message *value,
                           void *userdata, sd_bus_error *error)
    {
        dbus_interface *data = static_cast<dbus_interface *>(userdata);
        auto func = data->callbacksSet_.find(property);
        auto mesg = message::message(value);
        if (func != data->callbacksSet_.end())
        {
#ifdef __EXCEPTIONS
            try
            {
#endif
                int status = func->second->call(mesg);
                if (status == 1)
                {
                    data->signal_property(property);
                    return status;
                }
#ifdef __EXCEPTIONS
            }

            catch (sdbusplus::exception_t &e)
            {
                sd_bus_error_set_const(error, e.name(), e.description());
                return -EINVAL;
            }
            catch (...)
            {
                // hit default error below
            }
#endif
        }
        sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS, NULL);
        return -EINVAL;
    }

    static int method_handler(sd_bus_message *m, void *userdata,
                              sd_bus_error *error)
    {
        dbus_interface *data = static_cast<dbus_interface *>(userdata);
        auto mesg = message::message(m);
        auto func = data->callbacksMethod_.find(mesg.get_member());
        if (func != data->callbacksMethod_.end())
        {
#ifdef __EXCEPTIONS
            try
            {
#endif
                int status = func->second->call(mesg);
                if (status == 1)
                {
                    return status;
                }
#ifdef __EXCEPTIONS
            }

            catch (sdbusplus::exception_t &e)
            {
                sd_bus_error_set_const(error, e.name(), e.description());
                return -EINVAL;
            }
            catch (...)
            {
                // hit default error below
            }
#endif
        }
        sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS, NULL);
        return -EINVAL;
    }

    bool initialize()
    {
        // can only register once
        if (initialized_)
        {
            return false;
        }
        initialized_ = true;
        vtable_.emplace_back(vtable::end());

        interface_ = std::make_unique<sdbusplus::server::interface::interface>(
            static_cast<sdbusplus::bus::bus &>(*conn_), path_.c_str(),
            name_.c_str(), static_cast<const sd_bus_vtable *>(&vtable_[0]),
            this);

        for (const std::string &name : propertyNames_)
        {
            signal_property(name);
        }
        return true;
    }
    void signal_property(const std::string &name)
    {
        interface_->property_changed(name.c_str());
    }

    std::string get_object_path(void)
    {
        return path_;
    }

    std::string get_interface_name(void)
    {
        return name_;
    }

  private:
    std::shared_ptr<sdbusplus::asio::connection> conn_;
    std::string path_;
    std::string name_;
    std::list<std::string> propertyNames_;
    std::list<std::string> methodNames_;
    boost::container::flat_map<std::string, std::unique_ptr<callback>>
        callbacksGet_;
    boost::container::flat_map<std::string, std::unique_ptr<callback_set>>
        callbacksSet_;
    boost::container::flat_map<std::string, std::unique_ptr<callback>>
        callbacksMethod_;
    std::vector<sd_bus_vtable> vtable_;
    std::unique_ptr<sdbusplus::server::interface::interface> interface_;

    bool initialized_ = false;
};

class object_server
{
  public:
    object_server(std::shared_ptr<sdbusplus::asio::connection> &conn) :
        conn_(conn)
    {
        auto root = add_interface("/", "");
        root->initialize();
        add_manager("/");
    }

    std::shared_ptr<dbus_interface> add_interface(const std::string &path,
                                                  const std::string &name)
    {

        auto dbusIface = std::make_shared<dbus_interface>(conn_, path, name);
        interfaces_.emplace_back(dbusIface);
        return dbusIface;
    }

    void add_manager(const std::string &path)
    {
        managers_.emplace_back(
            std::make_unique<server::manager::manager>(server::manager::manager(
                static_cast<sdbusplus::bus::bus &>(*conn_), path.c_str())));
    }

    bool remove_interface(std::shared_ptr<dbus_interface> &iface)
    {
        auto findIface =
            std::find(interfaces_.begin(), interfaces_.end(), iface);
        if (findIface != interfaces_.end())
        {
            interfaces_.erase(findIface);
            return true;
        }
        return false;
    }

  private:
    std::shared_ptr<sdbusplus::asio::connection> conn_;
    std::vector<std::shared_ptr<dbus_interface>> interfaces_;
    std::vector<std::unique_ptr<server::manager::manager>> managers_;
};

} // namespace asio
} // namespace sdbusplus
<commit_msg>Correctly trigger interfaces added and removed<commit_after>#pragma once

#include <list>
#include <sdbusplus/exception.hpp>
#include <sdbusplus/server.hpp>
#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/message/types.hpp>
#include <sdbusplus/message/read.hpp>
#include <sdbusplus/utility/tuple_to_array.hpp>
#include <boost/any.hpp>
#include <boost/container/flat_map.hpp>

namespace sdbusplus
{
namespace asio
{

constexpr const char *PropertyNameAllowedCharacters =
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
class callback
{
  public:
    virtual int call(message::message &m) = 0;
};
class callback_set
{
  public:
    virtual int call(message::message &m) = 0;
    virtual int set(const boost::any &value) = 0;
};

template <typename CallbackType>
class callback_method_instance : public callback
{
  public:
    callback_method_instance(CallbackType &&func) : func_(std::move(func))
    {
    }
    int call(message::message &m) override
    {
        InputTupleType inputArgs;
        if (!utility::read_into_tuple(inputArgs, m))
        {
            return -EINVAL;
        }

        auto ret = m.new_method_return();
        callFunction<ResultType>(ret, inputArgs);
        ret.method_return();
        return 1;
    };

  private:
    using CallbackSignature = boost::callable_traits::args_t<CallbackType>;
    using InputTupleType =
        typename utility::decay_tuple<CallbackSignature>::type;
    using ResultType = boost::callable_traits::return_type_t<CallbackType>;
    CallbackType func_;
    template <typename T>
    std::enable_if_t<!std::is_void<T>::value, void>
        callFunction(message::message &m, InputTupleType &inputArgs)
    {
        ResultType r = std::experimental::apply(func_, inputArgs);
        m.append(r);
    }
    template <typename T>
    std::enable_if_t<std::is_void<T>::value, void>
        callFunction(message::message &m, InputTupleType &inputArgs)
    {
        std::experimental::apply(func_, inputArgs);
    }
};

template <typename PropertyType, typename CallbackType>
class callback_get_instance : public callback
{
  public:
    callback_get_instance(const std::shared_ptr<PropertyType> &value,
                          CallbackType &&func) :
        value_(value),
        func_(std::move(func))
    {
    }
    int call(message::message &m) override
    {
        auto r = func_(*value_);
        m.append(r);
        return 1;
    }

  private:
    std::shared_ptr<PropertyType> value_;
    CallbackType func_;
};

template <typename PropertyType, typename CallbackType>
class callback_set_instance : public callback_set
{
  public:
    callback_set_instance(const std::shared_ptr<PropertyType> &value,
                          CallbackType &&func) :
        value_(value),
        func_(std::move(func))
    {
    }
    int call(message::message &m) override
    {
        PropertyType input;
        m.read(input);

        return func_(input, *value_);
    }
    int set(const boost::any &value)
    {
        return func_(boost::any_cast<PropertyType>(value), *value_);
    }

  private:
    std::shared_ptr<PropertyType> value_;
    CallbackType func_;
};

enum class PropertyPermission
{
    readOnly,
    readWrite
};
class dbus_interface
{
  public:
    dbus_interface(std::shared_ptr<sdbusplus::asio::connection> conn,
                   const std::string &path, const std::string &name) :
        conn_(conn),
        path_(path), name_(name)

    {
        vtable_.emplace_back(vtable::start());
    }
    ~dbus_interface()
    {
        conn_->emit_interfaces_removed(path_.c_str(),
                                       std::vector<std::string>{name_});
    }

    // default getter and setter
    template <typename PropertyType>
    bool register_property(
        const std::string &name, const PropertyType &property,
        PropertyPermission access = PropertyPermission::readOnly)
    {
        // can only register once
        if (initialized_)
        {
            return false;
        }
        if (name.find_first_not_of(PropertyNameAllowedCharacters) !=
            std::string::npos)
        {
            return false;
        }
        static const auto type =
            utility::tuple_to_array(message::types::type_id<PropertyType>());

        auto nameItr = propertyNames_.emplace(propertyNames_.end(), name);
        auto propertyPtr = std::make_shared<PropertyType>(property);

        callbacksGet_[name] = std::make_unique<callback_get_instance<
            PropertyType, std::function<PropertyType(const PropertyType &)>>>(
            propertyPtr, [](const PropertyType &value) { return value; });
        callbacksSet_[name] = std::make_unique<callback_set_instance<
            PropertyType,
            std::function<int(const PropertyType &, PropertyType &)>>>(
            propertyPtr, [](const PropertyType &req, PropertyType &old) {
                old = req;
                return 1;
            });

        if (access == PropertyPermission::readOnly)
        {
            vtable_.emplace_back(
                vtable::property(nameItr->c_str(), type.data(), get_handler,
                                 vtable::property_::emits_change));
        }
        else
        {
            vtable_.emplace_back(
                vtable::property(nameItr->c_str(), type.data(), get_handler,
                                 set_handler, vtable::property_::emits_change));
        }
        return true;
    }

    // custom setter, sets take an input property and respond with an int status
    template <typename PropertyType, typename CallbackType>
    bool register_property(const std::string &name,
                           const PropertyType &property,
                           CallbackType &&setFunction)
    {
        // can only register once
        if (initialized_)
        {
            return false;
        }
        if (name.find_first_not_of(PropertyNameAllowedCharacters) !=
            std::string::npos)
        {
            return false;
        }
        static const auto type =
            utility::tuple_to_array(message::types::type_id<PropertyType>());

        auto nameItr = propertyNames_.emplace(propertyNames_.end(), name);
        auto propertyPtr = std::make_shared<PropertyType>(property);

        callbacksGet_[name] = std::make_unique<callback_get_instance<
            PropertyType, std::function<PropertyType(const PropertyType &)>>>(
            propertyPtr, [](const PropertyType &value) { return value; });

        callbacksSet_[name] =
            std::make_unique<callback_set_instance<PropertyType, CallbackType>>(
                propertyPtr, std::move(setFunction));
        vtable_.emplace_back(vtable::property(nameItr->c_str(), type.data(),
                                              get_handler, set_handler,
                                              vtable::property_::emits_change));

        return true;
    }

    // custom getter and setter, gets take an input of void and respond with a
    // property. property is only passed for type deduction
    template <typename PropertyType, typename CallbackType,
              typename CallbackTypeGet>
    bool register_property(const std::string &name,
                           const PropertyType &property,
                           CallbackType &&setFunction,
                           CallbackTypeGet &&getFunction)
    {
        // can only register once
        if (initialized_)
        {
            return false;
        }
        if (name.find_first_not_of(PropertyNameAllowedCharacters) !=
            std::string::npos)
        {
            return false;
        }
        static const auto type =
            utility::tuple_to_array(message::types::type_id<PropertyType>());

        auto nameItr = propertyNames_.emplace(propertyNames_.end(), name);
        auto propertyPtr = std::make_shared<PropertyType>(property);

        callbacksGet_[name] = std::make_unique<
            callback_get_instance<PropertyType, CallbackTypeGet>>(
            propertyPtr, std::move(getFunction));
        callbacksSet_[name] =
            std::make_unique<callback_set_instance<PropertyType, CallbackType>>(
                propertyPtr, std::move(setFunction));

        vtable_.emplace_back(vtable::property(nameItr->c_str(), type.data(),
                                              get_handler, set_handler,
                                              vtable::property_::emits_change));

        return true;
    }
    template <typename PropertyType>
    bool set_property(const std::string &name, const PropertyType &value)
    {
        if (!initialized_)
        {
            return false;
        }
        auto func = callbacksSet_.find(name);
        if (func != callbacksSet_.end())
        {
            if (func->second->set(value) != 1)
            {
                return false;
            }
            signal_property(name);
            return true;
        }
        return false;
    }

    template <typename CallbackType>
    bool register_method(const std::string &name, CallbackType &&handler)
    {
        using CallbackSignature = boost::callable_traits::args_t<CallbackType>;
        using InputTupleType =
            typename utility::decay_tuple<CallbackSignature>::type;
        using ResultType = boost::callable_traits::return_type_t<CallbackType>;

        if (initialized_)
        {
            return false;
        }
        static const auto argType = utility::strip_ends(
            utility::tuple_to_array(message::types::type_id<InputTupleType>()));
        static const auto resultType =
            utility::tuple_to_array(message::types::type_id<ResultType>());

        auto nameItr = methodNames_.emplace(methodNames_.end(), name);

        callbacksMethod_[name] =
            std::make_unique<callback_method_instance<CallbackType>>(
                std::move(handler));

        vtable_.emplace_back(vtable::method(nameItr->c_str(), argType.data(),
                                            resultType.data(), method_handler));
        return true;
    }

    static int get_handler(sd_bus *bus, const char *path, const char *interface,
                           const char *property, sd_bus_message *reply,
                           void *userdata, sd_bus_error *error)
    {
        dbus_interface *data = static_cast<dbus_interface *>(userdata);
        auto func = data->callbacksGet_.find(property);
        auto mesg = message::message(reply);
        if (func != data->callbacksGet_.end())
        {
#ifdef __EXCEPTIONS
            try
            {
#endif
                return func->second->call(mesg);
#ifdef __EXCEPTIONS
            }

            catch (sdbusplus::exception_t &e)
            {
                sd_bus_error_set_const(error, e.name(), e.description());
                return -EINVAL;
            }
            catch (...)
            {
                // hit default error below
            }
#endif
        }
        sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS, NULL);
        return -EINVAL;
    }

    static int set_handler(sd_bus *bus, const char *path, const char *interface,
                           const char *property, sd_bus_message *value,
                           void *userdata, sd_bus_error *error)
    {
        dbus_interface *data = static_cast<dbus_interface *>(userdata);
        auto func = data->callbacksSet_.find(property);
        auto mesg = message::message(value);
        if (func != data->callbacksSet_.end())
        {
#ifdef __EXCEPTIONS
            try
            {
#endif
                int status = func->second->call(mesg);
                if (status == 1)
                {
                    data->signal_property(property);
                    return status;
                }
#ifdef __EXCEPTIONS
            }

            catch (sdbusplus::exception_t &e)
            {
                sd_bus_error_set_const(error, e.name(), e.description());
                return -EINVAL;
            }
            catch (...)
            {
                // hit default error below
            }
#endif
        }
        sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS, NULL);
        return -EINVAL;
    }

    static int method_handler(sd_bus_message *m, void *userdata,
                              sd_bus_error *error)
    {
        dbus_interface *data = static_cast<dbus_interface *>(userdata);
        auto mesg = message::message(m);
        auto func = data->callbacksMethod_.find(mesg.get_member());
        if (func != data->callbacksMethod_.end())
        {
#ifdef __EXCEPTIONS
            try
            {
#endif
                int status = func->second->call(mesg);
                if (status == 1)
                {
                    return status;
                }
#ifdef __EXCEPTIONS
            }

            catch (sdbusplus::exception_t &e)
            {
                sd_bus_error_set_const(error, e.name(), e.description());
                return -EINVAL;
            }
            catch (...)
            {
                // hit default error below
            }
#endif
        }
        sd_bus_error_set_const(error, SD_BUS_ERROR_INVALID_ARGS, NULL);
        return -EINVAL;
    }

    bool initialize()
    {
        // can only register once
        if (initialized_)
        {
            return false;
        }
        initialized_ = true;
        vtable_.emplace_back(vtable::end());

        interface_ = std::make_unique<sdbusplus::server::interface::interface>(
            static_cast<sdbusplus::bus::bus &>(*conn_), path_.c_str(),
            name_.c_str(), static_cast<const sd_bus_vtable *>(&vtable_[0]),
            this);
        conn_->emit_interfaces_added(path_.c_str(),
                                     std::vector<std::string>{name_});
        for (const std::string &name : propertyNames_)
        {
            signal_property(name);
        }
        return true;
    }
    void signal_property(const std::string &name)
    {
        interface_->property_changed(name.c_str());
    }

    std::string get_object_path(void)
    {
        return path_;
    }

    std::string get_interface_name(void)
    {
        return name_;
    }

  private:
    std::shared_ptr<sdbusplus::asio::connection> conn_;
    std::string path_;
    std::string name_;
    std::list<std::string> propertyNames_;
    std::list<std::string> methodNames_;
    boost::container::flat_map<std::string, std::unique_ptr<callback>>
        callbacksGet_;
    boost::container::flat_map<std::string, std::unique_ptr<callback_set>>
        callbacksSet_;
    boost::container::flat_map<std::string, std::unique_ptr<callback>>
        callbacksMethod_;
    std::vector<sd_bus_vtable> vtable_;
    std::unique_ptr<sdbusplus::server::interface::interface> interface_;

    bool initialized_ = false;
};

class object_server
{
  public:
    object_server(std::shared_ptr<sdbusplus::asio::connection> &conn) :
        conn_(conn)
    {
        auto root = add_interface("/", "");
        root->initialize();
        add_manager("/");
    }

    std::shared_ptr<dbus_interface> add_interface(const std::string &path,
                                                  const std::string &name)
    {

        auto dbusIface = std::make_shared<dbus_interface>(conn_, path, name);
        interfaces_.emplace_back(dbusIface);
        return dbusIface;
    }

    void add_manager(const std::string &path)
    {
        managers_.emplace_back(
            std::make_unique<server::manager::manager>(server::manager::manager(
                static_cast<sdbusplus::bus::bus &>(*conn_), path.c_str())));
    }

    bool remove_interface(std::shared_ptr<dbus_interface> &iface)
    {
        auto findIface =
            std::find(interfaces_.begin(), interfaces_.end(), iface);
        if (findIface != interfaces_.end())
        {
            interfaces_.erase(findIface);
            return true;
        }
        return false;
    }

  private:
    std::shared_ptr<sdbusplus::asio::connection> conn_;
    std::vector<std::shared_ptr<dbus_interface>> interfaces_;
    std::vector<std::unique_ptr<server::manager::manager>> managers_;
};

} // namespace asio
} // namespace sdbusplus
<|endoftext|>


<commit_before>/*
 *  AlphaWheel.cpp
 *  Kepler
 *
 *  Created by Tom Carden on 3/14/11.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

#include "AlphaWheel.h"
#include "cinder/gl/gl.h"
#include "cinder/Font.h"
#include "cinder/Text.h"
#include "cinder/ImageIo.h"
#include "Globals.h"
#include "BloomGl.h"
#include "UIController.h"
#include "cinder/app/AppCocoaTouch.h" // for loadResource, getElapsedSeconds
#include "cinder/Utilities.h" // for toString
#include <sstream>

using namespace ci;
using namespace ci::app;
using namespace std;

void AlphaWheel::setup( const Font &font )
{
	// Textures
	mWheelTex		= gl::Texture( loadImage( loadResource( "alphaWheelMask.png" ) ) );

	mAlphaString	= "ABCDEFGHIJKLMNOPQRSTUVWXYZ#";
	mAlphaIndex		= 0;
	mAlphaChar		= ' ';
	mPrevAlphaChar	= ' ';
	mShowWheel		= false;
	mWheelScale		= 1.0f;

	initAlphaTextures( font );

//    mInterfaceSize = mRoot->getInterfaceSize();
//
//    mInterfaceCenter = mInterfaceSize * 0.5f;
//
//	setRects();
}

void AlphaWheel::initAlphaTextures( const Font &font )
{
	for( int i=0; i<mAlphaString.length(); i++ ){
//		float per = (float)i/27.0f;
//		float angle = per * TWO_PI - M_PI_2;
		TextLayout layout;
		layout.setFont( font );
		layout.setColor( ColorA( BRIGHT_BLUE, 1.0f ) );
		layout.addCenteredLine( ci::toString(mAlphaString[i]) );
		mAlphaTextures.push_back( gl::Texture( layout.render( true, false ) ) );

        // setRects()
//		float w = mAlphaTextures[i].getWidth()/2.0f;
//		float h = mAlphaTextures[i].getHeight()/2.0f;
//		Vec2f pos = Vec2f( cos( angle ), sin( angle ) ) * mAlphaRadius;
//		Rectf r = Rectf( pos.x - w, pos.y - h, pos.x + w, pos.y + h );
//		mAlphaRects.push_back( r );
	}
}

void AlphaWheel::setRects()
{
	mAlphaRects.clear();
	for( int i=0; i<mAlphaString.length(); i++ ){
		float per = (float)i/27.0f;
		float angle = per * TWO_PI - M_PI_2;
		float w = mAlphaTextures[i].getWidth()/2.0f;
		float h = mAlphaTextures[i].getHeight()/2.0f;
		Vec2f pos = Vec2f( cos( angle ), sin( angle ) ) * mAlphaRadius;
		Rectf r = Rectf( pos.x - w, pos.y - h, pos.x + w, pos.y + h );
		mAlphaRects.push_back( r );
	}
}

void AlphaWheel::setVerts()
{
	mTotalVertices = 54;
	delete[] mVerts;
	mVerts = NULL;
	mVerts = new VertexData[mTotalVertices];

	float W	= mInterfaceSize.x;
	float H = mInterfaceSize.y;
	float CW = W/2;
	float CH = H/2;
	float L = ( W - mAlphaRadius * 2.0f )/2;
	float T = ( H - mAlphaRadius * 2.0f )/2;
	float R = L + mAlphaRadius * 2.0f;
	float B = T + mAlphaRadius * 2.0f;

	vector<Vec2i> positions;
	positions.push_back( Vec2i( 0 - CW, 0 - CH ) );
	positions.push_back( Vec2i( L - CW, 0 - CH ) );
	positions.push_back( Vec2i( R - CW, 0 - CH ) );
	positions.push_back( Vec2i( W - CW, 0 - CH ) );

	positions.push_back( Vec2i( 0 - CW, T - CH ) );
	positions.push_back( Vec2i( L - CW, T - CH ) );
	positions.push_back( Vec2i( R - CW, T - CH ) );
	positions.push_back( Vec2i( W - CW, T - CH ) );

	positions.push_back( Vec2i( 0 - CW, B - CH ) );
	positions.push_back( Vec2i( L - CW, B - CH ) );
	positions.push_back( Vec2i( R - CW, B - CH ) );
	positions.push_back( Vec2i( W - CW, B - CH ) );

	positions.push_back( Vec2i( 0 - CW, H - CH ) );
	positions.push_back( Vec2i( L - CW, H - CH ) );
	positions.push_back( Vec2i( R - CW, H - CH ) );
	positions.push_back( Vec2i( W - CW, H - CH ) );

	vector<Vec2f> textures;
	textures.push_back( Vec2f( 0, 0 ) );
	textures.push_back( Vec2f( 0, 0 ) );
	textures.push_back( Vec2f( 1, 0 ) );
	textures.push_back( Vec2f( 1, 0 ) );

	textures.push_back( Vec2f( 0, 0 ) );
	textures.push_back( Vec2f( 0, 0 ) );
	textures.push_back( Vec2f( 1, 0 ) );
	textures.push_back( Vec2f( 1, 0 ) );

	textures.push_back( Vec2f( 0, 1 ) );
	textures.push_back( Vec2f( 0, 1 ) );
	textures.push_back( Vec2f( 1, 1 ) );
	textures.push_back( Vec2f( 1, 1 ) );

	textures.push_back( Vec2f( 0, 1 ) );
	textures.push_back( Vec2f( 0, 1 ) );
	textures.push_back( Vec2f( 1, 1 ) );
	textures.push_back( Vec2f( 1, 1 ) );

	int indices[54] = { 0, 1, 4,
					  1, 5, 4,
					  1, 2, 5,
					  2, 6, 5,
					  2, 3, 6,
					  3, 7, 6,
					  4, 5, 8,
					  5, 9, 8,
					  5, 6, 9,
					  6, 10, 9,
					  6, 7, 10,
					  7, 11, 10,
					  8, 9, 12,
					  9, 13, 12,
					  9, 10, 13,
					  10, 14, 13,
					  10, 11, 14,
					  11, 15, 14 };

	int vIndex = 0;
	for( int i=0; i<54; i++ ){
		mVerts[vIndex].vertex	= positions[indices[i]];
		mVerts[vIndex].texture	= textures[indices[i]];

		vIndex ++;
	}
}

bool AlphaWheel::touchBegan( TouchEvent::Touch touch )
{
    if (!mShowWheel) return false;

    if (selectWheelItem( touch.getPos(), false )) {
        // this means we'll follow the last touch that starts on a wheel item
        mLastTouchPos = touch.getPos();
        mActiveTouchId = touch.getId();
        return true;
    }

	return false;
}

bool AlphaWheel::touchMoved( TouchEvent::Touch touch )
{
    if (mShowWheel) {
        // only follow the last valid touch we received
        if (touch.getId() == mActiveTouchId) {
            mLastTouchPos = touch.getPos();
            return selectWheelItem( mLastTouchPos, false );
        }
    }
	return false;
}

bool AlphaWheel::touchEnded( TouchEvent::Touch touch )
{
    if (!mShowWheel) return false;

    mLastTouchPos = touch.getPos();
    return selectWheelItem( mLastTouchPos, true );
}

bool AlphaWheel::selectWheelItem( const Vec2f &pos, bool closeWheel )
{
	if( !mShowWheel ){
		return false;
	}
	float minDiam = mAlphaRadius - 25.0f;
	float maxDiam = mAlphaRadius + 25.0f;

	float timeSincePinchEnded = getElapsedSeconds() - mTimePinchEnded;
	if( mShowWheel && timeSincePinchEnded > 0.5f ){
        Vec2f dir = globalToLocal(pos) - mInterfaceCenter;
		float distToCenter = dir.length();
		if( distToCenter > minDiam && distToCenter < maxDiam ){
			float touchAngle	= atan2( dir.y, dir.x ) + M_PI;				// RANGE 0 -> TWO_PI
			float anglePer		= ( touchAngle + 0.11365f + M_PI*1.5f )/TWO_PI;
			mAlphaIndex			= (int)( anglePer * 27 )%27;
			mPrevAlphaChar		= mAlphaChar;
			mAlphaChar			= mAlphaString.at( mAlphaIndex % mAlphaString.size() );
			if( mPrevAlphaChar != mAlphaChar || closeWheel ){
				mCallbacksAlphaCharSelected.call( this );
			}
		}

		if( closeWheel && distToCenter < maxDiam ){
            setShowWheel(false);
		}

        return distToCenter > minDiam && distToCenter < maxDiam;
	}
    return false;
}

void AlphaWheel::setTimePinchEnded( float timePinchEnded )
{
	mTimePinchEnded = timePinchEnded;
}

void AlphaWheel::update( )
{
	if( getShowWheel() ){
		mWheelScale -= ( mWheelScale - 0.0f ) * 0.2f;
	} else {
		mWheelScale -= ( mWheelScale - 1.15f ) * 0.2f;
	}

    Vec2f interfaceSize = mRoot->getInterfaceSize();

    if (mInterfaceSize != interfaceSize) {
        mInterfaceSize = interfaceSize;
        mInterfaceCenter = mInterfaceSize * 0.5f;

        float prevRadius = mAlphaRadius;

        mAlphaRadius = 300.0f; // portrait

        if ( mInterfaceSize.x > mInterfaceSize.y ) {
            float amount = (mInterfaceSize.x - mInterfaceSize.y) / (1024-768);

            Matrix44f mat;
            mat.translate( Vec3f(0, -12.0f * amount, 0) );
            setTransform(mat);

            mAlphaRadius -= 30.0f * amount; // smaller for landscape to accomodate PlayControls/Settings
        }

        if (prevRadius != mAlphaRadius) {
            setRects();
            setVerts();
        }
    }
}

void AlphaWheel::setNumberAlphaPerChar( float *numberAlphaPerChar )
{
    mNumberAlphaPerChar = numberAlphaPerChar;
}

void AlphaWheel::draw()
{
	if( mWheelScale < 0.95f ){

		glPushMatrix();

		gl::color( Color::white() );
		gl::translate( mInterfaceCenter );
		gl::scale( Vec3f( mWheelScale + 1.0f, mWheelScale + 1.0f, 1.0f ) );
		drawWheel();

		for( int i=0; i<27; i++ ){
			float c = mNumberAlphaPerChar[i];
			if( c > 0.0f ){
				c += 0.3f;
				gl::color( Color( c, c, c ) );
			} else {
				gl::color( Color( 0.5f, 0, 0 ) );
			}
			mAlphaTextures[i].enableAndBind();
            // TODO: batch these rects (adapt bloom::gl::batchRect for color tints?)
			gl::drawSolidRect( mAlphaRects[i] );
			mAlphaTextures[i].disable();
		}

		glPopMatrix();
	}
}

void AlphaWheel::drawWheel()
{
	mWheelTex.enableAndBind();
	glEnableClientState( GL_VERTEX_ARRAY );
	glEnableClientState( GL_TEXTURE_COORD_ARRAY );

	glVertexPointer( 2, GL_FLOAT, sizeof(VertexData), mVerts );
	glTexCoordPointer( 2, GL_FLOAT, sizeof(VertexData), &mVerts[0].texture );

	glDrawArrays( GL_TRIANGLES, 0, mTotalVertices );

	glDisableClientState( GL_VERTEX_ARRAY );
	glDisableClientState( GL_TEXTURE_COORD_ARRAY );
	mWheelTex.disable();
}

void AlphaWheel::drawAlphaChar()
{
	//std::cout << "AlphaWheel::drawAlphaChar mAlphaIndex = " << mAlphaIndex << std::endl;
	float w = mAlphaTextures[mAlphaIndex].getWidth() * 0.5f;
	float h = mAlphaTextures[mAlphaIndex].getHeight() * 0.5f;

	gl::color( ColorA( BLUE, 1.0f - mWheelScale ) );

	gl::enableAdditiveBlending();
    mAlphaTextures[mAlphaIndex].enableAndBind();
	gl::drawSolidRect( Rectf( -w, -h, w, h ) );
	mAlphaTextures[mAlphaIndex].disable();
	gl::enableAlphaBlending();
}

void AlphaWheel::setShowWheel( bool b ){
    mShowWheel = b;
    mCallbacksWheelToggled.call(this);
}

<commit_msg>fix alphawheel background size for orientations<commit_after>/*
 *  AlphaWheel.cpp
 *  Kepler
 *
 *  Created by Tom Carden on 3/14/11.
 *  Copyright 2011 __MyCompanyName__. All rights reserved.
 *
 */

#include "AlphaWheel.h"
#include "cinder/gl/gl.h"
#include "cinder/Font.h"
#include "cinder/Text.h"
#include "cinder/ImageIo.h"
#include "Globals.h"
#include "BloomGl.h"
#include "UIController.h"
#include "cinder/app/AppCocoaTouch.h" // for loadResource, getElapsedSeconds
#include "cinder/Utilities.h" // for toString
#include <sstream>

using namespace ci;
using namespace ci::app;
using namespace std;

void AlphaWheel::setup( const Font &font )
{
	// Textures
	mWheelTex		= gl::Texture( loadImage( loadResource( "alphaWheelMask.png" ) ) );

	mAlphaString	= "ABCDEFGHIJKLMNOPQRSTUVWXYZ#";
	mAlphaIndex		= 0;
	mAlphaChar		= ' ';
	mPrevAlphaChar	= ' ';
	mShowWheel		= false;
	mWheelScale		= 1.0f;

	initAlphaTextures( font );

//    mInterfaceSize = mRoot->getInterfaceSize();
//
//    mInterfaceCenter = mInterfaceSize * 0.5f;
//
//	setRects();
}

void AlphaWheel::initAlphaTextures( const Font &font )
{
	for( int i=0; i<mAlphaString.length(); i++ ){
//		float per = (float)i/27.0f;
//		float angle = per * TWO_PI - M_PI_2;
		TextLayout layout;
		layout.setFont( font );
		layout.setColor( ColorA( BRIGHT_BLUE, 1.0f ) );
		layout.addCenteredLine( ci::toString(mAlphaString[i]) );
		mAlphaTextures.push_back( gl::Texture( layout.render( true, false ) ) );

        // setRects()
//		float w = mAlphaTextures[i].getWidth()/2.0f;
//		float h = mAlphaTextures[i].getHeight()/2.0f;
//		Vec2f pos = Vec2f( cos( angle ), sin( angle ) ) * mAlphaRadius;
//		Rectf r = Rectf( pos.x - w, pos.y - h, pos.x + w, pos.y + h );
//		mAlphaRects.push_back( r );
	}
}

void AlphaWheel::setRects()
{
	mAlphaRects.clear();
	for( int i=0; i<mAlphaString.length(); i++ ){
		float per = (float)i/27.0f;
		float angle = per * TWO_PI - M_PI_2;
		float w = mAlphaTextures[i].getWidth()/2.0f;
		float h = mAlphaTextures[i].getHeight()/2.0f;
		Vec2f pos = Vec2f( cos( angle ), sin( angle ) ) * mAlphaRadius;
		Rectf r = Rectf( pos.x - w, pos.y - h, pos.x + w, pos.y + h );
		mAlphaRects.push_back( r );
	}
}

void AlphaWheel::setVerts()
{
	mTotalVertices = 54;
	delete[] mVerts;
	mVerts = NULL;
	mVerts = new VertexData[mTotalVertices];

	float W	= 1536; // square to avoid glimpses behind the curtain
	float H = 1536;
	float CW = W/2;
	float CH = H/2;
	float L = ( W - mAlphaRadius * 2.0f ) / 2.0f;
	float T = ( H - mAlphaRadius * 2.0f ) / 2.0f;
	float R = L + mAlphaRadius * 2.0f;
	float B = T + mAlphaRadius * 2.0f;

	vector<Vec2i> positions;
	positions.push_back( Vec2i( 0 - CW, 0 - CH ) );
	positions.push_back( Vec2i( L - CW, 0 - CH ) );
	positions.push_back( Vec2i( R - CW, 0 - CH ) );
	positions.push_back( Vec2i( W - CW, 0 - CH ) );

	positions.push_back( Vec2i( 0 - CW, T - CH ) );
	positions.push_back( Vec2i( L - CW, T - CH ) );
	positions.push_back( Vec2i( R - CW, T - CH ) );
	positions.push_back( Vec2i( W - CW, T - CH ) );

	positions.push_back( Vec2i( 0 - CW, B - CH ) );
	positions.push_back( Vec2i( L - CW, B - CH ) );
	positions.push_back( Vec2i( R - CW, B - CH ) );
	positions.push_back( Vec2i( W - CW, B - CH ) );

	positions.push_back( Vec2i( 0 - CW, H - CH ) );
	positions.push_back( Vec2i( L - CW, H - CH ) );
	positions.push_back( Vec2i( R - CW, H - CH ) );
	positions.push_back( Vec2i( W - CW, H - CH ) );

	vector<Vec2f> textures;
	textures.push_back( Vec2f( 0, 0 ) );
	textures.push_back( Vec2f( 0, 0 ) );
	textures.push_back( Vec2f( 1, 0 ) );
	textures.push_back( Vec2f( 1, 0 ) );

	textures.push_back( Vec2f( 0, 0 ) );
	textures.push_back( Vec2f( 0, 0 ) );
	textures.push_back( Vec2f( 1, 0 ) );
	textures.push_back( Vec2f( 1, 0 ) );

	textures.push_back( Vec2f( 0, 1 ) );
	textures.push_back( Vec2f( 0, 1 ) );
	textures.push_back( Vec2f( 1, 1 ) );
	textures.push_back( Vec2f( 1, 1 ) );

	textures.push_back( Vec2f( 0, 1 ) );
	textures.push_back( Vec2f( 0, 1 ) );
	textures.push_back( Vec2f( 1, 1 ) );
	textures.push_back( Vec2f( 1, 1 ) );

	int indices[54] = { 0, 1, 4,
					  1, 5, 4,
					  1, 2, 5,
					  2, 6, 5,
					  2, 3, 6,
					  3, 7, 6,
					  4, 5, 8,
					  5, 9, 8,
					  5, 6, 9,
					  6, 10, 9,
					  6, 7, 10,
					  7, 11, 10,
					  8, 9, 12,
					  9, 13, 12,
					  9, 10, 13,
					  10, 14, 13,
					  10, 11, 14,
					  11, 15, 14 };

	int vIndex = 0;
	for( int i=0; i<54; i++ ){
		mVerts[vIndex].vertex	= positions[indices[i]];
		mVerts[vIndex].texture	= textures[indices[i]];

		vIndex ++;
	}
}

bool AlphaWheel::touchBegan( TouchEvent::Touch touch )
{
    if (!mShowWheel) return false;

    if (selectWheelItem( touch.getPos(), false )) {
        // this means we'll follow the last touch that starts on a wheel item
        mLastTouchPos = touch.getPos();
        mActiveTouchId = touch.getId();
        return true;
    }

	return false;
}

bool AlphaWheel::touchMoved( TouchEvent::Touch touch )
{
    if (mShowWheel) {
        // only follow the last valid touch we received
        if (touch.getId() == mActiveTouchId) {
            mLastTouchPos = touch.getPos();
            return selectWheelItem( mLastTouchPos, false );
        }
    }
	return false;
}

bool AlphaWheel::touchEnded( TouchEvent::Touch touch )
{
    if (!mShowWheel) return false;

    mLastTouchPos = touch.getPos();
    return selectWheelItem( mLastTouchPos, true );
}

bool AlphaWheel::selectWheelItem( const Vec2f &pos, bool closeWheel )
{
	if( !mShowWheel ){
		return false;
	}
	float minDiam = mAlphaRadius - 25.0f;
	float maxDiam = mAlphaRadius + 25.0f;

	float timeSincePinchEnded = getElapsedSeconds() - mTimePinchEnded;
	if( mShowWheel && timeSincePinchEnded > 0.5f ){
        Vec2f dir = globalToLocal(pos) - mInterfaceCenter;
		float distToCenter = dir.length();
		if( distToCenter > minDiam && distToCenter < maxDiam ){
			float touchAngle	= atan2( dir.y, dir.x ) + M_PI;				// RANGE 0 -> TWO_PI
			float anglePer		= ( touchAngle + 0.11365f + M_PI*1.5f )/TWO_PI;
			mAlphaIndex			= (int)( anglePer * 27 )%27;
			mPrevAlphaChar		= mAlphaChar;
			mAlphaChar			= mAlphaString.at( mAlphaIndex % mAlphaString.size() );
			if( mPrevAlphaChar != mAlphaChar || closeWheel ){
				mCallbacksAlphaCharSelected.call( this );
			}
		}

		if( closeWheel && distToCenter < maxDiam ){
            setShowWheel(false);
		}

        return distToCenter > minDiam && distToCenter < maxDiam;
	}
    return false;
}

void AlphaWheel::setTimePinchEnded( float timePinchEnded )
{
	mTimePinchEnded = timePinchEnded;
}

void AlphaWheel::update( )
{
	if( getShowWheel() ){
		mWheelScale -= ( mWheelScale - 0.0f ) * 0.2f;
	} else {
		mWheelScale -= ( mWheelScale - 1.15f ) * 0.2f;
	}

    Vec2f interfaceSize = mRoot->getInterfaceSize();

    if (mInterfaceSize != interfaceSize) {
        mInterfaceSize = interfaceSize;
        mInterfaceCenter = mInterfaceSize * 0.5f;

        float prevRadius = mAlphaRadius;

        mAlphaRadius = 300.0f; // portrait

        if ( mInterfaceSize.x > mInterfaceSize.y ) {
            float amount = (mInterfaceSize.x - mInterfaceSize.y) / (1024-768);

            Matrix44f mat;
            mat.translate( Vec3f(0, -12.0f * amount, 0) );
            setTransform(mat);

            mAlphaRadius -= 30.0f * amount; // smaller for landscape to accomodate PlayControls/Settings
        }

        if (prevRadius != mAlphaRadius) {
            setRects();
            setVerts();
        }
    }
}

void AlphaWheel::setNumberAlphaPerChar( float *numberAlphaPerChar )
{
    mNumberAlphaPerChar = numberAlphaPerChar;
}

void AlphaWheel::draw()
{
	if( mWheelScale < 0.95f ){

		glPushMatrix();

		gl::color( Color::white() );
		gl::translate( mInterfaceCenter );
		gl::scale( Vec3f( mWheelScale + 1.0f, mWheelScale + 1.0f, 1.0f ) );
		drawWheel();

		for( int i=0; i<27; i++ ){
			float c = mNumberAlphaPerChar[i];
			if( c > 0.0f ){
				c += 0.3f;
				gl::color( Color( c, c, c ) );
			} else {
				gl::color( Color( 0.5f, 0, 0 ) );
			}
			mAlphaTextures[i].enableAndBind();
            // TODO: batch these rects (adapt bloom::gl::batchRect for color tints?)
			gl::drawSolidRect( mAlphaRects[i] );
			mAlphaTextures[i].disable();
		}

		glPopMatrix();
	}
}

void AlphaWheel::drawWheel()
{
	mWheelTex.enableAndBind();
	glEnableClientState( GL_VERTEX_ARRAY );
	glEnableClientState( GL_TEXTURE_COORD_ARRAY );

	glVertexPointer( 2, GL_FLOAT, sizeof(VertexData), mVerts );
	glTexCoordPointer( 2, GL_FLOAT, sizeof(VertexData), &mVerts[0].texture );

	glDrawArrays( GL_TRIANGLES, 0, mTotalVertices );

	glDisableClientState( GL_VERTEX_ARRAY );
	glDisableClientState( GL_TEXTURE_COORD_ARRAY );
	mWheelTex.disable();
}

void AlphaWheel::drawAlphaChar()
{
	//std::cout << "AlphaWheel::drawAlphaChar mAlphaIndex = " << mAlphaIndex << std::endl;
	float w = mAlphaTextures[mAlphaIndex].getWidth() * 0.5f;
	float h = mAlphaTextures[mAlphaIndex].getHeight() * 0.5f;

	gl::color( ColorA( BLUE, 1.0f - mWheelScale ) );

	gl::enableAdditiveBlending();
    mAlphaTextures[mAlphaIndex].enableAndBind();
	gl::drawSolidRect( Rectf( -w, -h, w, h ) );
	mAlphaTextures[mAlphaIndex].disable();
	gl::enableAlphaBlending();
}

void AlphaWheel::setShowWheel( bool b ){
    mShowWheel = b;
    mCallbacksWheelToggled.call(this);
}

<|endoftext|>


<commit_before>#include "Atm_player.hpp"

/* Add optional parameters for the state machine to begin()
 * Add extra initialization code
 */

Atm_player& Atm_player::begin( int pin /* = - 1 */ ) {
  // clang-format off
  const static state_t state_table[] PROGMEM = {
    /*             ON_ENTER    ON_LOOP  ON_EXIT  EVT_START  EVT_STOP  EVT_TOGGLE  EVT_TIMER  EVT_EOPAT  EVT_REPEAT   ELSE */
    /*   IDLE */   ENT_IDLE, ATM_SLEEP,      -1,     START,       -1,      START,        -1,        -1,         -1,    -1,
    /*  START */  ENT_START,        -1,      -1,        -1,       -1,         -1,        -1,        -1,         -1, SOUND,
    /*  SOUND */  ENT_SOUND,        -1,      -1,        -1,     IDLE,       IDLE,     QUIET,        -1,         -1,    -1,
    /*  QUIET */  ENT_QUIET,        -1,      -1,        -1,     IDLE,       IDLE,      NEXT,        -1,         -1,    -1,
    /*   NEXT */   ENT_NEXT,        -1,      -1,        -1,     IDLE,       IDLE,        -1,    REPEAT,         -1, SOUND,
    /* REPEAT */ ENT_REPEAT,        -1,      -1,        -1,     IDLE,       IDLE,        -1,        -1,     FINISH, START,
    /* FINISH */ ENT_FINISH,        -1,      -1,        -1,     IDLE,         -1,        -1,        -1,       IDLE, START,
  };
  // clang-format on
  Machine::begin( state_table, ELSE );
  Atm_player::pin = pin;
  speed( 100 );
  pitch( 100 );
  repeat( 1 );
  play( 880, 50 );
  return *this;
}

/* Add C++ code for each event (input)
 * The code must return 1 if the event should be triggered
 */

int Atm_player::event( int id ) {
  switch ( id ) {
    case EVT_START:
      return 0;
    case EVT_TIMER:
      return timer.expired( this );
    case EVT_EOPAT:
      if ( patternwidth == 32 ) {
        return ( step * 3 * sizeof( uint32_t ) ) >= patternsize;
      } else {
        return ( step * 3 * sizeof( int ) ) >= patternsize;
      }
    case EVT_REPEAT:
      return counter_repeat.expired();
  }
  return 0;
}

/* Add C++ code for each action
 * This generates the 'output' for the state machine
 */

void Atm_player::action( int id ) {
  switch ( id ) {
    case ENT_FINISH:
      push( connectors, ON_FINISH, 0, 0, 0 );
      return;
    case ENT_IDLE:
      if ( pin >= 0 ) noTone( pin );  // Tone takes up 7 bytes extra SRAM
      counter_repeat.set( repeatCount );
      return;
    case ENT_START:
      step = 0;
      counter_repeat.decrement();
      return;
    case ENT_SOUND:
      if ( patternwidth == 32 ) {
        uint32_t v = pattern32[step * 3] * (uint32_t)pitchFactor;
        push( connectors, ON_NOTE, true, v & 0xFFFF, v >> 16 & 0xFFFF );
        if ( pin >= 0 ) tone( pin, pattern32[step * 3] * pitchFactor );
        timer.set( pattern32[step * 3 + 1] * speedFactor );
      } else {
        push( connectors, ON_NOTE, true, pattern16[step * 3] * pitchFactor, 1 );
        if ( pin >= 0 ) tone( pin, pattern16[step * 3] * pitchFactor );
        timer.set( pattern16[step * 3 + 1] * speedFactor );
      }
      return;
    case ENT_QUIET:
      if ( patternwidth == 32 ) {
        uint32_t v = pattern32[step * 3] * (uint32_t)pitchFactor;
        push( connectors, ON_NOTE, false, v & 0xFFFF, v >> 16 & 0xFFFF );
        if ( pin >= 0 ) noTone( pin );
        timer.set( pattern32[step * 3 + 2] * speedFactor );
      } else {
        push( connectors, ON_NOTE, false, pattern16[step * 3] * pitchFactor, 0 );
        if ( pin >= 0 ) noTone( pin );
        timer.set( pattern16[step * 3 + 2] * speedFactor );
      }
      return;
    case ENT_NEXT:
      step++;
      return;
    case ENT_REPEAT:
      return;
  }
}

/* How many times to repeat the pattern
 *
 */

Atm_player& Atm_player::repeat( uint16_t v /* = -1 */) {
  counter_repeat.set( repeatCount = v );
  return *this;
}

Atm_player& Atm_player::speed( float v ) {
  speedFactor = 100 / v;
  return *this;
}

Atm_player& Atm_player::pitch( float v ) {
  pitchFactor = v / 100;
  return *this;
}

Atm_player& Atm_player::start( void ) {
  trigger( EVT_START );
  return *this;
}

Atm_player& Atm_player::stop( void ) {
  trigger( EVT_STOP );
  return *this;
}

Atm_player& Atm_player::toggle( void ) {
  trigger( EVT_TOGGLE );
  return *this;
}

/* Sets the pattern and pattern length (in bytes)
 *
 */

Atm_player& Atm_player::play( int* pat, int patsize ) {
  patternwidth = 16;
  pattern16 = pat;
  patternsize = patsize;
  counter_repeat.set( repeatCount );
  step = 0;
  return *this;
}

Atm_player& Atm_player::play( uint32_t* pat, int patsize ) {
  patternwidth = 32;
  pattern32 = pat;
  patternsize = patsize;
  counter_repeat.set( repeatCount );
  step = 0;
  return *this;
}

Atm_player& Atm_player::play( int freq, int period, int pause /* = 0 */ ) {
  patternwidth = 16;
  stub[0] = freq;
  stub[1] = period;
  stub[2] = pause;
  pattern16 = stub;
  patternsize = 3 * sizeof( int );
  step = 0;
  return *this;
}

/* Optionally override the default trigger() method
 * Control what triggers your machine can and cannot process
 */

Atm_player& Atm_player::trigger( int event ) {
  Machine::trigger( event );
  return *this;
}

/* Optionally override the default state() method
 * Control what the machine returns when another process requests its state()
 */

int Atm_player::state( void ) {
  return Machine::state();
}

/* Nothing customizable below this line
 ************************************************************************************************
*/

/* onFinish() push connector variants ( slots 1, autostore 0, broadcast 0 )
 *
 * Usage in action() handler: push( connectors, ON_FINISH, 0, v, up)
 */

Atm_player& Atm_player::onFinish( Machine& machine, int event ) {
  onPush( connectors, ON_FINISH, 0, 1, 1, machine, event );
  return *this;
}
Atm_player& Atm_player::onFinish( atm_cb_push_t callback, int idx ) {
  onPush( connectors, ON_FINISH, 0, 1, 1, callback, idx );
  return *this;
}

/* onNote() push connector variants ( slots 2, autostore 0, broadcast 0 )
 *
 * Usage in action() handler: push( connectors, ON_NOTE, sub, v, up)
 */

Atm_player& Atm_player::onNote( Machine& machine, int event ) {
  onPush( connectors, ON_NOTE, 0, 2, 1, machine, event );
  return *this;
}
Atm_player& Atm_player::onNote( atm_cb_push_t callback, int idx ) {
  onPush( connectors, ON_NOTE, 0, 2, 1, callback, idx );
  return *this;
}
Atm_player& Atm_player::onNote( int sub, Machine& machine, int event ) {
  onPush( connectors, ON_NOTE, sub, 2, 0, machine, event );
  return *this;
}
Atm_player& Atm_player::onNote( int sub, atm_cb_push_t callback, int idx ) {
  onPush( connectors, ON_NOTE, sub, 2, 0, callback, idx );
  return *this;
}

/* State trace method
 * Sets the symbol table and the default logging method for serial monitoring
 */

Atm_player& Atm_player::trace( Stream& stream ) {
  Machine::setTrace( &stream, atm_serial_debug::trace,
                     "PLAYER\0EVT_START\0EVT_STOP\0EVT_TOGGLE\0EVT_TIMER\0EVT_EOPAT\0EVT_REPEAT\0ELSE\0IDLE\0START\0SOUND\0QUIET\0NEXT\0REPEAT\0FINISH" );
  return *this;
}
<commit_msg>Tone disabled for Arduino Due (Issue #41 )<commit_after>#include "Atm_player.hpp"

/* Add optional parameters for the state machine to begin()
 * Add extra initialization code
 */

Atm_player& Atm_player::begin( int pin /* = - 1 */ ) {
  // clang-format off
  const static state_t state_table[] PROGMEM = {
    /*             ON_ENTER    ON_LOOP  ON_EXIT  EVT_START  EVT_STOP  EVT_TOGGLE  EVT_TIMER  EVT_EOPAT  EVT_REPEAT   ELSE */
    /*   IDLE */   ENT_IDLE, ATM_SLEEP,      -1,     START,       -1,      START,        -1,        -1,         -1,    -1,
    /*  START */  ENT_START,        -1,      -1,        -1,       -1,         -1,        -1,        -1,         -1, SOUND,
    /*  SOUND */  ENT_SOUND,        -1,      -1,        -1,     IDLE,       IDLE,     QUIET,        -1,         -1,    -1,
    /*  QUIET */  ENT_QUIET,        -1,      -1,        -1,     IDLE,       IDLE,      NEXT,        -1,         -1,    -1,
    /*   NEXT */   ENT_NEXT,        -1,      -1,        -1,     IDLE,       IDLE,        -1,    REPEAT,         -1, SOUND,
    /* REPEAT */ ENT_REPEAT,        -1,      -1,        -1,     IDLE,       IDLE,        -1,        -1,     FINISH, START,
    /* FINISH */ ENT_FINISH,        -1,      -1,        -1,     IDLE,         -1,        -1,        -1,       IDLE, START,
  };
  // clang-format on
  Machine::begin( state_table, ELSE );
  Atm_player::pin = pin;
  speed( 100 );
  pitch( 100 );
  repeat( 1 );
  play( 880, 50 );
  return *this;
}

/* Add C++ code for each event (input)
 * The code must return 1 if the event should be triggered
 */

int Atm_player::event( int id ) {
  switch ( id ) {
    case EVT_START:
      return 0;
    case EVT_TIMER:
      return timer.expired( this );
    case EVT_EOPAT:
      if ( patternwidth == 32 ) {
        return ( step * 3 * sizeof( uint32_t ) ) >= patternsize;
      } else {
        return ( step * 3 * sizeof( int ) ) >= patternsize;
      }
    case EVT_REPEAT:
      return counter_repeat.expired();
  }
  return 0;
}

/* Add C++ code for each action
 * This generates the 'output' for the state machine
 */

void Atm_player::action( int id ) {
  switch ( id ) {
    case ENT_FINISH:
      push( connectors, ON_FINISH, 0, 0, 0 );
      return;
    case ENT_IDLE:
#ifdef _VARIANT_ARDUINO_DUE_X_
      if ( pin >= 0 ) noTone( pin );  // Tone takes up 7 bytes extra SRAM
#endif
      counter_repeat.set( repeatCount );
      return;
    case ENT_START:
      step = 0;
      counter_repeat.decrement();
      return;
    case ENT_SOUND:
      if ( patternwidth == 32 ) {
        uint32_t v = pattern32[step * 3] * (uint32_t)pitchFactor;
        push( connectors, ON_NOTE, true, v & 0xFFFF, v >> 16 & 0xFFFF );
#ifdef _VARIANT_ARDUINO_DUE_X_
        if ( pin >= 0 ) tone( pin, pattern32[step * 3] * pitchFactor );
#endif
        timer.set( pattern32[step * 3 + 1] * speedFactor );
      } else {
        push( connectors, ON_NOTE, true, pattern16[step * 3] * pitchFactor, 1 );
#ifdef _VARIANT_ARDUINO_DUE_X_
        if ( pin >= 0 ) tone( pin, pattern16[step * 3] * pitchFactor );
#endif
        timer.set( pattern16[step * 3 + 1] * speedFactor );
      }
      return;
    case ENT_QUIET:
      if ( patternwidth == 32 ) {
        uint32_t v = pattern32[step * 3] * (uint32_t)pitchFactor;
        push( connectors, ON_NOTE, false, v & 0xFFFF, v >> 16 & 0xFFFF );
#ifdef _VARIANT_ARDUINO_DUE_X_
        if ( pin >= 0 ) noTone( pin );
#endif
        timer.set( pattern32[step * 3 + 2] * speedFactor );
      } else {
        push( connectors, ON_NOTE, false, pattern16[step * 3] * pitchFactor, 0 );
#ifdef _VARIANT_ARDUINO_DUE_X_
        if ( pin >= 0 ) noTone( pin );
#endif
        timer.set( pattern16[step * 3 + 2] * speedFactor );
      }
      return;
    case ENT_NEXT:
      step++;
      return;
    case ENT_REPEAT:
      return;
  }
}

/* How many times to repeat the pattern
 *
 */

Atm_player& Atm_player::repeat( uint16_t v /* = -1 */) {
  counter_repeat.set( repeatCount = v );
  return *this;
}

Atm_player& Atm_player::speed( float v ) {
  speedFactor = 100 / v;
  return *this;
}

Atm_player& Atm_player::pitch( float v ) {
  pitchFactor = v / 100;
  return *this;
}

Atm_player& Atm_player::start( void ) {
  trigger( EVT_START );
  return *this;
}

Atm_player& Atm_player::stop( void ) {
  trigger( EVT_STOP );
  return *this;
}

Atm_player& Atm_player::toggle( void ) {
  trigger( EVT_TOGGLE );
  return *this;
}

/* Sets the pattern and pattern length (in bytes)
 *
 */

Atm_player& Atm_player::play( int* pat, int patsize ) {
  patternwidth = 16;
  pattern16 = pat;
  patternsize = patsize;
  counter_repeat.set( repeatCount );
  step = 0;
  return *this;
}

Atm_player& Atm_player::play( uint32_t* pat, int patsize ) {
  patternwidth = 32;
  pattern32 = pat;
  patternsize = patsize;
  counter_repeat.set( repeatCount );
  step = 0;
  return *this;
}

Atm_player& Atm_player::play( int freq, int period, int pause /* = 0 */ ) {
  patternwidth = 16;
  stub[0] = freq;
  stub[1] = period;
  stub[2] = pause;
  pattern16 = stub;
  patternsize = 3 * sizeof( int );
  step = 0;
  return *this;
}

/* Optionally override the default trigger() method
 * Control what triggers your machine can and cannot process
 */

Atm_player& Atm_player::trigger( int event ) {
  Machine::trigger( event );
  return *this;
}

/* Optionally override the default state() method
 * Control what the machine returns when another process requests its state()
 */

int Atm_player::state( void ) {
  return Machine::state();
}

/* Nothing customizable below this line
 ************************************************************************************************
*/

/* onFinish() push connector variants ( slots 1, autostore 0, broadcast 0 )
 *
 * Usage in action() handler: push( connectors, ON_FINISH, 0, v, up)
 */

Atm_player& Atm_player::onFinish( Machine& machine, int event ) {
  onPush( connectors, ON_FINISH, 0, 1, 1, machine, event );
  return *this;
}
Atm_player& Atm_player::onFinish( atm_cb_push_t callback, int idx ) {
  onPush( connectors, ON_FINISH, 0, 1, 1, callback, idx );
  return *this;
}

/* onNote() push connector variants ( slots 2, autostore 0, broadcast 0 )
 *
 * Usage in action() handler: push( connectors, ON_NOTE, sub, v, up)
 */

Atm_player& Atm_player::onNote( Machine& machine, int event ) {
  onPush( connectors, ON_NOTE, 0, 2, 1, machine, event );
  return *this;
}
Atm_player& Atm_player::onNote( atm_cb_push_t callback, int idx ) {
  onPush( connectors, ON_NOTE, 0, 2, 1, callback, idx );
  return *this;
}
Atm_player& Atm_player::onNote( int sub, Machine& machine, int event ) {
  onPush( connectors, ON_NOTE, sub, 2, 0, machine, event );
  return *this;
}
Atm_player& Atm_player::onNote( int sub, atm_cb_push_t callback, int idx ) {
  onPush( connectors, ON_NOTE, sub, 2, 0, callback, idx );
  return *this;
}

/* State trace method
 * Sets the symbol table and the default logging method for serial monitoring
 */

Atm_player& Atm_player::trace( Stream& stream ) {
  Machine::setTrace( &stream, atm_serial_debug::trace,
                     "PLAYER\0EVT_START\0EVT_STOP\0EVT_TOGGLE\0EVT_TIMER\0EVT_EOPAT\0EVT_REPEAT\0ELSE\0IDLE\0START\0SOUND\0QUIET\0NEXT\0REPEAT\0FINISH" );
  return *this;
}
<|endoftext|>