<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// QUESO - a library to support the Quantification of Uncertainty
// for Estimation, Simulation and Optimization
//
// Copyright (C) 2008,2009,2010,2011,2012,2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

#include <iostream>

#include <gsl/gsl_multimin.h>
#include <queso/GslVector.h>
#include <queso/VectorSpace.h>
#include <queso/ScalarFunction.h>
#include <queso/GslOptimizer.h>

namespace QUESO {

// We need to extern "C" because gsl needs a pointer to a C function to
// minimize
extern "C" {
  // This evaluate -log posterior
  double c_evaluate(const gsl_vector * x, void * context) {

    GslOptimizer * optimizer = static_cast<GslOptimizer * >(context);

    GslVector state(
        optimizer->objectiveFunction().domainSet().vectorSpace().zeroVector());

    // DM: Doing this copy sucks, but whatever.  It'll do for now.
    for (unsigned int i = 0; i < state.sizeLocal(); i++) {
      state[i] = gsl_vector_get(x, i);
    }

    // Bail early if GSL tries to evaluate outside of the domain
    if (!optimizer->objectiveFunction().domainSet().contains(state)) {
      return GSL_NAN;
    }

    // Should cache derivative here so we don't a) segfault in the user's code
    // and b) so we don't recompute stuff
    double result = -optimizer->objectiveFunction().lnValue(state, NULL, NULL,
        NULL, NULL);

    return result;
  }

  // This evaluates the derivative of -log posterior
  void c_evaluate_derivative(const gsl_vector * x, void * context,
      gsl_vector * derivative) {
    GslOptimizer * optimizer = static_cast<GslOptimizer * >(context);

    GslVector state(
        optimizer->objectiveFunction().domainSet().vectorSpace().zeroVector());
    GslVector deriv(
        optimizer->objectiveFunction().domainSet().vectorSpace().zeroVector());

    // DM: Doing this copy sucks, but whatever.  It'll do for now.
    for (unsigned int i = 0; i < state.sizeLocal(); i++) {
      state[i] = gsl_vector_get(x, i);

      // We fill with GSL_NAN and use it as a flag to check later that the user
      // actually fills the derivative vector with stuff
      deriv[i] = GSL_NAN;
    }

    if (!optimizer->objectiveFunction().domainSet().contains(state)) {
      // Fill derivative with error codes if the point is outside of the
      // domain
      for (unsigned int i = 0; i < deriv.sizeLocal(); i++) {
        gsl_vector_set(derivative, i, GSL_NAN);
      }
    }
    else {
      // We should cache the return value here so we don't recompute stuff
      double fx = -optimizer->objectiveFunction().lnValue(state, NULL, &deriv,
          NULL, NULL);

      // Decide whether or not we need to do a finite difference based on
      // whether the user actually filled deriv with values that are not
      // GSL_NAN
      //
      // We're currently doing this check every time this function gets called.
      // We could probably pull this logic out of here and put it somewhere
      // where it only happens once
      bool userComputedDerivative = true;
      for (unsigned int i = 0; i < deriv.sizeLocal(); i++) {
        // If the user missed out a derivative in any direction, fall back to
        // a finite difference
        if (gsl_isnan(deriv[i])) {
          userComputedDerivative = false;
          break;
        }
      }

      if (userComputedDerivative) {
        for (unsigned int i = 0; i < deriv.sizeLocal(); i++) {
          gsl_vector_set(derivative, i, -deriv[i]);  // We need the minus sign
        }
      }
      else {
        // Finite difference step-size
        double h = optimizer->getFiniteDifferenceStepSize();

        // User did not provide a derivative, so do a finite difference
        for (unsigned int i = 0; i < deriv.sizeLocal(); i++) {
          double tempState = state[i];
          state[i] += h;

          // User didn't provide a derivative, so we don't bother passing in
          // the derivative vector again
          double fxph = -optimizer->objectiveFunction().lnValue(state, NULL,
              NULL, NULL, NULL);

          // Reset the state back to what it was before
          state[i] = tempState;

          // Make sure we didn't do anything dumb and tell gsl if we did
          if (!gsl_isnan(fx) && !gsl_isnan(fxph)) {
            gsl_vector_set(derivative, i, (fxph - fx) / h);
          }
          else {
            gsl_vector_set(derivative, i, GSL_NAN);
          }
        }
      }
    }
  }

  // This evaluates -log posterior and the derivative of -log posterior
  void c_evaluate_with_derivative(const gsl_vector * x, void * context,
      double * f, gsl_vector * derivative) {
    // We don't need to call both of these
    *f = c_evaluate(x, context);
    c_evaluate_derivative(x, context, derivative);
  }
}  // End extern "C"

GslOptimizer::GslOptimizer(
    const BaseScalarFunction<GslVector, GslMatrix> & objectiveFunction)
  : BaseOptimizer(),
    m_objectiveFunction(objectiveFunction),
    m_initialPoint(new GslVector(objectiveFunction.domainSet().
          vectorSpace().zeroVector())),
    m_minimizer(new GslVector(this->m_objectiveFunction.domainSet().
        vectorSpace().zeroVector())),
    m_solver_type(BFGS2),
    m_step_size(this->m_objectiveFunction.domainSet().vectorSpace().zeroVector())
{
  // We initialize the minimizer to GSL_NAN just in case the optimization fails
  for (unsigned int i = 0; i < this->m_minimizer->sizeLocal(); i++) {
    (*(this->m_minimizer))[i] = GSL_NAN;
  }

  // Set to documented default value.
  m_step_size.cwSet(0.1);
}

GslOptimizer::~GslOptimizer()
{
  delete this->m_initialPoint;
}

void GslOptimizer::minimize() {

  // First check that initial guess is reasonable
  if (!this->m_objectiveFunction.domainSet().contains(*(this->m_initialPoint)))
    {
      if( m_objectiveFunction.domainSet().env().fullRank() == 0 )
        {
          std::cerr << "Minimization was given initial point outside of domain"
                    << std::endl;
        }
      queso_error();
    }

  unsigned int dim = this->m_objectiveFunction.domainSet().vectorSpace().
    zeroVector().sizeLocal();

  if( this->solver_needs_gradient(m_solver_type) )
    {
      this->minimize_with_gradient( dim );
    }
  else
    {
      this->minimize_no_gradient( dim );
    }

  return;
}

const BaseScalarFunction<GslVector, GslMatrix> &
GslOptimizer::objectiveFunction() const
{
  return this->m_objectiveFunction;
}

void
GslOptimizer::setInitialPoint(const GslVector & initialPoint)
{
  for (unsigned int i = 0; i < initialPoint.sizeLocal(); i++) {
    (*(this->m_initialPoint))[i] = initialPoint[i];
  }
}

const GslVector &
GslOptimizer::minimizer() const
{
  return *(this->m_minimizer);
}

  void GslOptimizer::set_solver_type( SolverType solver )
  {
    m_solver_type = solver;
  }

  bool GslOptimizer::solver_needs_gradient( SolverType solver )
  {
    bool gradient_needed = false;

    switch(solver)
      {
      case(FLETCHER_REEVES_CG):
      case(POLAK_RIBIERE_CG):
      case(BFGS):
      case(BFGS2):
      case(STEEPEST_DECENT):
        {
          gradient_needed = true;
          break;
        }
      case(NELDER_MEAD):
      case(NELDER_MEAD2):
      case(NELDER_MEAD2_RAND):
        {
          break;
        }
      default:
        {
          // Wat?!
          queso_error();
        }
      } // switch(solver)

    return gradient_needed;
  }

  void GslOptimizer::minimize_with_gradient( unsigned int dim )
  {
    // Set initial point
    gsl_vector * x = gsl_vector_alloc(dim);
    for (unsigned int i = 0; i < dim; i++) {
      gsl_vector_set(x, i, (*m_initialPoint)[i]);
    }

    // Tell GSL which solver we're using
    const gsl_multimin_fdfminimizer_type* type = NULL;

    switch(m_solver_type)
      {
      case(FLETCHER_REEVES_CG):
        type = gsl_multimin_fdfminimizer_conjugate_fr;
        break;
      case(POLAK_RIBIERE_CG):
        type = gsl_multimin_fdfminimizer_conjugate_pr;
        break;
      case(BFGS):
        type = gsl_multimin_fdfminimizer_vector_bfgs;
        break;
      case(BFGS2):
        type = gsl_multimin_fdfminimizer_vector_bfgs2;
        break;
      case(STEEPEST_DECENT):
        type = gsl_multimin_fdfminimizer_steepest_descent;
        break;
      case(NELDER_MEAD):
      case(NELDER_MEAD2):
      case(NELDER_MEAD2_RAND):
      default:
        // Wat?!
        queso_error();
      }

    // Init solver
    gsl_multimin_fdfminimizer * solver =
      gsl_multimin_fdfminimizer_alloc(type, dim);

    // Point GSL to the right functions
    gsl_multimin_function_fdf minusLogPosterior;
    minusLogPosterior.n = dim;
    minusLogPosterior.f = &c_evaluate;
    minusLogPosterior.df = &c_evaluate_derivative;
    minusLogPosterior.fdf = &c_evaluate_with_derivative;
    minusLogPosterior.params = (void *)(this);

    /*!
     * \todo Allow the user to tweak these hard-coded values
     */
    gsl_multimin_fdfminimizer_set(solver, &minusLogPosterior, x, 0.01, 0.1);

    int status;
    size_t iter = 0;

    do {
      iter++;
      status = gsl_multimin_fdfminimizer_iterate(solver);

      if (status) {
        if( m_objectiveFunction.domainSet().env().fullRank() == 0 )
          {
            std::cerr << "Error while GSL does optimisation. "
                      << "See below for GSL error type." << std::endl;
            std::cerr << "Gsl error: " << gsl_strerror(status) << std::endl;
          }
        break;
      }

      status = gsl_multimin_test_gradient(solver->gradient, this->getTolerance());

    } while ((status == GSL_CONTINUE) && (iter < this->getMaxIterations()));

    for (unsigned int i = 0; i < dim; i++) {
      (*m_minimizer)[i] = gsl_vector_get(solver->x, i);
    }

    // We're being good human beings and cleaning up the memory we allocated
    gsl_multimin_fdfminimizer_free(solver);
    gsl_vector_free(x);

    return;
  }

  void GslOptimizer::minimize_no_gradient( unsigned int dim )
  {
    // Set initial point
    gsl_vector* x = gsl_vector_alloc(dim);
    for (unsigned int i = 0; i < dim; i++) {
      gsl_vector_set(x, i, (*m_initialPoint)[i]);
    }

    // Tell GSL which solver we're using
    const gsl_multimin_fminimizer_type* type = NULL;

    switch(m_solver_type)
      {
      case(NELDER_MEAD):
        type = gsl_multimin_fminimizer_nmsimplex;
        break;
      case(NELDER_MEAD2):
        type = gsl_multimin_fminimizer_nmsimplex2;
        break;
      case(NELDER_MEAD2_RAND):
        type = gsl_multimin_fminimizer_nmsimplex2rand;
        break;
      case(FLETCHER_REEVES_CG):
      case(POLAK_RIBIERE_CG):
      case(BFGS):
      case(BFGS2):
      case(STEEPEST_DECENT):
      default:
        // Wat?!
        queso_error();
      }

    // Init solver
    gsl_multimin_fminimizer* solver =
      gsl_multimin_fminimizer_alloc(type, dim);

    // Point GSL at the right functions
    gsl_multimin_function minusLogPosterior;
    minusLogPosterior.n = dim;
    minusLogPosterior.f = &c_evaluate;
    minusLogPosterior.params = (void *)(this);

    // Needed for these gradient free algorithms.
    gsl_vector* step_size = gsl_vector_alloc(dim);

    for(unsigned int i = 0; i < dim; i++) {
      gsl_vector_set(step_size, i, m_step_size[i]);
    }

    gsl_multimin_fminimizer_set(solver, &minusLogPosterior, x, step_size);

    int status;
    size_t iter = 0;
    double size = 0.0;

    do
      {
        iter++;
        status = gsl_multimin_fminimizer_iterate(solver);

        if (status) {
          if( m_objectiveFunction.domainSet().env().fullRank() == 0 )
            {
              std::cerr << "Error while GSL does optimisation. "
                        << "See below for GSL error type." << std::endl;
              std::cerr << "Gsl error: " << gsl_strerror(status) << std::endl;
            }
          break;
        }

        size = gsl_multimin_fminimizer_size(solver);

        /*! \todo Tolerance should be set by the user*/
        status = gsl_multimin_test_size (size, this->getTolerance());

      }
    /*! \todo max iterations should be set by the user */
    while ((status == GSL_CONTINUE) && (iter < this->getMaxIterations()));

    for (unsigned int i = 0; i < dim; i++) {
      (*m_minimizer)[i] = gsl_vector_get(solver->x, i);
    }

    // We're being good human beings and cleaning up the memory we allocated
    gsl_vector_free(step_size);
    gsl_multimin_fminimizer_free(solver);
    gsl_vector_free(x);

    return;
  }

  void GslOptimizer::set_step_size( const GslVector& step_size )
  {
    m_step_size = step_size;
  }

}  // End namespace QUESO
<commit_msg>Removing atavistic todo's<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// QUESO - a library to support the Quantification of Uncertainty
// for Estimation, Simulation and Optimization
//
// Copyright (C) 2008,2009,2010,2011,2012,2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

#include <iostream>

#include <gsl/gsl_multimin.h>
#include <queso/GslVector.h>
#include <queso/VectorSpace.h>
#include <queso/ScalarFunction.h>
#include <queso/GslOptimizer.h>

namespace QUESO {

// We need to extern "C" because gsl needs a pointer to a C function to
// minimize
extern "C" {
  // This evaluate -log posterior
  double c_evaluate(const gsl_vector * x, void * context) {

    GslOptimizer * optimizer = static_cast<GslOptimizer * >(context);

    GslVector state(
        optimizer->objectiveFunction().domainSet().vectorSpace().zeroVector());

    // DM: Doing this copy sucks, but whatever.  It'll do for now.
    for (unsigned int i = 0; i < state.sizeLocal(); i++) {
      state[i] = gsl_vector_get(x, i);
    }

    // Bail early if GSL tries to evaluate outside of the domain
    if (!optimizer->objectiveFunction().domainSet().contains(state)) {
      return GSL_NAN;
    }

    // Should cache derivative here so we don't a) segfault in the user's code
    // and b) so we don't recompute stuff
    double result = -optimizer->objectiveFunction().lnValue(state, NULL, NULL,
        NULL, NULL);

    return result;
  }

  // This evaluates the derivative of -log posterior
  void c_evaluate_derivative(const gsl_vector * x, void * context,
      gsl_vector * derivative) {
    GslOptimizer * optimizer = static_cast<GslOptimizer * >(context);

    GslVector state(
        optimizer->objectiveFunction().domainSet().vectorSpace().zeroVector());
    GslVector deriv(
        optimizer->objectiveFunction().domainSet().vectorSpace().zeroVector());

    // DM: Doing this copy sucks, but whatever.  It'll do for now.
    for (unsigned int i = 0; i < state.sizeLocal(); i++) {
      state[i] = gsl_vector_get(x, i);

      // We fill with GSL_NAN and use it as a flag to check later that the user
      // actually fills the derivative vector with stuff
      deriv[i] = GSL_NAN;
    }

    if (!optimizer->objectiveFunction().domainSet().contains(state)) {
      // Fill derivative with error codes if the point is outside of the
      // domain
      for (unsigned int i = 0; i < deriv.sizeLocal(); i++) {
        gsl_vector_set(derivative, i, GSL_NAN);
      }
    }
    else {
      // We should cache the return value here so we don't recompute stuff
      double fx = -optimizer->objectiveFunction().lnValue(state, NULL, &deriv,
          NULL, NULL);

      // Decide whether or not we need to do a finite difference based on
      // whether the user actually filled deriv with values that are not
      // GSL_NAN
      //
      // We're currently doing this check every time this function gets called.
      // We could probably pull this logic out of here and put it somewhere
      // where it only happens once
      bool userComputedDerivative = true;
      for (unsigned int i = 0; i < deriv.sizeLocal(); i++) {
        // If the user missed out a derivative in any direction, fall back to
        // a finite difference
        if (gsl_isnan(deriv[i])) {
          userComputedDerivative = false;
          break;
        }
      }

      if (userComputedDerivative) {
        for (unsigned int i = 0; i < deriv.sizeLocal(); i++) {
          gsl_vector_set(derivative, i, -deriv[i]);  // We need the minus sign
        }
      }
      else {
        // Finite difference step-size
        double h = optimizer->getFiniteDifferenceStepSize();

        // User did not provide a derivative, so do a finite difference
        for (unsigned int i = 0; i < deriv.sizeLocal(); i++) {
          double tempState = state[i];
          state[i] += h;

          // User didn't provide a derivative, so we don't bother passing in
          // the derivative vector again
          double fxph = -optimizer->objectiveFunction().lnValue(state, NULL,
              NULL, NULL, NULL);

          // Reset the state back to what it was before
          state[i] = tempState;

          // Make sure we didn't do anything dumb and tell gsl if we did
          if (!gsl_isnan(fx) && !gsl_isnan(fxph)) {
            gsl_vector_set(derivative, i, (fxph - fx) / h);
          }
          else {
            gsl_vector_set(derivative, i, GSL_NAN);
          }
        }
      }
    }
  }

  // This evaluates -log posterior and the derivative of -log posterior
  void c_evaluate_with_derivative(const gsl_vector * x, void * context,
      double * f, gsl_vector * derivative) {
    // We don't need to call both of these
    *f = c_evaluate(x, context);
    c_evaluate_derivative(x, context, derivative);
  }
}  // End extern "C"

GslOptimizer::GslOptimizer(
    const BaseScalarFunction<GslVector, GslMatrix> & objectiveFunction)
  : BaseOptimizer(),
    m_objectiveFunction(objectiveFunction),
    m_initialPoint(new GslVector(objectiveFunction.domainSet().
          vectorSpace().zeroVector())),
    m_minimizer(new GslVector(this->m_objectiveFunction.domainSet().
        vectorSpace().zeroVector())),
    m_solver_type(BFGS2),
    m_step_size(this->m_objectiveFunction.domainSet().vectorSpace().zeroVector())
{
  // We initialize the minimizer to GSL_NAN just in case the optimization fails
  for (unsigned int i = 0; i < this->m_minimizer->sizeLocal(); i++) {
    (*(this->m_minimizer))[i] = GSL_NAN;
  }

  // Set to documented default value.
  m_step_size.cwSet(0.1);
}

GslOptimizer::~GslOptimizer()
{
  delete this->m_initialPoint;
}

void GslOptimizer::minimize() {

  // First check that initial guess is reasonable
  if (!this->m_objectiveFunction.domainSet().contains(*(this->m_initialPoint)))
    {
      if( m_objectiveFunction.domainSet().env().fullRank() == 0 )
        {
          std::cerr << "Minimization was given initial point outside of domain"
                    << std::endl;
        }
      queso_error();
    }

  unsigned int dim = this->m_objectiveFunction.domainSet().vectorSpace().
    zeroVector().sizeLocal();

  if( this->solver_needs_gradient(m_solver_type) )
    {
      this->minimize_with_gradient( dim );
    }
  else
    {
      this->minimize_no_gradient( dim );
    }

  return;
}

const BaseScalarFunction<GslVector, GslMatrix> &
GslOptimizer::objectiveFunction() const
{
  return this->m_objectiveFunction;
}

void
GslOptimizer::setInitialPoint(const GslVector & initialPoint)
{
  for (unsigned int i = 0; i < initialPoint.sizeLocal(); i++) {
    (*(this->m_initialPoint))[i] = initialPoint[i];
  }
}

const GslVector &
GslOptimizer::minimizer() const
{
  return *(this->m_minimizer);
}

  void GslOptimizer::set_solver_type( SolverType solver )
  {
    m_solver_type = solver;
  }

  bool GslOptimizer::solver_needs_gradient( SolverType solver )
  {
    bool gradient_needed = false;

    switch(solver)
      {
      case(FLETCHER_REEVES_CG):
      case(POLAK_RIBIERE_CG):
      case(BFGS):
      case(BFGS2):
      case(STEEPEST_DECENT):
        {
          gradient_needed = true;
          break;
        }
      case(NELDER_MEAD):
      case(NELDER_MEAD2):
      case(NELDER_MEAD2_RAND):
        {
          break;
        }
      default:
        {
          // Wat?!
          queso_error();
        }
      } // switch(solver)

    return gradient_needed;
  }

  void GslOptimizer::minimize_with_gradient( unsigned int dim )
  {
    // Set initial point
    gsl_vector * x = gsl_vector_alloc(dim);
    for (unsigned int i = 0; i < dim; i++) {
      gsl_vector_set(x, i, (*m_initialPoint)[i]);
    }

    // Tell GSL which solver we're using
    const gsl_multimin_fdfminimizer_type* type = NULL;

    switch(m_solver_type)
      {
      case(FLETCHER_REEVES_CG):
        type = gsl_multimin_fdfminimizer_conjugate_fr;
        break;
      case(POLAK_RIBIERE_CG):
        type = gsl_multimin_fdfminimizer_conjugate_pr;
        break;
      case(BFGS):
        type = gsl_multimin_fdfminimizer_vector_bfgs;
        break;
      case(BFGS2):
        type = gsl_multimin_fdfminimizer_vector_bfgs2;
        break;
      case(STEEPEST_DECENT):
        type = gsl_multimin_fdfminimizer_steepest_descent;
        break;
      case(NELDER_MEAD):
      case(NELDER_MEAD2):
      case(NELDER_MEAD2_RAND):
      default:
        // Wat?!
        queso_error();
      }

    // Init solver
    gsl_multimin_fdfminimizer * solver =
      gsl_multimin_fdfminimizer_alloc(type, dim);

    // Point GSL to the right functions
    gsl_multimin_function_fdf minusLogPosterior;
    minusLogPosterior.n = dim;
    minusLogPosterior.f = &c_evaluate;
    minusLogPosterior.df = &c_evaluate_derivative;
    minusLogPosterior.fdf = &c_evaluate_with_derivative;
    minusLogPosterior.params = (void *)(this);

    /*!
     * \todo Allow the user to tweak these hard-coded values
     */
    gsl_multimin_fdfminimizer_set(solver, &minusLogPosterior, x, 0.01, 0.1);

    int status;
    size_t iter = 0;

    do {
      iter++;
      status = gsl_multimin_fdfminimizer_iterate(solver);

      if (status) {
        if( m_objectiveFunction.domainSet().env().fullRank() == 0 )
          {
            std::cerr << "Error while GSL does optimisation. "
                      << "See below for GSL error type." << std::endl;
            std::cerr << "Gsl error: " << gsl_strerror(status) << std::endl;
          }
        break;
      }

      status = gsl_multimin_test_gradient(solver->gradient, this->getTolerance());

    } while ((status == GSL_CONTINUE) && (iter < this->getMaxIterations()));

    for (unsigned int i = 0; i < dim; i++) {
      (*m_minimizer)[i] = gsl_vector_get(solver->x, i);
    }

    // We're being good human beings and cleaning up the memory we allocated
    gsl_multimin_fdfminimizer_free(solver);
    gsl_vector_free(x);

    return;
  }

  void GslOptimizer::minimize_no_gradient( unsigned int dim )
  {
    // Set initial point
    gsl_vector* x = gsl_vector_alloc(dim);
    for (unsigned int i = 0; i < dim; i++) {
      gsl_vector_set(x, i, (*m_initialPoint)[i]);
    }

    // Tell GSL which solver we're using
    const gsl_multimin_fminimizer_type* type = NULL;

    switch(m_solver_type)
      {
      case(NELDER_MEAD):
        type = gsl_multimin_fminimizer_nmsimplex;
        break;
      case(NELDER_MEAD2):
        type = gsl_multimin_fminimizer_nmsimplex2;
        break;
      case(NELDER_MEAD2_RAND):
        type = gsl_multimin_fminimizer_nmsimplex2rand;
        break;
      case(FLETCHER_REEVES_CG):
      case(POLAK_RIBIERE_CG):
      case(BFGS):
      case(BFGS2):
      case(STEEPEST_DECENT):
      default:
        // Wat?!
        queso_error();
      }

    // Init solver
    gsl_multimin_fminimizer* solver =
      gsl_multimin_fminimizer_alloc(type, dim);

    // Point GSL at the right functions
    gsl_multimin_function minusLogPosterior;
    minusLogPosterior.n = dim;
    minusLogPosterior.f = &c_evaluate;
    minusLogPosterior.params = (void *)(this);

    // Needed for these gradient free algorithms.
    gsl_vector* step_size = gsl_vector_alloc(dim);

    for(unsigned int i = 0; i < dim; i++) {
      gsl_vector_set(step_size, i, m_step_size[i]);
    }

    gsl_multimin_fminimizer_set(solver, &minusLogPosterior, x, step_size);

    int status;
    size_t iter = 0;
    double size = 0.0;

    do
      {
        iter++;
        status = gsl_multimin_fminimizer_iterate(solver);

        if (status) {
          if( m_objectiveFunction.domainSet().env().fullRank() == 0 )
            {
              std::cerr << "Error while GSL does optimisation. "
                        << "See below for GSL error type." << std::endl;
              std::cerr << "Gsl error: " << gsl_strerror(status) << std::endl;
            }
          break;
        }

        size = gsl_multimin_fminimizer_size(solver);

        status = gsl_multimin_test_size (size, this->getTolerance());

      }

    while ((status == GSL_CONTINUE) && (iter < this->getMaxIterations()));

    for (unsigned int i = 0; i < dim; i++) {
      (*m_minimizer)[i] = gsl_vector_get(solver->x, i);
    }

    // We're being good human beings and cleaning up the memory we allocated
    gsl_vector_free(step_size);
    gsl_multimin_fminimizer_free(solver);
    gsl_vector_free(x);

    return;
  }

  void GslOptimizer::set_step_size( const GslVector& step_size )
  {
    m_step_size = step_size;
  }

}  // End namespace QUESO
<|endoftext|>


<commit_before>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// QUESO - a library to support the Quantification of Uncertainty
// for Estimation, Simulation and Optimization
//
// Copyright (C) 2008,2009,2010,2011,2012,2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

#include <iostream>

#include <gsl/gsl_multimin.h>
#include <queso/GslVector.h>
#include <queso/VectorSpace.h>
#include <queso/ScalarFunction.h>
#include <queso/GslOptimizer.h>

namespace QUESO {

// We need to extern "C" because gsl needs a pointer to a C function to
// minimize
extern "C" {
  // This evaluate -log posterior
  double c_evaluate(const gsl_vector * x, void * context) {

    BaseScalarFunction<GslVector, GslMatrix> & objectiveFunction =
      *(static_cast<BaseScalarFunction<GslVector, GslMatrix> * >(context));

    GslVector state(objectiveFunction.domainSet().vectorSpace().zeroVector());

    // DM: Doing this copy sucks, but whatever.  It'll do for now.
    for (unsigned int i = 0; i < state.sizeLocal(); i++) {
      state[i] = gsl_vector_get(x, i);
    }

    double result = -objectiveFunction.lnValue(state, NULL, NULL, NULL, NULL);

    return result;
  }

  // This evaluates the derivative of -log posterior
  void c_evaluate_derivative(const gsl_vector * x, void * context,
      gsl_vector * derivative) {
    BaseScalarFunction<GslVector, GslMatrix> & objectiveFunction =
      *(static_cast<BaseScalarFunction<GslVector, GslMatrix> * >(context));

    GslVector state(objectiveFunction.domainSet().vectorSpace().zeroVector());
    GslVector deriv(objectiveFunction.domainSet().vectorSpace().zeroVector());

    // DM: Doing this copy sucks, but whatever.  It'll do for now.
    for (unsigned int i = 0; i < state.sizeLocal(); i++) {
      state[i] = gsl_vector_get(x, i);
    }

    // We should cache the return value here so we don't recompute stuff
    double fx = -objectiveFunction.lnValue(state, NULL, &deriv, NULL, NULL);

    for (unsigned int i = 0; i < deriv.sizeLocal(); i++) {
      gsl_vector_set(derivative, i, deriv[i]);
    }
  }

  // This evaluates -log posterior and the derivative of -log posterior
  void c_evaluate_with_derivative(const gsl_vector * x, void * context,
      double * f, gsl_vector * derivative) {
    // We don't need to call both of these
    *f = c_evaluate(x, context);
    c_evaluate_derivative(x, context, derivative);
  }
}  // End extern "C"

GslOptimizer::GslOptimizer(
    const BaseScalarFunction<GslVector, GslMatrix> & objectiveFunction)
  : BaseOptimizer(),
    m_objectiveFunction(objectiveFunction)
{
}

GslOptimizer::~GslOptimizer()
{
}

const Vector *
GslOptimizer::minimize() {
  size_t iter = 0;
  int status;
  int dim = this->m_objectiveFunction.domainSet().vectorSpace().zeroVector().
    sizeLocal();

  const gsl_multimin_fdfminimizer_type * T =
    gsl_multimin_fdfminimizer_conjugate_fr;

  gsl_multimin_fdfminimizer * s =
    gsl_multimin_fdfminimizer_alloc(T, dim);

  gsl_multimin_function_fdf minusLogPosterior;
  minusLogPosterior.n = dim;
  minusLogPosterior.f = &c_evaluate;
  minusLogPosterior.df = &c_evaluate_derivative;
  minusLogPosterior.fdf = &c_evaluate_with_derivative;
  minusLogPosterior.params = (void *)(&(this->m_objectiveFunction));

  // Set initial point (should take this from the user instead);
  gsl_vector * x = gsl_vector_alloc(dim);
  for (unsigned int i = 0; i < dim; i++) {
    gsl_vector_set(x, i, 9.0);  // DM: Initial point should not be hard-coded
  }

  // What are these hard-coded values?
  gsl_multimin_fdfminimizer_set(s, &minusLogPosterior, x, 0.01, 0.1);

  do {
    iter++;
    status = gsl_multimin_fdfminimizer_iterate(s);

    if (status) {
      if (status == GSL_ENOPROG) {
        std::cerr << "Minimizer could not make progress" << std::endl;
      }
      std::cerr << "Gsl error: " << gsl_strerror(status) << std::endl;
      break;
    }

    // What is this hard-coded value?
    status = gsl_multimin_test_gradient(s->gradient, 1e-3);

    if (status == GSL_SUCCESS) {
      std::cerr << "Minimizer will do another iteration" << std::endl;
    }
  } while (status == GSL_CONTINUE && iter < 100);  // We shouldn't be hard-coding the max number of iterations

  // Get the minimizer
  GslVector * minimizer = new GslVector(this->m_objectiveFunction.domainSet().
      vectorSpace().zeroVector());
  for (unsigned int i = 0; i < dim; i++) {
    (*minimizer)[i] = gsl_vector_get(s->x, i);
  }

  // We're being good human beings and cleaning up the memory we allocated
  gsl_multimin_fdfminimizer_free(s);
  gsl_vector_free(x);

  // Return the minimizer.  That's all she wrote.
  return minimizer;
}

}  // End namespace QUESO
<commit_msg>Return the correct error when out of the domain<commit_after>//-----------------------------------------------------------------------bl-
//--------------------------------------------------------------------------
//
// QUESO - a library to support the Quantification of Uncertainty
// for Estimation, Simulation and Optimization
//
// Copyright (C) 2008,2009,2010,2011,2012,2013 The PECOS Development Team
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the Version 2.1 GNU Lesser General
// Public License as published by the Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc. 51 Franklin Street, Fifth Floor,
// Boston, MA  02110-1301  USA
//
//-----------------------------------------------------------------------el-

#include <iostream>

#include <gsl/gsl_multimin.h>
#include <queso/GslVector.h>
#include <queso/VectorSpace.h>
#include <queso/ScalarFunction.h>
#include <queso/GslOptimizer.h>

namespace QUESO {

// We need to extern "C" because gsl needs a pointer to a C function to
// minimize
extern "C" {
  // This evaluate -log posterior
  double c_evaluate(const gsl_vector * x, void * context) {

    BaseScalarFunction<GslVector, GslMatrix> & objectiveFunction =
      *(static_cast<BaseScalarFunction<GslVector, GslMatrix> * >(context));

    GslVector state(objectiveFunction.domainSet().vectorSpace().zeroVector());

    // DM: Doing this copy sucks, but whatever.  It'll do for now.
    for (unsigned int i = 0; i < state.sizeLocal(); i++) {
      state[i] = gsl_vector_get(x, i);
    }

    // Bail early if GSL tries to evaluate outside of the domain
    if (!objectiveFunction.domainSet().contains(state)) {
      return GSL_NAN;
    }

    // Should cace derivative here so we don't a) segfault in the user's code
    // and b) so we don't recompute stuff
    double result = -objectiveFunction.lnValue(state, NULL, NULL, NULL, NULL);

    return result;
  }

  // This evaluates the derivative of -log posterior
  void c_evaluate_derivative(const gsl_vector * x, void * context,
      gsl_vector * derivative) {
    BaseScalarFunction<GslVector, GslMatrix> & objectiveFunction =
      *(static_cast<BaseScalarFunction<GslVector, GslMatrix> * >(context));

    GslVector state(objectiveFunction.domainSet().vectorSpace().zeroVector());
    GslVector deriv(objectiveFunction.domainSet().vectorSpace().zeroVector());

    // DM: Doing this copy sucks, but whatever.  It'll do for now.
    for (unsigned int i = 0; i < state.sizeLocal(); i++) {
      state[i] = gsl_vector_get(x, i);
    }

    if (!objectiveFunction.domainSet().contains(state)) {
      // Fill derivative with error codes if the point is outside of the
      // domain
      for (unsigned int i = 0; i < deriv.sizeLocal(); i++) {
        gsl_vector_set(derivative, i, GSL_NAN);
      }
    }
    else {
      // We should cache the return value here so we don't recompute stuff
      double fx = -objectiveFunction.lnValue(state, NULL, &deriv, NULL, NULL);

    for (unsigned int i = 0; i < deriv.sizeLocal(); i++) {
      gsl_vector_set(derivative, i, deriv[i]);
    }
  }

  // This evaluates -log posterior and the derivative of -log posterior
  void c_evaluate_with_derivative(const gsl_vector * x, void * context,
      double * f, gsl_vector * derivative) {
    // We don't need to call both of these
    *f = c_evaluate(x, context);
    c_evaluate_derivative(x, context, derivative);
  }
}  // End extern "C"

GslOptimizer::GslOptimizer(
    const BaseScalarFunction<GslVector, GslMatrix> & objectiveFunction)
  : BaseOptimizer(),
    m_objectiveFunction(objectiveFunction)
{
}

GslOptimizer::~GslOptimizer()
{
}

const Vector *
GslOptimizer::minimize() {
  size_t iter = 0;
  int status;
  int dim = this->m_objectiveFunction.domainSet().vectorSpace().zeroVector().
    sizeLocal();

  const gsl_multimin_fdfminimizer_type * T =
    gsl_multimin_fdfminimizer_conjugate_fr;

  gsl_multimin_fdfminimizer * s =
    gsl_multimin_fdfminimizer_alloc(T, dim);

  gsl_multimin_function_fdf minusLogPosterior;
  minusLogPosterior.n = dim;
  minusLogPosterior.f = &c_evaluate;
  minusLogPosterior.df = &c_evaluate_derivative;
  minusLogPosterior.fdf = &c_evaluate_with_derivative;
  minusLogPosterior.params = (void *)(&(this->m_objectiveFunction));

  // Set initial point (should take this from the user instead);
  gsl_vector * x = gsl_vector_alloc(dim);
  for (unsigned int i = 0; i < dim; i++) {
    gsl_vector_set(x, i, 9.0);  // DM: Initial point should not be hard-coded
  }

  // What are these hard-coded values?
  gsl_multimin_fdfminimizer_set(s, &minusLogPosterior, x, 0.01, 0.1);

  do {
    iter++;
    status = gsl_multimin_fdfminimizer_iterate(s);

    if (status) {
      if (status == GSL_ENOPROG) {
        std::cerr << "Minimizer could not make progress" << std::endl;
      }
      std::cerr << "Gsl error: " << gsl_strerror(status) << std::endl;
      break;
    }

    // What is this hard-coded value?
    status = gsl_multimin_test_gradient(s->gradient, 1e-3);

    if (status == GSL_SUCCESS) {
      std::cerr << "Minimizer will do another iteration" << std::endl;
    }
  } while (status == GSL_CONTINUE && iter < 100);  // We shouldn't be hard-coding the max number of iterations

  // Get the minimizer
  GslVector * minimizer = new GslVector(this->m_objectiveFunction.domainSet().
      vectorSpace().zeroVector());
  for (unsigned int i = 0; i < dim; i++) {
    (*minimizer)[i] = gsl_vector_get(s->x, i);
  }

  // We're being good human beings and cleaning up the memory we allocated
  gsl_multimin_fdfminimizer_free(s);
  gsl_vector_free(x);

  // Return the minimizer.  That's all she wrote.
  return minimizer;
}

}  // End namespace QUESO
<|endoftext|>


<commit_before>#include "cvm.h"

DabClass &DabVM::define_builtin_class(const std::string &name, size_t class_index,
                                      size_t superclass_index)
{
    DabClass klass;
    klass.index            = class_index;
    klass.name             = name;
    klass.builtin          = true;
    klass.superclass_index = superclass_index;
    classes[class_index]   = klass;
    return classes[class_index];
}

void DabVM::define_default_classes()
{
    auto &vm = *this;

    auto &object_class = define_builtin_class("Object", CLASS_OBJECT);
    object_class.add_static_function("new", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 1);
        assert(n_ret == 1);
        auto arg = stack.pop_value();
        assert(arg.data.type == TYPE_CLASS);
        stack.push_value(arg.create_instance());
    });
    object_class.add_function("class", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 1);
        assert(n_ret == 1);
        auto arg = stack.pop_value();
        stack.push_value(arg.get_class(*this));
    });

    auto &string_class = define_builtin_class("String", CLASS_STRING);
    string_class.add_simple_function(vm, "upcase", [](DabValue self) {
        auto arg0 = self;
        assert(arg0.data.type == TYPE_STRING);
        auto &s = arg0.data.string;
        std::transform(s.begin(), s.end(), s.begin(), ::toupper);
        return arg0;
    });
    string_class.add_function("[]", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 2);
        assert(n_ret == 1);
        auto arg0 = stack.pop_value();
        auto arg1 = stack.pop_value();
        assert(arg0.data.type == TYPE_STRING);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &s = arg0.data.string;
        auto  n = arg1.data.fixnum;
        stack.push(s.substr(n, 1));
    });
    string_class.add_static_function("new", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 1 || n_args == 2);
        assert(n_ret == 1);
        auto     klass = stack.pop_value();
        DabValue ret_value;
        ret_value.data.type = TYPE_STRING;
        ret_value.data.kind = VAL_STACK;
        if (n_args == 2)
        {
            auto arg = stack.pop_value();
            assert(arg.data.type == TYPE_STRING);
            ret_value.data.string = arg.data.string;
        }
        stack.push_value(ret_value);
    });

    define_builtin_class("LiteralString", CLASS_LITERALSTRING, CLASS_STRING);

    auto &fixnum_class = define_builtin_class("Fixnum", CLASS_FIXNUM);
    fixnum_class.add_static_function("new", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 1 || n_args == 2);
        assert(n_ret == 1);
        auto     klass = stack.pop_value();
        DabValue ret_value;
        ret_value.data.type   = TYPE_FIXNUM;
        ret_value.data.kind   = VAL_STACK;
        ret_value.data.fixnum = 0;
        if (n_args == 2)
        {
            auto arg = stack.pop_value();
            assert(arg.data.type == TYPE_FIXNUM);
            ret_value.data.fixnum = arg.data.fixnum;
        }
        stack.push_value(ret_value);
    });

    define_builtin_class("LiteralFixnum", CLASS_LITERALFIXNUM, CLASS_FIXNUM);

    define_builtin_class("Boolean", CLASS_BOOLEAN);

    define_builtin_class("NilClass", CLASS_NILCLASS);

    auto &array_class = define_builtin_class("Array", CLASS_ARRAY);
    array_class.add_function("count", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 1);
        assert(n_ret == 1);
        auto arg0 = stack.pop_value();
        assert(arg0.data.type == TYPE_ARRAY);
        auto &a = arg0.data.array;
        stack.push(a.size());
    });
    array_class.add_function("[]", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 2);
        assert(n_ret == 1);
        auto arg0 = stack.pop_value();
        auto arg1 = stack.pop_value();
        assert(arg0.data.type == TYPE_ARRAY);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.data.array;
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= a.size())
            stack.push_value(nullptr);
        else
            stack.push_value(a[n]);
    });
}
<commit_msg>vm: simplify Object.class<commit_after>#include "cvm.h"

DabClass &DabVM::define_builtin_class(const std::string &name, size_t class_index,
                                      size_t superclass_index)
{
    DabClass klass;
    klass.index            = class_index;
    klass.name             = name;
    klass.builtin          = true;
    klass.superclass_index = superclass_index;
    classes[class_index]   = klass;
    return classes[class_index];
}

void DabVM::define_default_classes()
{
    auto &vm = *this;

    auto &object_class = define_builtin_class("Object", CLASS_OBJECT);
    object_class.add_static_function("new", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 1);
        assert(n_ret == 1);
        auto arg = stack.pop_value();
        assert(arg.data.type == TYPE_CLASS);
        stack.push_value(arg.create_instance());
    });
    object_class.add_simple_function(vm, "class", [this](DabValue self) {
        auto arg = self;
        return arg.get_class(*this);
    });

    auto &string_class = define_builtin_class("String", CLASS_STRING);
    string_class.add_simple_function(vm, "upcase", [](DabValue self) {
        auto arg0 = self;
        assert(arg0.data.type == TYPE_STRING);
        auto &s = arg0.data.string;
        std::transform(s.begin(), s.end(), s.begin(), ::toupper);
        return arg0;
    });
    string_class.add_function("[]", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 2);
        assert(n_ret == 1);
        auto arg0 = stack.pop_value();
        auto arg1 = stack.pop_value();
        assert(arg0.data.type == TYPE_STRING);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &s = arg0.data.string;
        auto  n = arg1.data.fixnum;
        stack.push(s.substr(n, 1));
    });
    string_class.add_static_function("new", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 1 || n_args == 2);
        assert(n_ret == 1);
        auto     klass = stack.pop_value();
        DabValue ret_value;
        ret_value.data.type = TYPE_STRING;
        ret_value.data.kind = VAL_STACK;
        if (n_args == 2)
        {
            auto arg = stack.pop_value();
            assert(arg.data.type == TYPE_STRING);
            ret_value.data.string = arg.data.string;
        }
        stack.push_value(ret_value);
    });

    define_builtin_class("LiteralString", CLASS_LITERALSTRING, CLASS_STRING);

    auto &fixnum_class = define_builtin_class("Fixnum", CLASS_FIXNUM);
    fixnum_class.add_static_function("new", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 1 || n_args == 2);
        assert(n_ret == 1);
        auto     klass = stack.pop_value();
        DabValue ret_value;
        ret_value.data.type   = TYPE_FIXNUM;
        ret_value.data.kind   = VAL_STACK;
        ret_value.data.fixnum = 0;
        if (n_args == 2)
        {
            auto arg = stack.pop_value();
            assert(arg.data.type == TYPE_FIXNUM);
            ret_value.data.fixnum = arg.data.fixnum;
        }
        stack.push_value(ret_value);
    });

    define_builtin_class("LiteralFixnum", CLASS_LITERALFIXNUM, CLASS_FIXNUM);

    define_builtin_class("Boolean", CLASS_BOOLEAN);

    define_builtin_class("NilClass", CLASS_NILCLASS);

    auto &array_class = define_builtin_class("Array", CLASS_ARRAY);
    array_class.add_function("count", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 1);
        assert(n_ret == 1);
        auto arg0 = stack.pop_value();
        assert(arg0.data.type == TYPE_ARRAY);
        auto &a = arg0.data.array;
        stack.push(a.size());
    });
    array_class.add_function("[]", [this](size_t n_args, size_t n_ret) {
        assert(n_args == 2);
        assert(n_ret == 1);
        auto arg0 = stack.pop_value();
        auto arg1 = stack.pop_value();
        assert(arg0.data.type == TYPE_ARRAY);
        assert(arg1.data.type == TYPE_FIXNUM);
        auto &a = arg0.data.array;
        auto  n = arg1.data.fixnum;
        if (n < 0)
            n = a.size() + n;
        if (n < 0 || n >= a.size())
            stack.push_value(nullptr);
        else
            stack.push_value(a[n]);
    });
}
<|endoftext|>


<commit_before>#include "renderdoc.hpp"

#include "../platform.hpp"
#include "../util/logger.hpp"
#include "../util/utils.hpp"

#if defined(NOVA_WINDOWS)
#include "../util/windows.hpp"
#include "../util/windows_utils.hpp"

// Fucking hell
#ifdef ERROR
#undef ERROR
#endif
#elif defined(NOVA_LINUX)
#include <dlfcn.h>
#include "../util/linux_utils.hpp"
#endif

namespace nova::renderer {
    result<RENDERDOC_API_1_3_0*> load_renderdoc(const std::string& renderdoc_dll_path) {
#if defined(NOVA_WINDOWS)
        using HINSTANCE = HINSTANCE__* const;
        HINSTANCE renderdoc_dll = LoadLibrary(renderdoc_dll_path.c_str());
        if(!renderdoc_dll) {
            const std::string error = get_last_windows_error();
            return result<RENDERDOC_API_1_3_0*>(MAKE_ERROR("Could not load RenderDoc. Error: {:s}", error));
        }

        NOVA_LOG(TRACE) << "Loaded RenderDoc DLL from " << renderdoc_dll_path;

        const auto get_api = reinterpret_cast<pRENDERDOC_GetAPI>(GetProcAddress(renderdoc_dll, "RENDERDOC_GetAPI"));
        if(!get_api) {
            const std::string error = get_last_windows_error();
            return result<RENDERDOC_API_1_3_0*>(MAKE_ERROR("Could not load RenderDoc DLL. Error: {:s}", error));
        }

#elif defined(NOVA_LINUX)
        void* renderdoc_so = dlopen(renderdoc_dll_path.c_str(), RTLD_NOW);
        if(renderdoc_so == nullptr) {
            // Try to load system-wide version of renderdoc
            renderdoc_so = dlopen("librenderdoc.so", RTLD_NOW);
            if(renderdoc_so == nullptr) {
                return error_result<RENDERDOC_API_1_3_0*>("Could not load RenderDoc. Error: {:s}", dlerror());
            }
        }

        const auto get_api = reinterpret_cast<pRENDERDOC_GetAPI>(dlsym(renderdoc_so, "RENDERDOC_GetAPI"));
        if(get_api == nullptr) {
            return error_result<RENDERDOC_API_1_3_0*>("Could not find the RenderDoc API loading function. Error: {:s}", dlerror());
        }
#endif

        RENDERDOC_API_1_3_0* api;
        const int32_t ret = get_api(eRENDERDOC_API_Version_1_3_0, reinterpret_cast<void**>(&api));
        if(ret != 1) {
            NOVA_LOG(ERROR) << "Could not load RenderDoc API";

            return result<RENDERDOC_API_1_3_0*>(MAKE_ERROR("Could not load RenderDoc API. Error code {:d}", ret));
        }

        NOVA_LOG(TRACE) << "Loaded RenderDoc 1.3 API";
        return result(api);
    }
} // namespace nova::renderer
<commit_msg>Macros > templates linux edition<commit_after>#include "renderdoc.hpp"

#include "../platform.hpp"
#include "../util/logger.hpp"
#include "../util/utils.hpp"

#if defined(NOVA_WINDOWS)
#include "../util/windows.hpp"
#include "../util/windows_utils.hpp"

// Fucking hell
#ifdef ERROR
#undef ERROR
#endif
#elif defined(NOVA_LINUX)
#include <dlfcn.h>
#include "../util/linux_utils.hpp"
#endif

namespace nova::renderer {
    result<RENDERDOC_API_1_3_0*> load_renderdoc(const std::string& renderdoc_dll_path) {
#if defined(NOVA_WINDOWS)
        using HINSTANCE = HINSTANCE__* const;
        HINSTANCE renderdoc_dll = LoadLibrary(renderdoc_dll_path.c_str());
        if(!renderdoc_dll) {
            const std::string error = get_last_windows_error();
            return result<RENDERDOC_API_1_3_0*>(MAKE_ERROR("Could not load RenderDoc. Error: {:s}", error));
        }

        NOVA_LOG(TRACE) << "Loaded RenderDoc DLL from " << renderdoc_dll_path;

        const auto get_api = reinterpret_cast<pRENDERDOC_GetAPI>(GetProcAddress(renderdoc_dll, "RENDERDOC_GetAPI"));
        if(!get_api) {
            const std::string error = get_last_windows_error();
            return result<RENDERDOC_API_1_3_0*>(MAKE_ERROR("Could not load RenderDoc DLL. Error: {:s}", error));
        }

#elif defined(NOVA_LINUX)
        void* renderdoc_so = dlopen(renderdoc_dll_path.c_str(), RTLD_NOW);
        if(renderdoc_so == nullptr) {
            // Try to load system-wide version of renderdoc
            renderdoc_so = dlopen("librenderdoc.so", RTLD_NOW);
            if(renderdoc_so == nullptr) {
                return result<RENDERDOC_API_1_3_0*>(MAKE_ERROR("Could not load RenderDoc DLL. Error: {:s}", dlerror()));
            }
        }

        const auto get_api = reinterpret_cast<pRENDERDOC_GetAPI>(dlsym(renderdoc_so, "RENDERDOC_GetAPI"));
        if(get_api == nullptr) {
            return result<RENDERDOC_API_1_3_0*>(MAKE_ERROR("Could not find the RenderDoc API loading function. Error: {:s}", dlerror()));
        }
#endif

        RENDERDOC_API_1_3_0* api;
        const int32_t ret = get_api(eRENDERDOC_API_Version_1_3_0, reinterpret_cast<void**>(&api));
        if(ret != 1) {
            NOVA_LOG(ERROR) << "Could not load RenderDoc API";

            return result<RENDERDOC_API_1_3_0*>(MAKE_ERROR("Could not load RenderDoc API. Error code {:d}", ret));
        }

        NOVA_LOG(TRACE) << "Loaded RenderDoc 1.3 API";
        return result(api);
    }
} // namespace nova::renderer
<|endoftext|>


<commit_before>#include <stdio.h>
#include <string.h>

#include "SDL/SDL.h"

#include "video/Bitmap.h"
#include "video/FrameBuffer.h"
#include "logger/Logger.h"
#include "video/FrameBufferSDL.h"

using namespace poppy;

int main(int argc, char *argv[])
{
  SDL_Init(SDL_INIT_EVERYTHING);

  SDL_Surface *screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);

  int x, y;
  uint32_t yellow;

  x = screen->w / 2;
  y = screen->h / 2;
  yellow = SDL_MapRGB(screen->format, 0xff, 0x00, 0x00);

  FrameBufferSDL sdlFrameBuf(screen, true);
  uint8_t *buf = NULL;
  int pitch = 0;

  sdlFrameBuf.lockFrameBuffer(&buf, &pitch);
  sdlFrameBuf.putPixel(buf, x, y, yellow);
  sdlFrameBuf.unlockFrameBuffer(buf);

  SDL_Quit();
  SDL_Delay(20000);

  return 0;
}

<commit_msg>添加消息处理代码，解决SDL窗口无响应的问题。<commit_after>#include <stdio.h>
#include <string.h>

#include "SDL/SDL.h"

#include "video/Bitmap.h"
#include "video/FrameBuffer.h"
#include "logger/Logger.h"
#include "video/FrameBufferSDL.h"

using namespace poppy;

int main(int argc, char *argv[])
{
  SDL_Init(SDL_INIT_EVERYTHING);
  //setLogLevel(INFO);

  SDL_Surface *screen = SDL_SetVideoMode(640, 480, 32, SDL_SWSURFACE);

  int x, y;
  uint32_t yellow;

  x = screen->w / 2;
  y = screen->h / 2;
  yellow = SDL_MapRGB(screen->format, 0xff, 0x00, 0x00);

  FrameBufferSDL sdlFrameBuf(screen, true);
  uint8_t *buf = NULL;
  int pitch = 0;

  sdlFrameBuf.lockFrameBuffer(&buf, &pitch);
  sdlFrameBuf.putPixel(buf, x, y, yellow);
  sdlFrameBuf.unlockFrameBuffer(buf);

  //handing event
  SDL_Event event;
  while (SDL_WaitEvent(&event))
  {
    LOG_INFO("Get a event: %d\n", event.type);
    if (event.type == SDL_QUIT)
    {
      LOG_INFO("Break from event loop!\n");
      break;
    }
  }

  SDL_Quit();

  return 0;
}

<|endoftext|>


<commit_before>#include "blackmagicsdk_video_source.h"

namespace gg
{

VideoSourceBlackmagicSDK::VideoSourceBlackmagicSDK()
    : IVideoSource()
    , _frame_rate(0.0)
    , _video_buffer(nullptr)
    , _video_buffer_length(0)
    , _cols(0)
    , _rows(0)
    // This constructor should never be called,
    // therefore setting I420 arbitrarily for the
    // buffer video frame here.
    , _buffer_video_frame(VideoFrame(I420))
    , _running(false)
{
    // nop
}

VideoSourceBlackmagicSDK::VideoSourceBlackmagicSDK(size_t deck_link_index,
                                                   ColourSpace colour)
    : IVideoSource(colour)
    , _frame_rate(0.0)
    , _video_buffer(nullptr)
    , _video_buffer_length(0)
    , _cols(0)
    , _rows(0)
    , _buffer_video_frame(VideoFrame(colour, false)) // TODO manage data?
    , _deck_link(nullptr)
    , _deck_link_input(nullptr)
    , _running(false)
{
    // Pixel format, i.e. colour space
    BMDPixelFormat pixel_format;
    switch(_colour)
    {
    case BGRA:
        pixel_format = bmdFormat8BitBGRA;
        break;
    case UYVY:
        pixel_format = bmdFormat8BitYUV;
        break;
    case I420:
    default:
        release_deck_link();
        throw VideoSourceError(
            "BlackmagicSDK video source supports only the BGRA and UYVY colour spaces"
        );
    }

    // Get an iterator through the available DeckLink ports
    IDeckLinkIterator * deck_link_iterator = CreateDeckLinkIteratorInstance();
    if (deck_link_iterator == nullptr)
    {
        release_deck_link();
        throw VideoSourceError("DeckLink drivers do not appear to be installed");
    }

    HRESULT res;

    // Get the desired DeckLink index (port)
    int idx = deck_link_index;
    while ((res = deck_link_iterator->Next(&_deck_link)) == S_OK)
    {
        if (idx == 0)
            break;
        --idx;

        _deck_link->Release();
    }
    if (deck_link_iterator != nullptr)
        deck_link_iterator->Release();
    // No glory: release everything and throw exception
    if (res != S_OK or _deck_link == nullptr)
    {
        release_deck_link();
        throw VideoSourceError(
            std::string("Could not get DeckLink device ").append(std::to_string(deck_link_index))
        );
    }

    // Get the input interface of connected DeckLink port
    res = _deck_link->QueryInterface(IID_IDeckLinkInput, reinterpret_cast<void **>(&_deck_link_input));
    // No glory: release everything and throw exception
    if (res != S_OK)
    {
        release_deck_link();
        throw VideoSourceError("Could not get the Blackmagic DeckLink input interface");
    }

    // Set this object (IDeckLinkInputCallback instance) as callback
    res = _deck_link_input->SetCallback(this);
    // No glory: release everything and throw exception
    if (res != S_OK)
    {
        release_deck_link();
        throw VideoSourceError("Could not set the callback of Blackmagic DeckLink device");
    }

    // Set the input format (i.e. display mode)
    BMDDisplayMode display_mode;
    std::string error_msg = "";
    BMDVideoInputFlags video_input_flags = bmdVideoInputFlagDefault | bmdVideoInputEnableFormatDetection;
    if (not detect_input_format(pixel_format, video_input_flags, display_mode, _frame_rate, error_msg))
        bail(error_msg);

    // Enable video input
    res = _deck_link_input->EnableVideoInput(display_mode,
                                             pixel_format,
                                             video_input_flags);
    // No glory
    if (res != S_OK)
        bail("Could not enable video input of Blackmagic DeckLink device");

    // Start streaming
    _running = true;
    res = _deck_link_input->StartStreams();
    // No glory: release everything and throw exception
    if (res != S_OK)
    {
        _running = false;
        bail("Could not start streaming from the Blackmagic DeckLink device");
    }
}

VideoSourceBlackmagicSDK::~VideoSourceBlackmagicSDK()
{
    // Make sure streamer thread not trying to access buffer
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);
    _running = false;

    // Stop streaming and disable enabled inputs
    _deck_link_input->StopStreams();
    _deck_link_input->DisableVideoInput();

    // Release DeckLink members
    release_deck_link();
}

bool VideoSourceBlackmagicSDK::get_frame_dimensions(int & width, int & height)
{
    // Make sure only this thread is accessing the cols and rows members now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);
    if (_cols <= 0 or _rows <= 0)
        return false;

    width = _cols;
    height = _rows;
    return true;
}

bool VideoSourceBlackmagicSDK::get_frame(VideoFrame & frame)
{
    if (frame.colour() != _colour)
        return false;

    // Make sure only this thread is accessing the video frame data now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);

    if (_video_buffer_length > 0 and _cols > 0 and _rows > 0)
    {
        frame.init_from_specs(_video_buffer, _video_buffer_length, _cols, _rows);
        return true;
    }
    else
        return false;
}

double VideoSourceBlackmagicSDK::get_frame_rate()
{
    return _frame_rate;
}

void VideoSourceBlackmagicSDK::set_sub_frame(int x, int y, int width, int height)
{
    // TODO
}

void VideoSourceBlackmagicSDK::get_full_frame()
{
    // TODO
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::QueryInterface(REFIID iid, LPVOID * ppv)
{
    return E_NOINTERFACE;
}

ULONG STDMETHODCALLTYPE VideoSourceBlackmagicSDK::AddRef(void)
{
    __sync_add_and_fetch(&_n_ref, 1);
    return _n_ref;
}

ULONG STDMETHODCALLTYPE VideoSourceBlackmagicSDK::Release(void)
{
    __sync_sub_and_fetch(&_n_ref, 1);
    return _n_ref;
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::VideoInputFormatChanged(
    BMDVideoInputFormatChangedEvents events,
    IDeckLinkDisplayMode * display_mode,
    BMDDetectedVideoInputFormatFlags format_flags
)
{
    // TODO
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::VideoInputFrameArrived(
    IDeckLinkVideoInputFrame * video_frame,
    IDeckLinkAudioInputPacket * audio_packet
)
{
    // Not processing the audio packet, but only the video
    // frame for the time being
    if (video_frame == nullptr)
        // nop if no data
        return S_OK;

    // Nr. of bytes of received data
    size_t n_bytes = video_frame->GetRowBytes() * video_frame->GetHeight();

    // Make sure only this thread is accessing the buffer now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);

    // Extend buffer if more memory needed than already allocated
    if (n_bytes > _video_buffer_length)
        _video_buffer = reinterpret_cast<uint8_t *>(
                    realloc(_video_buffer, n_bytes * sizeof(uint8_t))
        );
    if (_video_buffer == nullptr) // something's terribly wrong!
        // nop if something's terribly wrong!
        return S_OK;

    // Get the new data into the buffer
    HRESULT res = video_frame->GetBytes(
        reinterpret_cast<void **>(&_video_buffer)
    );
    // If data could not be read into the buffer, return
    if (FAILED(res))
        return res;
    // Set video frame specs according to new data
    _video_buffer_length = n_bytes;
    _cols = video_frame->GetWidth();
    _rows = video_frame->GetHeight();

    // Propagate new video frame to observers
    _buffer_video_frame.init_from_specs(
        _video_buffer, _video_buffer_length, _cols, _rows
    );
    this->notify(_buffer_video_frame);

    // Everything went fine, return success
    return S_OK;
}

void VideoSourceBlackmagicSDK::release_deck_link() noexcept
{
    if (_deck_link_input != nullptr)
    {
        _deck_link_input->Release();
        _deck_link_input = nullptr;
    }

    if (_deck_link != nullptr)
        _deck_link->Release();
}

bool VideoSourceBlackmagicSDK::detect_input_format(BMDPixelFormat pixel_format,
                                                   BMDVideoInputFlags video_input_flags,
                                                   BMDDisplayMode & display_mode,
                                                   double & frame_rate,
                                                   std::string & error_msg) noexcept
{
    // These are output and result variables
    BMDDisplayModeSupport display_mode_support;
    IDeckLinkDisplayMode * deck_link_display_mode = nullptr;
    HRESULT res;
    bool detected = true;

    // TODO
    BMDDisplayMode display_mode_ = bmdModeHD1080i6000;

    // Check whether the mode is supported
    res = _deck_link_input->DoesSupportVideoMode(
        display_mode_, pixel_format, video_input_flags,
        &display_mode_support, &deck_link_display_mode
    );
    // No glory (could not even check mode support)
    if (res != S_OK or deck_link_display_mode == nullptr)
    {
        detected = false;
        error_msg = "Could not check video mode support of Blackmagic DeckLink device";
    }
    else
    {
        // If mode supported, then get frame rate
        if (display_mode_support == bmdDisplayModeSupported)
        {
            // Get frame rate of DeckLink device
            BMDTimeValue frame_rate_duration, frame_rate_scale;
            res = deck_link_display_mode->GetFrameRate(&frame_rate_duration, &frame_rate_scale);
            // No glory
            if (res != S_OK)
            {
                detected = false;
                error_msg = "Could not infer frame rate of Blackmagic DeckLink device";
            }
            else
                frame_rate = (double) frame_rate_scale / (double) frame_rate_duration;
        }
        else
        {
            detected = false;
            // TODO
            error_msg = "TODO";
        }
    }

    // Release the DeckLink display mode object
    if (deck_link_display_mode != nullptr)
    {
        deck_link_display_mode->Release();
        deck_link_display_mode = nullptr;
    }

    if (detected)
        display_mode = display_mode_;

    return detected;
}

}
<commit_msg>Issue #5: DRYed BlackmagicSDK constructor by replacing release-throw's with bail()<commit_after>#include "blackmagicsdk_video_source.h"

namespace gg
{

VideoSourceBlackmagicSDK::VideoSourceBlackmagicSDK()
    : IVideoSource()
    , _frame_rate(0.0)
    , _video_buffer(nullptr)
    , _video_buffer_length(0)
    , _cols(0)
    , _rows(0)
    // This constructor should never be called,
    // therefore setting I420 arbitrarily for the
    // buffer video frame here.
    , _buffer_video_frame(VideoFrame(I420))
    , _running(false)
{
    // nop
}

VideoSourceBlackmagicSDK::VideoSourceBlackmagicSDK(size_t deck_link_index,
                                                   ColourSpace colour)
    : IVideoSource(colour)
    , _frame_rate(0.0)
    , _video_buffer(nullptr)
    , _video_buffer_length(0)
    , _cols(0)
    , _rows(0)
    , _buffer_video_frame(VideoFrame(colour, false)) // TODO manage data?
    , _deck_link(nullptr)
    , _deck_link_input(nullptr)
    , _running(false)
{
    // Pixel format, i.e. colour space
    BMDPixelFormat pixel_format;
    switch(_colour)
    {
    case BGRA:
        pixel_format = bmdFormat8BitBGRA;
        break;
    case UYVY:
        pixel_format = bmdFormat8BitYUV;
        break;
    case I420:
    default:
        bail("BlackmagicSDK video source supports only the BGRA and UYVY colour spaces");
    }

    // Get an iterator through the available DeckLink ports
    IDeckLinkIterator * deck_link_iterator = CreateDeckLinkIteratorInstance();
    if (deck_link_iterator == nullptr)
        bail("DeckLink drivers do not appear to be installed");

    HRESULT res;

    // Get the desired DeckLink index (port)
    int idx = deck_link_index;
    while ((res = deck_link_iterator->Next(&_deck_link)) == S_OK)
    {
        if (idx == 0)
            break;
        --idx;

        _deck_link->Release();
    }
    if (deck_link_iterator != nullptr)
        deck_link_iterator->Release();
    // No glory: release everything and throw exception
    if (res != S_OK or _deck_link == nullptr)
        bail(
            std::string("Could not get DeckLink device ").append(std::to_string(deck_link_index))
        );

    // Get the input interface of connected DeckLink port
    res = _deck_link->QueryInterface(IID_IDeckLinkInput, reinterpret_cast<void **>(&_deck_link_input));
    // No glory: release everything and throw exception
    if (res != S_OK)
        bail("Could not get the Blackmagic DeckLink input interface");

    // Set this object (IDeckLinkInputCallback instance) as callback
    res = _deck_link_input->SetCallback(this);
    // No glory: release everything and throw exception
    if (res != S_OK)
        bail("Could not set the callback of Blackmagic DeckLink device");

    // Set the input format (i.e. display mode)
    BMDDisplayMode display_mode;
    std::string error_msg = "";
    BMDVideoInputFlags video_input_flags = bmdVideoInputFlagDefault | bmdVideoInputEnableFormatDetection;
    if (not detect_input_format(pixel_format, video_input_flags, display_mode, _frame_rate, error_msg))
        bail(error_msg);

    // Enable video input
    res = _deck_link_input->EnableVideoInput(display_mode,
                                             pixel_format,
                                             video_input_flags);
    // No glory
    if (res != S_OK)
        bail("Could not enable video input of Blackmagic DeckLink device");

    // Start streaming
    _running = true;
    res = _deck_link_input->StartStreams();
    // No glory: release everything and throw exception
    if (res != S_OK)
    {
        _running = false;
        bail("Could not start streaming from the Blackmagic DeckLink device");
    }
}

VideoSourceBlackmagicSDK::~VideoSourceBlackmagicSDK()
{
    // Make sure streamer thread not trying to access buffer
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);
    _running = false;

    // Stop streaming and disable enabled inputs
    _deck_link_input->StopStreams();
    _deck_link_input->DisableVideoInput();

    // Release DeckLink members
    release_deck_link();
}

bool VideoSourceBlackmagicSDK::get_frame_dimensions(int & width, int & height)
{
    // Make sure only this thread is accessing the cols and rows members now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);
    if (_cols <= 0 or _rows <= 0)
        return false;

    width = _cols;
    height = _rows;
    return true;
}

bool VideoSourceBlackmagicSDK::get_frame(VideoFrame & frame)
{
    if (frame.colour() != _colour)
        return false;

    // Make sure only this thread is accessing the video frame data now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);

    if (_video_buffer_length > 0 and _cols > 0 and _rows > 0)
    {
        frame.init_from_specs(_video_buffer, _video_buffer_length, _cols, _rows);
        return true;
    }
    else
        return false;
}

double VideoSourceBlackmagicSDK::get_frame_rate()
{
    return _frame_rate;
}

void VideoSourceBlackmagicSDK::set_sub_frame(int x, int y, int width, int height)
{
    // TODO
}

void VideoSourceBlackmagicSDK::get_full_frame()
{
    // TODO
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::QueryInterface(REFIID iid, LPVOID * ppv)
{
    return E_NOINTERFACE;
}

ULONG STDMETHODCALLTYPE VideoSourceBlackmagicSDK::AddRef(void)
{
    __sync_add_and_fetch(&_n_ref, 1);
    return _n_ref;
}

ULONG STDMETHODCALLTYPE VideoSourceBlackmagicSDK::Release(void)
{
    __sync_sub_and_fetch(&_n_ref, 1);
    return _n_ref;
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::VideoInputFormatChanged(
    BMDVideoInputFormatChangedEvents events,
    IDeckLinkDisplayMode * display_mode,
    BMDDetectedVideoInputFormatFlags format_flags
)
{
    // TODO
}

HRESULT STDMETHODCALLTYPE VideoSourceBlackmagicSDK::VideoInputFrameArrived(
    IDeckLinkVideoInputFrame * video_frame,
    IDeckLinkAudioInputPacket * audio_packet
)
{
    // Not processing the audio packet, but only the video
    // frame for the time being
    if (video_frame == nullptr)
        // nop if no data
        return S_OK;

    // Nr. of bytes of received data
    size_t n_bytes = video_frame->GetRowBytes() * video_frame->GetHeight();

    // Make sure only this thread is accessing the buffer now
    std::lock_guard<std::mutex> data_lock_guard(_data_lock);

    // Extend buffer if more memory needed than already allocated
    if (n_bytes > _video_buffer_length)
        _video_buffer = reinterpret_cast<uint8_t *>(
                    realloc(_video_buffer, n_bytes * sizeof(uint8_t))
        );
    if (_video_buffer == nullptr) // something's terribly wrong!
        // nop if something's terribly wrong!
        return S_OK;

    // Get the new data into the buffer
    HRESULT res = video_frame->GetBytes(
        reinterpret_cast<void **>(&_video_buffer)
    );
    // If data could not be read into the buffer, return
    if (FAILED(res))
        return res;
    // Set video frame specs according to new data
    _video_buffer_length = n_bytes;
    _cols = video_frame->GetWidth();
    _rows = video_frame->GetHeight();

    // Propagate new video frame to observers
    _buffer_video_frame.init_from_specs(
        _video_buffer, _video_buffer_length, _cols, _rows
    );
    this->notify(_buffer_video_frame);

    // Everything went fine, return success
    return S_OK;
}

void VideoSourceBlackmagicSDK::release_deck_link() noexcept
{
    if (_deck_link_input != nullptr)
    {
        _deck_link_input->Release();
        _deck_link_input = nullptr;
    }

    if (_deck_link != nullptr)
        _deck_link->Release();
}

bool VideoSourceBlackmagicSDK::detect_input_format(BMDPixelFormat pixel_format,
                                                   BMDVideoInputFlags video_input_flags,
                                                   BMDDisplayMode & display_mode,
                                                   double & frame_rate,
                                                   std::string & error_msg) noexcept
{
    // These are output and result variables
    BMDDisplayModeSupport display_mode_support;
    IDeckLinkDisplayMode * deck_link_display_mode = nullptr;
    HRESULT res;
    bool detected = true;

    // TODO
    BMDDisplayMode display_mode_ = bmdModeHD1080i6000;

    // Check whether the mode is supported
    res = _deck_link_input->DoesSupportVideoMode(
        display_mode_, pixel_format, video_input_flags,
        &display_mode_support, &deck_link_display_mode
    );
    // No glory (could not even check mode support)
    if (res != S_OK or deck_link_display_mode == nullptr)
    {
        detected = false;
        error_msg = "Could not check video mode support of Blackmagic DeckLink device";
    }
    else
    {
        // If mode supported, then get frame rate
        if (display_mode_support == bmdDisplayModeSupported)
        {
            // Get frame rate of DeckLink device
            BMDTimeValue frame_rate_duration, frame_rate_scale;
            res = deck_link_display_mode->GetFrameRate(&frame_rate_duration, &frame_rate_scale);
            // No glory
            if (res != S_OK)
            {
                detected = false;
                error_msg = "Could not infer frame rate of Blackmagic DeckLink device";
            }
            else
                frame_rate = (double) frame_rate_scale / (double) frame_rate_duration;
        }
        else
        {
            detected = false;
            // TODO
            error_msg = "TODO";
        }
    }

    // Release the DeckLink display mode object
    if (deck_link_display_mode != nullptr)
    {
        deck_link_display_mode->Release();
        deck_link_display_mode = nullptr;
    }

    if (detected)
        display_mode = display_mode_;

    return detected;
}

}
<|endoftext|>


<commit_before>/*
  This file is part of KDE Kontact.

  Copyright (C) 2003 Cornelius Schumacher <schumacher@kde.org>

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

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

  You should have received a copy of the GNU General Public License
  along with this program; see the file COPYING.  If not, write to
  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  Boston, MA 02111-1307, USA.
 */

#include <qptrlist.h>
#include <qwidgetstack.h>
#include <qsignal.h>
#include <qobjectlist.h>
#include <qlabel.h>
#include <qimage.h>
#include <qpainter.h>
#include <qbitmap.h>
#include <qfontmetrics.h>
#include <qsignalmapper.h>
#include <qstyle.h>
#include <qframe.h>
#include <qdrawutil.h>

#include <kpopupmenu.h>
#include <kapplication.h>
#include <kdialog.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kimageeffect.h>
#include <sidebarextension.h>

#include <kdebug.h>

#include "mainwindow.h"

#include "plugin.h"

#include "prefs.h"
#include "iconsidepane.h"

namespace Kontact
{

//ugly wrapper class for adding an operator< to the Plugin class

class PluginProxy
{
  public:
    PluginProxy()
      : mPlugin( 0 )
    { }

    PluginProxy( Plugin *plugin )
      : mPlugin( plugin )
    { }

    PluginProxy & operator=( Plugin *plugin )
    {
      mPlugin = plugin;
      return *this;
    }

    bool operator<( PluginProxy &rhs ) const
    {
      return mPlugin->weight() < rhs.mPlugin->weight();
    }

    Plugin *plugin() const
    {
      return mPlugin;
    }

  private:
    Plugin *mPlugin;
};

} //namespace

using namespace Kontact;

EntryItem::EntryItem( Navigator *parent, Kontact::Plugin *plugin )
  : QListBoxItem( parent ),
    mPlugin( plugin )
{
  reloadPixmap();
  setCustomHighlighting( true );
  setText( plugin->title() );
}

EntryItem::~EntryItem()
{
}

void EntryItem::reloadPixmap()
{
  int size = (int)navigator()->viewMode();
  if ( size != 0 )
    mPixmap = KGlobal::iconLoader()->loadIcon( mPlugin->icon(),
                                               KIcon::Desktop, size );
  else
    mPixmap = QPixmap();
}

Navigator* EntryItem::navigator() const
{
  return static_cast<Navigator*>( listBox() );
}

int EntryItem::width( const QListBox *listbox ) const
{
  int w;
  if ( text().isEmpty() )
    w = mPixmap.width();
  else if (navigator()->viewMode() > SmallIcons)
    w = QMAX( (int)navigator()->viewMode(), listbox->fontMetrics().width( text() ) );
  else
    w = (int)navigator()->viewMode() + 4 + listbox->fontMetrics().width( text() );

  return w + ( KDialog::marginHint() * 2 );
}

int EntryItem::height( const QListBox *listbox ) const
{
  int h;
  if ( text().isEmpty() )
    h = mPixmap.height();
  else if (navigator()->viewMode() > SmallIcons)
    h = (int)navigator()->viewMode() + listbox->fontMetrics().lineSpacing();
  else
    h = QMAX( (int)navigator()->viewMode(), listbox->fontMetrics().lineSpacing() );

  return h + 4;
}

void EntryItem::paint( QPainter *p )
{
  reloadPixmap();

  QListBox *box = listBox();
  bool iconAboveText = navigator()->viewMode() > SmallIcons;
  int w = box->viewport()->width();
  int y = 2;

  // we'll only do neat things when we have enough color depth
  // because things like gradients look ugly without it
  bool beFancy = QPixmap::defaultDepth() > 14;

  // draw selected
  if ( isCurrent() || isSelected() ) {
    if ( beFancy ) {
      int h = height( box );
      bool reverse = QApplication::reverseLayout();
      QImage gradient = KImageEffect::gradient( QSize( w, h ),
                                                reverse ? box->colorGroup().highlight() :
                                                          box->colorGroup().mid(),
                                                reverse ? box->colorGroup().mid() :
                                                          box->colorGroup().highlight(),
                                                KImageEffect::HorizontalGradient );
      p->drawImage( 0, 0, gradient );
      QPen pen = p->pen();
      QPen oldPen = pen;
      pen.setWidth( 1 );
      pen.setColor( box->colorGroup().mid() );
      p->setPen( pen );

      if ( reverse ) {
        p->drawPoint( 0, 0 );
        p->drawPoint( 0, h - 1 );
      }
      else {
        p->drawPoint( w - 1, 0 );
        p->drawPoint( w - 1, h - 1 );
      }

      p->setPen( oldPen );
    }
    else {
      QColorGroup group = box->colorGroup();
      group.setColor( QColorGroup::Dark, Qt::black );
      qDrawShadePanel( p, 1, 0, w - 2, height( box ),
                       group, true, 1, 0 );
    }
  }

  if ( !mPixmap.isNull() ) {
    int x = iconAboveText ? ( ( w - mPixmap.width() ) / 2 ) : KDialog::marginHint();
    p->drawPixmap( x, y, mPixmap );
  }

  QColor shadowColor = listBox()->colorGroup().background().dark(115);
  if ( isCurrent() || isSelected() ) {
    p->setPen( box->colorGroup().highlightedText() );
  }

  if ( !text().isEmpty() ) {
    QFontMetrics fm = p->fontMetrics();

    int x = 0;
    if (iconAboveText) {
      x = ( w - fm.width( text() ) ) / 2;
      y += fm.height() - fm.descent() + mPixmap.height();
    }
    else {
      x = KDialog::marginHint() + mPixmap.width() + 4;

      if ( mPixmap.height() < fm.height() )
        y += fm.ascent() + fm.leading()/2;
      else
        y += mPixmap.height()/2 - fm.height()/2 + fm.ascent();
    }

    if ( isCurrent() || isSelected() ) {
      if ( beFancy ) {
        p->setPen( box->colorGroup().highlight().dark(115) );
        p->drawText( x + ( QApplication::reverseLayout() ? -1 : 1),
                     y + 1, text() );
      }
      p->setPen( box->colorGroup().highlightedText() );
    }
    else
      p->setPen( box->colorGroup().text() );

    p->drawText( x, y, text() );
  }
}

Navigator::Navigator( SidePaneBase *parent, const char *name )
  : KListBox( parent, name ), mSidePane( parent )
{
  mViewMode = sizeIntToEnum( Prefs::self()->sidePaneIconSize() );
  setSelectionMode( KListBox::Single );
  viewport()->setBackgroundMode( PaletteMid );
  setHScrollBarMode( QScrollView::AlwaysOff );
  setAcceptDrops( true );

  setFocusPolicy( NoFocus );

  connect( this, SIGNAL( selectionChanged( QListBoxItem* ) ),
           SLOT( slotExecuted( QListBoxItem* ) ) );

  connect( this, SIGNAL( rightButtonPressed( QListBoxItem*, const QPoint& ) ),
           SLOT( slotShowRMBMenu( QListBoxItem*, const QPoint& ) ) );

  mMapper = new QSignalMapper( this );
  connect( mMapper, SIGNAL( mapped( int ) ), SLOT( shortCutSelected( int ) ) );
}

QSize Navigator::sizeHint() const
{
  return QSize( 100, 100 );
}

void Navigator::setSelected( QListBoxItem *item, bool selected )
{
  // Reimplemented to avoid the immediate activation of
  // the item. might turn out it doesn't work, we check that
  // an confirm from MainWindow::selectPlugin()
  if ( selected ) {
    EntryItem *entry = static_cast<EntryItem*>( item );
    emit pluginActivated( entry->plugin() );
  }
}

void Navigator::updatePlugins( QValueList<Kontact::Plugin*> plugins_ )
{
  QValueList<Kontact::PluginProxy> plugins;
  QValueList<Kontact::Plugin*>::ConstIterator end_ = plugins_.end();
  QValueList<Kontact::Plugin*>::ConstIterator it_ = plugins_.begin();
  for ( ; it_ != end_; ++it_ )
    plugins += PluginProxy( *it_ );

  clear();

  mActions.setAutoDelete( true );
  mActions.clear();
  mActions.setAutoDelete( false );

  int counter = 0;
  int minWidth = 0;
  qBubbleSort( plugins );
  QValueList<Kontact::PluginProxy>::ConstIterator end = plugins.end();
  QValueList<Kontact::PluginProxy>::ConstIterator it = plugins.begin();
  for ( ; it != end; ++it ) {
    Kontact::Plugin *plugin = ( *it ).plugin();
    if ( !plugin->showInSideBar() )
      continue;

    EntryItem *item = new EntryItem( this, plugin );

    if ( item->width( this ) > minWidth )
      minWidth = item->width( this );

    QString name = QString( "CTRL+%1" ).arg( counter + 1 );
    KAction *action = new KAction( plugin->title(), KShortcut( name ),
                                   mMapper, SLOT( map() ),
                                   mSidePane->actionCollection(), name.latin1() );
    mMapper->setMapping( action, counter );
    counter++;
  }

  parentWidget()->setFixedWidth( minWidth );
}

void Navigator::dragEnterEvent( QDragEnterEvent *event )
{
  kdDebug(5600) << "Navigator::dragEnterEvent()" << endl;

  dragMoveEvent( event );
}

void Navigator::dragMoveEvent( QDragMoveEvent *event )
{
  kdDebug(5600) << "Navigator::dragEnterEvent()" << endl;

  kdDebug(5600) << "  Format: " << event->format() << endl;

  QListBoxItem *item = itemAt( event->pos() );

  if ( !item ) {
    event->accept( false );
    return;
  }

  EntryItem *entry = static_cast<EntryItem*>( item );

  kdDebug(5600) << "  PLUGIN: " << entry->plugin()->identifier() << endl;

  event->accept( entry->plugin()->canDecodeDrag( event ) );
}

void Navigator::dropEvent( QDropEvent *event )
{
  kdDebug(5600) << "Navigator::dropEvent()" << endl;

  QListBoxItem *item = itemAt( event->pos() );

  if ( !item ) {
    return;
  }

  EntryItem *entry = static_cast<EntryItem*>( item );

  kdDebug(5600) << "  PLUGIN: " << entry->plugin()->identifier() << endl;

  entry->plugin()->processDropEvent( event );
}

void Navigator::resizeEvent( QResizeEvent *event )
{
  QListBox::resizeEvent( event );
  triggerUpdate( true );
}

void Navigator::slotExecuted( QListBoxItem *item )
{
  if ( !item )
    return;

  EntryItem *entry = static_cast<EntryItem*>( item );

  emit pluginActivated( entry->plugin() );
}

IconViewMode Navigator::sizeIntToEnum(int size) const
{
  switch ( size ) {
    case int(LargeIcons):
      return LargeIcons;
      break;
    case int(NormalIcons):
      return NormalIcons;
      break;
    case int(SmallIcons):
      return SmallIcons;
      break;
    case int(TextOnly):
      return TextOnly;
      break;
    default:
      // Stick with sane values
      return NormalIcons;
      kdDebug() << "View mode not implemented!" << endl;
      break;
  }
}

void Navigator::slotShowRMBMenu( QListBoxItem *, const QPoint &pos )
{
  KPopupMenu menu;
  menu.insertTitle( i18n( "Icon Size" ) );
  menu.insertItem( i18n( "Large" ), (int)LargeIcons );
  menu.insertItem( i18n( "Normal" ), (int)NormalIcons );
  menu.insertItem( i18n( "Small" ), (int)SmallIcons );
  menu.insertItem( i18n( "Text Only" ), (int)TextOnly );
  int choice = menu.exec( pos );

  if ( choice == -1 )
    return;

  mViewMode = sizeIntToEnum( choice );
  Prefs::self()->setSidePaneIconSize( choice );

  int maxWidth = 0;
  QListBoxItem* it = 0;
  for (int i = 0; (it = item(i)) != 0; ++i)
  {
    int width = it->width(this);
    if (width > maxWidth)
      maxWidth = width;
  }
  parentWidget()->setFixedWidth( maxWidth );

  triggerUpdate( true );
}

void Navigator::shortCutSelected( int pos )
{
  setCurrentItem( pos );
}

IconSidePane::IconSidePane( Core *core, QWidget *parent, const char *name )
  : SidePaneBase( core, parent, name )
{
  mNavigator = new Navigator( this );
  connect( mNavigator, SIGNAL( pluginActivated( Kontact::Plugin* ) ),
           SIGNAL( pluginSelected( Kontact::Plugin* ) ) );

  setAcceptDrops( true );
}

IconSidePane::~IconSidePane()
{
}

void IconSidePane::updatePlugins()
{
  mNavigator->updatePlugins( core()->pluginList() );
}

void IconSidePane::selectPlugin( Kontact::Plugin *plugin )
{
  bool blocked = signalsBlocked();
  blockSignals( true );

  uint i;
  for ( i = 0; i < mNavigator->count(); ++i ) {
    EntryItem *item = static_cast<EntryItem*>( mNavigator->item( i ) );
    if ( item->plugin() == plugin ) {
      mNavigator->setCurrentItem( i );
      break;
    }
  }

  blockSignals( blocked );
}

void IconSidePane::selectPlugin( const QString &name )
{
  bool blocked = signalsBlocked();
  blockSignals( true );

  uint i;
  for ( i = 0; i < mNavigator->count(); ++i ) {
    EntryItem *item = static_cast<EntryItem*>( mNavigator->item( i ) );
    if ( item->plugin()->identifier() == name ) {
      mNavigator->setCurrentItem( i );
      break;
    }
  }

  blockSignals( blocked );
}

#include "iconsidepane.moc"

// vim: sw=2 sts=2 et tw=80
<commit_msg>today's look: shadowed text served on a bed of solid background, gently rounded and accented with a tangy raspberry sauce. this quicker, slightly calmer look, is kind on the waistline and the palette.<commit_after>/*
  This file is part of KDE Kontact.

  Copyright (C) 2003 Cornelius Schumacher <schumacher@kde.org>

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

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

  You should have received a copy of the GNU General Public License
  along with this program; see the file COPYING.  If not, write to
  the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  Boston, MA 02111-1307, USA.
 */

#include <qptrlist.h>
#include <qwidgetstack.h>
#include <qsignal.h>
#include <qobjectlist.h>
#include <qlabel.h>
#include <qimage.h>
#include <qpainter.h>
#include <qbitmap.h>
#include <qfontmetrics.h>
#include <qsignalmapper.h>
#include <qstyle.h>
#include <qframe.h>
#include <qdrawutil.h>

#include <kpopupmenu.h>
#include <kapplication.h>
#include <kdialog.h>
#include <klocale.h>
#include <kiconloader.h>
#include <sidebarextension.h>

#include <kdebug.h>

#include "mainwindow.h"

#include "plugin.h"

#include "prefs.h"
#include "iconsidepane.h"

namespace Kontact
{

//ugly wrapper class for adding an operator< to the Plugin class

class PluginProxy
{
  public:
    PluginProxy()
      : mPlugin( 0 )
    { }

    PluginProxy( Plugin *plugin )
      : mPlugin( plugin )
    { }

    PluginProxy & operator=( Plugin *plugin )
    {
      mPlugin = plugin;
      return *this;
    }

    bool operator<( PluginProxy &rhs ) const
    {
      return mPlugin->weight() < rhs.mPlugin->weight();
    }

    Plugin *plugin() const
    {
      return mPlugin;
    }

  private:
    Plugin *mPlugin;
};

} //namespace

using namespace Kontact;

EntryItem::EntryItem( Navigator *parent, Kontact::Plugin *plugin )
  : QListBoxItem( parent ),
    mPlugin( plugin )
{
  reloadPixmap();
  setCustomHighlighting( true );
  setText( plugin->title() );
}

EntryItem::~EntryItem()
{
}

void EntryItem::reloadPixmap()
{
  int size = (int)navigator()->viewMode();
  if ( size != 0 )
    mPixmap = KGlobal::iconLoader()->loadIcon( mPlugin->icon(),
                                               KIcon::Desktop, size );
  else
    mPixmap = QPixmap();
}

Navigator* EntryItem::navigator() const
{
  return static_cast<Navigator*>( listBox() );
}

int EntryItem::width( const QListBox *listbox ) const
{
  int w;
  if ( text().isEmpty() )
    w = mPixmap.width();
  else if (navigator()->viewMode() > SmallIcons)
    w = QMAX( (int)navigator()->viewMode(), listbox->fontMetrics().width( text() ) );
  else
    w = (int)navigator()->viewMode() + 4 + listbox->fontMetrics().width( text() );

  return w + ( KDialog::marginHint() * 2 );
}

int EntryItem::height( const QListBox *listbox ) const
{
  int h;
  if ( text().isEmpty() )
    h = mPixmap.height();
  else if (navigator()->viewMode() > SmallIcons)
    h = (int)navigator()->viewMode() + listbox->fontMetrics().lineSpacing();
  else
    h = QMAX( (int)navigator()->viewMode(), listbox->fontMetrics().lineSpacing() );

  return h + 4;
}

void EntryItem::paint( QPainter *p )
{
  reloadPixmap();

  QListBox *box = listBox();
  bool iconAboveText = navigator()->viewMode() > SmallIcons;
  int w = box->viewport()->width();
  int y = 2;

  // draw selected
  if ( isCurrent() || isSelected() ) {
    int h = height( box );

    QBrush brush = box->colorGroup().brush( QColorGroup::Highlight );
    brush.setColor( brush.color().light( 115 ) );
    p->fillRect( 1, 0, w - 2, h - 1, brush );
    QPen pen = p->pen();
    QPen oldPen = pen;
    pen.setColor( box->colorGroup().mid() );
    p->setPen( pen );

    p->drawPoint( 1, 0 );
    p->drawPoint( 1, h - 2 );
    p->drawPoint( w - 2, 0 );
    p->drawPoint( w - 2, h - 2 );

    p->setPen( oldPen );
  }

  if ( !mPixmap.isNull() ) {
      int x = iconAboveText ? ( ( w - mPixmap.width() ) / 2 ) : KDialog::marginHint();
    p->drawPixmap( x, y, mPixmap );
  }

  QColor shadowColor = listBox()->colorGroup().background().dark(115);
  if ( isCurrent() || isSelected() ) {
    p->setPen( box->colorGroup().highlightedText() );
  }

  if ( !text().isEmpty() ) {
    QFontMetrics fm = p->fontMetrics();

    int x = 0;
    if (iconAboveText) {
      x = ( w - fm.width( text() ) ) / 2;
      y += fm.height() - fm.descent() + mPixmap.height();
    }
    else {
      x = KDialog::marginHint() + mPixmap.width() + 4;

      if ( mPixmap.height() < fm.height() )
        y += fm.ascent() + fm.leading()/2;
      else
        y += mPixmap.height()/2 - fm.height()/2 + fm.ascent();
    }

    if ( isCurrent() || isSelected() ) {
      p->setPen( box->colorGroup().highlight().dark(115) );
      p->drawText( x + ( QApplication::reverseLayout() ? -1 : 1),
                   y + 1, text() );
      p->setPen( box->colorGroup().highlightedText() );
    }
    else
      p->setPen( box->colorGroup().text() );

    p->drawText( x, y, text() );
  }
}

Navigator::Navigator( SidePaneBase *parent, const char *name )
  : KListBox( parent, name ), mSidePane( parent )
{
  mViewMode = sizeIntToEnum( Prefs::self()->sidePaneIconSize() );
  setSelectionMode( KListBox::Single );
  viewport()->setBackgroundMode( PaletteMid );
  setHScrollBarMode( QScrollView::AlwaysOff );
  setAcceptDrops( true );

  setFocusPolicy( NoFocus );

  connect( this, SIGNAL( selectionChanged( QListBoxItem* ) ),
           SLOT( slotExecuted( QListBoxItem* ) ) );

  connect( this, SIGNAL( rightButtonPressed( QListBoxItem*, const QPoint& ) ),
           SLOT( slotShowRMBMenu( QListBoxItem*, const QPoint& ) ) );

  mMapper = new QSignalMapper( this );
  connect( mMapper, SIGNAL( mapped( int ) ), SLOT( shortCutSelected( int ) ) );
}

QSize Navigator::sizeHint() const
{
  return QSize( 100, 100 );
}

void Navigator::setSelected( QListBoxItem *item, bool selected )
{
  // Reimplemented to avoid the immediate activation of
  // the item. might turn out it doesn't work, we check that
  // an confirm from MainWindow::selectPlugin()
  if ( selected ) {
    EntryItem *entry = static_cast<EntryItem*>( item );
    emit pluginActivated( entry->plugin() );
  }
}

void Navigator::updatePlugins( QValueList<Kontact::Plugin*> plugins_ )
{
  QValueList<Kontact::PluginProxy> plugins;
  QValueList<Kontact::Plugin*>::ConstIterator end_ = plugins_.end();
  QValueList<Kontact::Plugin*>::ConstIterator it_ = plugins_.begin();
  for ( ; it_ != end_; ++it_ )
    plugins += PluginProxy( *it_ );

  clear();

  mActions.setAutoDelete( true );
  mActions.clear();
  mActions.setAutoDelete( false );

  int counter = 0;
  int minWidth = 0;
  qBubbleSort( plugins );
  QValueList<Kontact::PluginProxy>::ConstIterator end = plugins.end();
  QValueList<Kontact::PluginProxy>::ConstIterator it = plugins.begin();
  for ( ; it != end; ++it ) {
    Kontact::Plugin *plugin = ( *it ).plugin();
    if ( !plugin->showInSideBar() )
      continue;

    EntryItem *item = new EntryItem( this, plugin );

    if ( item->width( this ) > minWidth )
      minWidth = item->width( this );

    QString name = QString( "CTRL+%1" ).arg( counter + 1 );
    KAction *action = new KAction( plugin->title(), KShortcut( name ),
                                   mMapper, SLOT( map() ),
                                   mSidePane->actionCollection(), name.latin1() );
    mMapper->setMapping( action, counter );
    counter++;
  }

  parentWidget()->setFixedWidth( minWidth );
}

void Navigator::dragEnterEvent( QDragEnterEvent *event )
{
  kdDebug(5600) << "Navigator::dragEnterEvent()" << endl;

  dragMoveEvent( event );
}

void Navigator::dragMoveEvent( QDragMoveEvent *event )
{
  kdDebug(5600) << "Navigator::dragEnterEvent()" << endl;

  kdDebug(5600) << "  Format: " << event->format() << endl;

  QListBoxItem *item = itemAt( event->pos() );

  if ( !item ) {
    event->accept( false );
    return;
  }

  EntryItem *entry = static_cast<EntryItem*>( item );

  kdDebug(5600) << "  PLUGIN: " << entry->plugin()->identifier() << endl;

  event->accept( entry->plugin()->canDecodeDrag( event ) );
}

void Navigator::dropEvent( QDropEvent *event )
{
  kdDebug(5600) << "Navigator::dropEvent()" << endl;

  QListBoxItem *item = itemAt( event->pos() );

  if ( !item ) {
    return;
  }

  EntryItem *entry = static_cast<EntryItem*>( item );

  kdDebug(5600) << "  PLUGIN: " << entry->plugin()->identifier() << endl;

  entry->plugin()->processDropEvent( event );
}

void Navigator::resizeEvent( QResizeEvent *event )
{
  QListBox::resizeEvent( event );
  triggerUpdate( true );
}

void Navigator::slotExecuted( QListBoxItem *item )
{
  if ( !item )
    return;

  EntryItem *entry = static_cast<EntryItem*>( item );

  emit pluginActivated( entry->plugin() );
}

IconViewMode Navigator::sizeIntToEnum(int size) const
{
  switch ( size ) {
    case int(LargeIcons):
      return LargeIcons;
      break;
    case int(NormalIcons):
      return NormalIcons;
      break;
    case int(SmallIcons):
      return SmallIcons;
      break;
    case int(TextOnly):
      return TextOnly;
      break;
    default:
      // Stick with sane values
      return NormalIcons;
      kdDebug() << "View mode not implemented!" << endl;
      break;
  }
}

void Navigator::slotShowRMBMenu( QListBoxItem *, const QPoint &pos )
{
  KPopupMenu menu;
  menu.insertTitle( i18n( "Icon Size" ) );
  menu.insertItem( i18n( "Large" ), (int)LargeIcons );
  menu.insertItem( i18n( "Normal" ), (int)NormalIcons );
  menu.insertItem( i18n( "Small" ), (int)SmallIcons );
  menu.insertItem( i18n( "Text Only" ), (int)TextOnly );
  int choice = menu.exec( pos );

  if ( choice == -1 )
    return;

  mViewMode = sizeIntToEnum( choice );
  Prefs::self()->setSidePaneIconSize( choice );

  int maxWidth = 0;
  QListBoxItem* it = 0;
  for (int i = 0; (it = item(i)) != 0; ++i)
  {
    int width = it->width(this);
    if (width > maxWidth)
      maxWidth = width;
  }
  parentWidget()->setFixedWidth( maxWidth );

  triggerUpdate( true );
}

void Navigator::shortCutSelected( int pos )
{
  setCurrentItem( pos );
}

IconSidePane::IconSidePane( Core *core, QWidget *parent, const char *name )
  : SidePaneBase( core, parent, name )
{
  mNavigator = new Navigator( this );
  connect( mNavigator, SIGNAL( pluginActivated( Kontact::Plugin* ) ),
           SIGNAL( pluginSelected( Kontact::Plugin* ) ) );

  setAcceptDrops( true );
}

IconSidePane::~IconSidePane()
{
}

void IconSidePane::updatePlugins()
{
  mNavigator->updatePlugins( core()->pluginList() );
}

void IconSidePane::selectPlugin( Kontact::Plugin *plugin )
{
  bool blocked = signalsBlocked();
  blockSignals( true );

  uint i;
  for ( i = 0; i < mNavigator->count(); ++i ) {
    EntryItem *item = static_cast<EntryItem*>( mNavigator->item( i ) );
    if ( item->plugin() == plugin ) {
      mNavigator->setCurrentItem( i );
      break;
    }
  }

  blockSignals( blocked );
}

void IconSidePane::selectPlugin( const QString &name )
{
  bool blocked = signalsBlocked();
  blockSignals( true );

  uint i;
  for ( i = 0; i < mNavigator->count(); ++i ) {
    EntryItem *item = static_cast<EntryItem*>( mNavigator->item( i ) );
    if ( item->plugin()->identifier() == name ) {
      mNavigator->setCurrentItem( i );
      break;
    }
  }

  blockSignals( blocked );
}

#include "iconsidepane.moc"

// vim: sw=2 sts=2 et tw=80
<|endoftext|>