<commit_before>/*
This file is part of CanFestival, a library implementing CanOpen Stack.

CanFestival Copyright (C): Edouard TISSERANT and Francis DUPIN
CanFestival Win32 port Copyright (C) 2007 Leonid Tochinski, ChattenAssociates, Inc.

See COPYING file for copyrights details.

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

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

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
// pragma based message
// http://www.codeproject.com/macro/location_pragma.asp
#define __STR2__(x) #x
#define __STR1__(x) __STR2__(x)
#define __LOC2__ __FILE__ "("__STR1__(__LINE__)") : "

#pragma message("*********************************************************************************")
#pragma message("  NOTE: IXXAT Win32 drivers and API should be installed in order to build this project!")
#pragma message(__LOC2__ "See IXXAT.Cpp header for details.")
#pragma message("*********************************************************************************")

// IXXAT adapter driver for CanFestival-3 Win32 port
//
// Notes
//--------------------------------------------
// For building of this project you will need
// the following IXXAT API files
// Vci2.h
// Vci11un6.lib
//
// IXXAT Win32 drivers and API can be downloaded from
// http://www.ixxat.com/download_vci_en,7547,5873.html
//
// Copy Vci2.h & Vci11un6.lib files to can_ixxat_win32 folder of add path to them in Project settings.

#include <stdio.h>
extern "C" {
#include "applicfg.h"
#include "can_driver.h"
#include "def.h"
}
#include "VCI2.h"
#include "async_access_que.h"

#pragma warning(disable:4996)

#define CAN_NUM 0

class IXXAT
   {
   public:
      class error
        {
        };
      IXXAT(s_BOARD *board);
      ~IXXAT();
      bool send(const Message *m);
      bool receive(Message *m);
   private:
      bool open(const char* board_name, int board_number, const char* baud_rate);
      bool close();
      void receive_queuedata(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ* p_obj);
      // VCI2 handler
      static void VCI_CALLBACKATTR message_handler(char *msg_str);
      static void VCI_CALLBACKATTR receive_queuedata_handler(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ* p_obj);
      static void VCI_CALLBACKATTR exception_handler(VCI_FUNC_NUM func_num, INT32 err_code, UINT16 ext_err, char* err_str);

   private:
      UINT16 m_BoardHdl;
      UINT16 m_TxQueHdl;
      UINT16 m_RxQueHdl;
      async_access_que<VCI_CAN_OBJ> m_RX_Que;
      static IXXAT* m_callbackPtr;
   };

IXXAT *IXXAT::m_callbackPtr = NULL;

IXXAT::IXXAT(s_BOARD *board) : m_BoardHdl(0xFFFF),
                               m_TxQueHdl(0xFFFF),
                               m_RxQueHdl(0xFFFF)

   {
   char busname[100];
   ::strcpy(busname,board->busname);
   char board_name[100];
   long board_number = 0;
   char *ptr = ::strrchr(busname,':');
   if (ptr != 0)
      {
      *ptr = 0;
      ::strcpy(board_name,busname);
      if (++ptr - busname < (int)::strlen(board->busname))
         board_number = ::atoi(ptr);
      }
   if (!open(board_name,board_number,board->baudrate))
      {
      close();
      throw error();
      }
   m_callbackPtr = this;
   }

IXXAT::~IXXAT()
   {
   close();
   m_callbackPtr = 0;
   }

bool IXXAT::send(const Message *m)
   {
   if (m_BoardHdl == 0xFFFF)
      return true; // true -> NOT OK
   long res = VCI_ERR;
   if (m->rtr == NOT_A_REQUEST)
      res = VCI_TransmitObj(m_BoardHdl, m_TxQueHdl, m->cob_id, m->len, const_cast<unsigned char*>(m->data));
   else
      res = VCI_RequestObj(m_BoardHdl, m_TxQueHdl, m->cob_id, m->len);
   return (res == false); // false -> OK
   }

bool IXXAT::receive(Message *m)
   {
   if (m_BoardHdl == 0xFFFF)
      return false;
   VCI_CAN_OBJ obj;
   if (m_RX_Que.extract_top(obj))
      {
      m->cob_id = obj.id;
      m->len = obj.len;
      m->rtr = (obj.rtr == VCI_RX_BUF) ? NOT_A_REQUEST : REQUEST;
      if (m->rtr == NOT_A_REQUEST)
         ::memcpy(m->data, obj.a_data, m->len);
      return true;
      }
   return false;
   }

bool IXXAT::open(const char* board_name, int board_number, const char* baud_rate)
   {
   // check, if baudrate is supported
   struct IXXAT_baud_rate_param
     {
     UINT8  bt0;
     UINT8  bt1;
     };
   struct IXXAT_look_up_table
     {
     char baud_rate[20];
     IXXAT_baud_rate_param bt;
     };
   static const IXXAT_look_up_table br_lut[] = {
               {"10K",{VCI_10KB}},
               {"20K",{VCI_20KB}},
               {"50K",{VCI_50KB}},
               {"100K",{VCI_100KB}},
               {"125K",{VCI_125KB}},
               {"250K",{VCI_250KB}},
               {"500K",{VCI_500KB}},
               {"800K",{VCI_800KB}},
               {"1M",{VCI_1000KB}}
               };
   static const long br_lut_size = sizeof (br_lut)/sizeof(IXXAT_look_up_table);
   int index;
   for (index = 0; index < br_lut_size; ++index)
       {
       if (::strcmp(br_lut[index].baud_rate,baud_rate)==0)
          break;
       }
   if (index == br_lut_size)
      return false;
   // close existing board
   close();
   // init IXXAT board
   unsigned long board_type = VCI_GetBrdTypeByName(const_cast<char*>(board_name));
   long res = VCI2_PrepareBoard( board_type,                  // board type
                                   board_number,              // unique board index
                                   NULL,                      // pointer to buffer for additional info
                                   0,                         // length of additional info buffer
                                   message_handler,           // pointer to msg-callbackhandler
                                   receive_queuedata_handler, // pointer to receive-callbackhandler
                                   exception_handler);        // pointer to exception-callbackhandler
   if (res < 0)
      return false;
   m_BoardHdl = (UINT16)res;

   VCI_ResetBoard(m_BoardHdl);

   // init CAN parameters

   // initialize CAN-Controller
   res = VCI_InitCan(m_BoardHdl, CAN_NUM, br_lut[index].bt.bt0,br_lut[index].bt.bt1, VCI_11B);

   //  definition of Acceptance-Mask (define to receive all IDs)
   res = VCI_SetAccMask(m_BoardHdl, CAN_NUM, 0x0UL, 0x0UL);

   // definition of Transmit Queue
   res = VCI_ConfigQueue(m_BoardHdl, CAN_NUM, VCI_TX_QUE, 100 , 0, 0, 0,  &m_TxQueHdl);

   //  definition of Receive Queue (interrupt mode)
   res = VCI_ConfigQueue(m_BoardHdl, CAN_NUM, VCI_RX_QUE, 50, 1, 0, 100,  &m_RxQueHdl);

   //  assign the all IDs to the Receive Queue
   res = VCI_AssignRxQueObj(m_BoardHdl, m_RxQueHdl ,VCI_ACCEPT, 0, 0) ;

   //  And now start the CAN
   res = VCI_StartCan(m_BoardHdl, CAN_NUM);

   return true;
   }

bool IXXAT::close()
   {
   if (m_BoardHdl == 0xFFFF)
      return true;
   VCI_ResetBoard(m_BoardHdl);
   VCI_CancelBoard(m_BoardHdl);
   m_BoardHdl =
   m_TxQueHdl =
   m_RxQueHdl = 0xFFFF;
   return true;
   }

void IXXAT::receive_queuedata(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ *p_obj)
   {
   for (int i = 0; i < count; ++i)
       m_RX_Que.append(p_obj[i]); // can packet
   }

void VCI_CALLBACKATTR IXXAT::receive_queuedata_handler(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ *p_obj)
  {
   if (m_callbackPtr != NULL)
      m_callbackPtr->receive_queuedata(que_hdl, count, p_obj);
  }

void VCI_CALLBACKATTR IXXAT::message_handler(char *msg_str)
  {
  char buf[200];
  ::sprintf(buf,"IXXAT Message: [%s]\n", msg_str);
  ::OutputDebugString(buf);
  }

void VCI_CALLBACKATTR IXXAT::exception_handler(VCI_FUNC_NUM func_num, INT32 err_code, UINT16 ext_err, char* err_str)
  {
  static const char* Num2Function[] =
    {
    "VCI_Init",
    "VCI_Searchboard",
    "VCI_Prepareboard",
    "VCI_Cancel_board",
    "VCI_Testboard",
    "VCI_ReadBoardInfo",
    "VCI_ReadBoardStatus",
    "VCI_Resetboard",
    "VCI_ReadCANInfo",
    "VCI_ReadCANStatus",
    "VCI_InitCAN",
    "VCI_SetAccMask",
    "VCI_ResetCAN",
    "VCI_StartCAN",
    "VCI_ResetTimeStamps",
    "VCI_ConfigQueue",
    "VCI_AssignRxQueObj",
    "VCI_ConfigBuffer",
    "VCI_ReconfigBuffer",
    "VCI_ConfigTimer",
    "VCI_ReadQueStatus",
    "VCI_ReadQueObj",
    "VCI_ReadBufStatus",
    "VCI_ReadBufData",
    "VCI_TransmitObj",
    "VCI_RequestObj",
    "VCI_UpdateBufObj",
    "VCI_CciReqData"
    };
  char buf[200];
  ::sprintf(buf, "IXXAT Exception: %s (%i / %u) [%s]\n", Num2Function[func_num], err_code, ext_err, err_str);
  ::OutputDebugString(buf);
  }

//------------------------------------------------------------------------
extern "C"
   UNS8 __stdcall canReceive_driver(CAN_HANDLE inst, Message *m)
   {
   return (UNS8)reinterpret_cast<IXXAT*>(inst)->receive(m);
   }

extern "C"
   UNS8 __stdcall canSend_driver(CAN_HANDLE inst, Message const *m)
   {
   return (UNS8)reinterpret_cast<IXXAT*>(inst)->send(m);
   }

extern "C"
   CAN_HANDLE __stdcall canOpen_driver(s_BOARD *board)
   {
   try
      {
      return new IXXAT(board);
      }
   catch (IXXAT::error&)
      {
      return 0;
      }
   }

extern "C"
   int __stdcall canClose_driver(CAN_HANDLE inst)
   {
   delete reinterpret_cast<IXXAT*>(inst);
   return 1;
   }

extern "C"
   UNS8 __stdcall canChangeBaudRate_driver( CAN_HANDLE fd, char* baud)
	{
	//printf("canChangeBaudRate not yet supported by this driver\n");
	return 0;
	}
<commit_msg>CHANGED: - added explicit cast to remove compiler warning<commit_after>/*
This file is part of CanFestival, a library implementing CanOpen Stack.

CanFestival Copyright (C): Edouard TISSERANT and Francis DUPIN
CanFestival Win32 port Copyright (C) 2007 Leonid Tochinski, ChattenAssociates, Inc.

See COPYING file for copyrights details.

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

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

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
// pragma based message
// http://www.codeproject.com/macro/location_pragma.asp
#define __STR2__(x) #x
#define __STR1__(x) __STR2__(x)
#define __LOC2__ __FILE__ "("__STR1__(__LINE__)") : "

#pragma message("*********************************************************************************")
#pragma message("  NOTE: IXXAT Win32 drivers and API should be installed in order to build this project!")
#pragma message(__LOC2__ "See IXXAT.Cpp header for details.")
#pragma message("*********************************************************************************")

// IXXAT adapter driver for CanFestival-3 Win32 port
//
// Notes
//--------------------------------------------
// For building of this project you will need
// the following IXXAT API files
// Vci2.h
// Vci11un6.lib
//
// IXXAT Win32 drivers and API can be downloaded from
// http://www.ixxat.com/download_vci_en,7547,5873.html
//
// Copy Vci2.h & Vci11un6.lib files to can_ixxat_win32 folder of add path to them in Project settings.

#include <stdio.h>
extern "C" {
#include "applicfg.h"
#include "can_driver.h"
#include "def.h"
}
#include "VCI2.h"
#include "async_access_que.h"

#pragma warning(disable:4996)

#define CAN_NUM 0

class IXXAT
   {
   public:
      class error
        {
        };
      IXXAT(s_BOARD *board);
      ~IXXAT();
      bool send(const Message *m);
      bool receive(Message *m);
   private:
      bool open(const char* board_name, int board_number, const char* baud_rate);
      bool close();
      void receive_queuedata(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ* p_obj);
      // VCI2 handler
      static void VCI_CALLBACKATTR message_handler(char *msg_str);
      static void VCI_CALLBACKATTR receive_queuedata_handler(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ* p_obj);
      static void VCI_CALLBACKATTR exception_handler(VCI_FUNC_NUM func_num, INT32 err_code, UINT16 ext_err, char* err_str);

   private:
      UINT16 m_BoardHdl;
      UINT16 m_TxQueHdl;
      UINT16 m_RxQueHdl;
      async_access_que<VCI_CAN_OBJ> m_RX_Que;
      static IXXAT* m_callbackPtr;
   };

IXXAT *IXXAT::m_callbackPtr = NULL;

IXXAT::IXXAT(s_BOARD *board) : m_BoardHdl(0xFFFF),
                               m_TxQueHdl(0xFFFF),
                               m_RxQueHdl(0xFFFF)

   {
   char busname[100];
   ::strcpy(busname,board->busname);
   char board_name[100];
   long board_number = 0;
   char *ptr = ::strrchr(busname,':');
   if (ptr != 0)
      {
      *ptr = 0;
      ::strcpy(board_name,busname);
      if (++ptr - busname < (int)::strlen(board->busname))
         board_number = ::atoi(ptr);
      }
   if (!open(board_name,board_number,board->baudrate))
      {
      close();
      throw error();
      }
   m_callbackPtr = this;
   }

IXXAT::~IXXAT()
   {
   close();
   m_callbackPtr = 0;
   }

bool IXXAT::send(const Message *m)
   {
   if (m_BoardHdl == 0xFFFF)
      return true; // true -> NOT OK
   long res = VCI_ERR;
   if (m->rtr == NOT_A_REQUEST)
      res = VCI_TransmitObj(m_BoardHdl, m_TxQueHdl, m->cob_id, m->len, const_cast<unsigned char*>(m->data));
   else
      res = VCI_RequestObj(m_BoardHdl, m_TxQueHdl, m->cob_id, m->len);
   return (res == false); // false -> OK
   }

bool IXXAT::receive(Message *m)
   {
   if (m_BoardHdl == 0xFFFF)
      return false;
   VCI_CAN_OBJ obj;
   if (m_RX_Que.extract_top(obj))
      {
      m->cob_id = static_cast<UNS16>(obj.id); //valid for 11Bit ids
      m->len = obj.len;
      m->rtr = (obj.rtr == VCI_RX_BUF) ? NOT_A_REQUEST : REQUEST;
      if (m->rtr == NOT_A_REQUEST)
         ::memcpy(m->data, obj.a_data, m->len);
      return true;
      }
   return false;
   }

bool IXXAT::open(const char* board_name, int board_number, const char* baud_rate)
   {
   // check, if baudrate is supported
   struct IXXAT_baud_rate_param
     {
     UINT8  bt0;
     UINT8  bt1;
     };
   struct IXXAT_look_up_table
     {
     char baud_rate[20];
     IXXAT_baud_rate_param bt;
     };
   static const IXXAT_look_up_table br_lut[] = {
               {"10K",{VCI_10KB}},
               {"20K",{VCI_20KB}},
               {"50K",{VCI_50KB}},
               {"100K",{VCI_100KB}},
               {"125K",{VCI_125KB}},
               {"250K",{VCI_250KB}},
               {"500K",{VCI_500KB}},
               {"800K",{VCI_800KB}},
               {"1M",{VCI_1000KB}}
               };
   static const long br_lut_size = sizeof (br_lut)/sizeof(IXXAT_look_up_table);
   int index;
   for (index = 0; index < br_lut_size; ++index)
       {
       if (::strcmp(br_lut[index].baud_rate,baud_rate)==0)
          break;
       }
   if (index == br_lut_size)
      return false;
   // close existing board
   close();
   // init IXXAT board
   unsigned long board_type = VCI_GetBrdTypeByName(const_cast<char*>(board_name));
   long res = VCI2_PrepareBoard( board_type,                  // board type
                                   board_number,              // unique board index
                                   NULL,                      // pointer to buffer for additional info
                                   0,                         // length of additional info buffer
                                   message_handler,           // pointer to msg-callbackhandler
                                   receive_queuedata_handler, // pointer to receive-callbackhandler
                                   exception_handler);        // pointer to exception-callbackhandler
   if (res < 0)
      return false;
   m_BoardHdl = (UINT16)res;

   VCI_ResetBoard(m_BoardHdl);

   // init CAN parameters

   // initialize CAN-Controller
   res = VCI_InitCan(m_BoardHdl, CAN_NUM, br_lut[index].bt.bt0,br_lut[index].bt.bt1, VCI_11B);

   //  definition of Acceptance-Mask (define to receive all IDs)
   res = VCI_SetAccMask(m_BoardHdl, CAN_NUM, 0x0UL, 0x0UL);

   // definition of Transmit Queue
   res = VCI_ConfigQueue(m_BoardHdl, CAN_NUM, VCI_TX_QUE, 100 , 0, 0, 0,  &m_TxQueHdl);

   //  definition of Receive Queue (interrupt mode)
   res = VCI_ConfigQueue(m_BoardHdl, CAN_NUM, VCI_RX_QUE, 50, 1, 0, 100,  &m_RxQueHdl);

   //  assign the all IDs to the Receive Queue
   res = VCI_AssignRxQueObj(m_BoardHdl, m_RxQueHdl ,VCI_ACCEPT, 0, 0) ;

   //  And now start the CAN
   res = VCI_StartCan(m_BoardHdl, CAN_NUM);

   return true;
   }

bool IXXAT::close()
   {
   if (m_BoardHdl == 0xFFFF)
      return true;
   VCI_ResetBoard(m_BoardHdl);
   VCI_CancelBoard(m_BoardHdl);
   m_BoardHdl =
   m_TxQueHdl =
   m_RxQueHdl = 0xFFFF;
   return true;
   }

void IXXAT::receive_queuedata(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ *p_obj)
   {
   for (int i = 0; i < count; ++i)
       m_RX_Que.append(p_obj[i]); // can packet
   }

void VCI_CALLBACKATTR IXXAT::receive_queuedata_handler(UINT16 que_hdl, UINT16 count, VCI_CAN_OBJ *p_obj)
  {
   if (m_callbackPtr != NULL)
      m_callbackPtr->receive_queuedata(que_hdl, count, p_obj);
  }

void VCI_CALLBACKATTR IXXAT::message_handler(char *msg_str)
  {
  char buf[200];
  ::sprintf(buf,"IXXAT Message: [%s]\n", msg_str);
  ::OutputDebugString(buf);
  }

void VCI_CALLBACKATTR IXXAT::exception_handler(VCI_FUNC_NUM func_num, INT32 err_code, UINT16 ext_err, char* err_str)
  {
  static const char* Num2Function[] =
    {
    "VCI_Init",
    "VCI_Searchboard",
    "VCI_Prepareboard",
    "VCI_Cancel_board",
    "VCI_Testboard",
    "VCI_ReadBoardInfo",
    "VCI_ReadBoardStatus",
    "VCI_Resetboard",
    "VCI_ReadCANInfo",
    "VCI_ReadCANStatus",
    "VCI_InitCAN",
    "VCI_SetAccMask",
    "VCI_ResetCAN",
    "VCI_StartCAN",
    "VCI_ResetTimeStamps",
    "VCI_ConfigQueue",
    "VCI_AssignRxQueObj",
    "VCI_ConfigBuffer",
    "VCI_ReconfigBuffer",
    "VCI_ConfigTimer",
    "VCI_ReadQueStatus",
    "VCI_ReadQueObj",
    "VCI_ReadBufStatus",
    "VCI_ReadBufData",
    "VCI_TransmitObj",
    "VCI_RequestObj",
    "VCI_UpdateBufObj",
    "VCI_CciReqData"
    };
  char buf[200];
  ::sprintf(buf, "IXXAT Exception: %s (%i / %u) [%s]\n", Num2Function[func_num], err_code, ext_err, err_str);
  ::OutputDebugString(buf);
  }

//------------------------------------------------------------------------
extern "C"
   UNS8 __stdcall canReceive_driver(CAN_HANDLE inst, Message *m)
   {
   return (UNS8)reinterpret_cast<IXXAT*>(inst)->receive(m);
   }

extern "C"
   UNS8 __stdcall canSend_driver(CAN_HANDLE inst, Message const *m)
   {
   return (UNS8)reinterpret_cast<IXXAT*>(inst)->send(m);
   }

extern "C"
   CAN_HANDLE __stdcall canOpen_driver(s_BOARD *board)
   {
   try
      {
      return new IXXAT(board);
      }
   catch (IXXAT::error&)
      {
      return 0;
      }
   }

extern "C"
   int __stdcall canClose_driver(CAN_HANDLE inst)
   {
   delete reinterpret_cast<IXXAT*>(inst);
   return 1;
   }

extern "C"
   UNS8 __stdcall canChangeBaudRate_driver( CAN_HANDLE fd, char* baud)
	{
	//printf("canChangeBaudRate not yet supported by this driver\n");
	return 0;
	}
<|endoftext|>


<commit_before>/* This file is part of the KDE libraries
 * Copyright (C) 2008-2009 Erlend Hamberg <ehamberg@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) version 3.
 *
 * 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "kateviglobal.h"
#include "katevikeyparser.h"

#include "kconfiggroup.h"
#include "kdebug.h"
#include <QApplication>
#include <QClipboard>

KateViGlobal::KateViGlobal()
{
  m_numberedRegisters = new QList<QString>;
  m_registers = new QMap<QChar, QString>;
}

KateViGlobal::~KateViGlobal()
{
  delete m_numberedRegisters;
  delete m_registers;
}

void KateViGlobal::writeConfig( KConfigGroup &config ) const
{
  config.writeEntry( "Normal Mode Mapping Keys", getMappings( NormalMode, true ) );
  QStringList l;
  foreach( const QString &s, getMappings( NormalMode ) ) {
    l << KateViKeyParser::getInstance()->decodeKeySequence( getMapping( NormalMode, s ) );
  }
  config.writeEntry( "Normal Mode Mappings", l );
}

void KateViGlobal::readConfig( const KConfigGroup &config )
{
    QStringList keys = config.readEntry( "Normal Mode Mapping Keys", QStringList() );
    QStringList mappings = config.readEntry( "Normal Mode Mappings", QStringList() );

    // sanity check
    if ( keys.length() == mappings.length() ) {
      for ( int i = 0; i < keys.length(); i++ ) {
        addMapping( NormalMode, keys.at( i ), mappings.at( i ) );
        kDebug( 13070 ) << "Mapping " << keys.at( i ) << " -> " << mappings.at( i );
      }
    } else {
      kDebug( 13070 ) << "Error when reading mappings from config: number of keys != number of values";
    }
}

QString KateViGlobal::getRegisterContent( const QChar &reg ) const
{
  QString regContent;
  QChar _reg = ( reg != '"' ? reg : m_defaultRegister );

  if ( _reg >= '1' && _reg <= '9' ) { // numbered register
    int index = QString( _reg ).toInt()-1;
    if ( m_numberedRegisters->size() > index) {
      regContent = m_numberedRegisters->at( index );
    } else {
      regContent = QString();
    }
  } else if ( _reg == '+' ) { // system clipboard register
      regContent = QApplication::clipboard()->text( QClipboard::Clipboard );
  } else if ( _reg == '*' ) { // system selection register
      regContent = QApplication::clipboard()->text( QClipboard::Selection );
  } else { // regular, named register
    if ( m_registers->contains( _reg ) ) {
      regContent = m_registers->value( _reg );
    }
  }

  return regContent;
}

void KateViGlobal::addToNumberedRegister( const QString &text )
{
  if ( m_numberedRegisters->size() == 9 ) {
    m_numberedRegisters->removeLast();
  }

  // register 0 is used for the last yank command, so insert at position 1
  m_numberedRegisters->prepend( text );

  kDebug( 13070 ) << "Register 1-9:";
  for ( int i = 0; i < m_numberedRegisters->size(); i++ ) {
      kDebug( 13070 ) << "\t Register " << i+1 << ": " << m_numberedRegisters->at( i );
  }
}

void KateViGlobal::fillRegister( const QChar &reg, const QString &text )
{
  // the specified register is the "black hole register", don't do anything
  if ( reg == '_' ) {
    return;
  }

  if ( reg >= '1' && reg <= '9' ) { // "kill ring" registers
    addToNumberedRegister( text );
  } else if ( reg == '+' ) { // system clipboard register
      QApplication::clipboard()->setText( text,  QClipboard::Clipboard );
  } else if ( reg == '*' ) { // system selection register
      QApplication::clipboard()->setText( text, QClipboard::Selection );
  } else {
    m_registers->insert( reg, text );
  }

  kDebug( 13070 ) << "Register " << reg << " set to " << getRegisterContent( reg );

  if ( reg == '0' || reg == '1' || reg == '-' ) {
    m_defaultRegister = reg;
    kDebug( 13070 ) << "Register " << '"' << " set to point to \"" << reg;
  }
}

void KateViGlobal::addMapping( ViMode mode, const QString &from, const QString &to )
{
  if ( !from.isEmpty() ) {
    switch ( mode ) {
    case NormalMode:
      m_normalModeMappings[ KateViKeyParser::getInstance()->encodeKeySequence( from ) ]
        = KateViKeyParser::getInstance()->encodeKeySequence( to );
      break;
    default:
      kDebug( 13070 ) << "Mapping not supported for given mode";
    }
  }
}

const QString KateViGlobal::getMapping( ViMode mode, const QString &from, bool decode ) const
{
    QString ret;
    switch ( mode ) {
    case NormalMode:
      ret = m_normalModeMappings.value( from );
      break;
    default:
      kDebug( 13070 ) << "Mapping not supported for given mode";
    }

    if ( decode ) {
      return KateViKeyParser::getInstance()->decodeKeySequence( ret );
    }
    return ret;
}

const QStringList KateViGlobal::getMappings( ViMode mode, bool decode ) const
{
  QStringList l;
  switch (mode ) {
  case NormalMode:
    foreach ( const QString &str, m_normalModeMappings.keys() ) {
      if ( decode ) {
        l << KateViKeyParser::getInstance()->decodeKeySequence( str );
      } else {
        l << str;
      }
    }
    break;
  default:
    kDebug( 13070 ) << "Mapping not supported for given mode";
  }

  return l;
}

void KateViGlobal::clearMappings( ViMode mode )
{
  switch (mode ) {
  case NormalMode:
    m_normalModeMappings.clear();
    break;
  default:
    kDebug( 13070 ) << "Mapping not supported for given mode";
  }
}
<commit_msg>fix krazy warning<commit_after>/* This file is part of the KDE libraries
 * Copyright (C) 2008-2009 Erlend Hamberg <ehamberg@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) version 3.
 *
 * 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public License
 * along with this library; see the file COPYING.LIB.  If not, write to
 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include "kateviglobal.h"
#include "katevikeyparser.h"

#include "kconfiggroup.h"
#include "kdebug.h"
#include <QApplication>
#include <QClipboard>

KateViGlobal::KateViGlobal()
{
  m_numberedRegisters = new QList<QString>;
  m_registers = new QMap<QChar, QString>;
}

KateViGlobal::~KateViGlobal()
{
  delete m_numberedRegisters;
  delete m_registers;
}

void KateViGlobal::writeConfig( KConfigGroup &config ) const
{
  config.writeEntry( "Normal Mode Mapping Keys", getMappings( NormalMode, true ) );
  QStringList l;
  foreach( const QString &s, getMappings( NormalMode ) ) {
    l << KateViKeyParser::getInstance()->decodeKeySequence( getMapping( NormalMode, s ) );
  }
  config.writeEntry( "Normal Mode Mappings", l );
}

void KateViGlobal::readConfig( const KConfigGroup &config )
{
    QStringList keys = config.readEntry( "Normal Mode Mapping Keys", QStringList() );
    QStringList mappings = config.readEntry( "Normal Mode Mappings", QStringList() );

    // sanity check
    if ( keys.length() == mappings.length() ) {
      for ( int i = 0; i < keys.length(); i++ ) {
        addMapping( NormalMode, keys.at( i ), mappings.at( i ) );
        kDebug( 13070 ) << "Mapping " << keys.at( i ) << " -> " << mappings.at( i );
      }
    } else {
      kDebug( 13070 ) << "Error when reading mappings from config: number of keys != number of values";
    }
}

QString KateViGlobal::getRegisterContent( const QChar &reg ) const
{
  QString regContent;
  QChar _reg = ( reg != '"' ? reg : m_defaultRegister );

  if ( _reg >= '1' && _reg <= '9' ) { // numbered register
    int index = QString( _reg ).toInt()-1;
    if ( m_numberedRegisters->size() > index) {
      regContent = m_numberedRegisters->at( index );
    }
  } else if ( _reg == '+' ) { // system clipboard register
      regContent = QApplication::clipboard()->text( QClipboard::Clipboard );
  } else if ( _reg == '*' ) { // system selection register
      regContent = QApplication::clipboard()->text( QClipboard::Selection );
  } else { // regular, named register
    if ( m_registers->contains( _reg ) ) {
      regContent = m_registers->value( _reg );
    }
  }

  return regContent;
}

void KateViGlobal::addToNumberedRegister( const QString &text )
{
  if ( m_numberedRegisters->size() == 9 ) {
    m_numberedRegisters->removeLast();
  }

  // register 0 is used for the last yank command, so insert at position 1
  m_numberedRegisters->prepend( text );

  kDebug( 13070 ) << "Register 1-9:";
  for ( int i = 0; i < m_numberedRegisters->size(); i++ ) {
      kDebug( 13070 ) << "\t Register " << i+1 << ": " << m_numberedRegisters->at( i );
  }
}

void KateViGlobal::fillRegister( const QChar &reg, const QString &text )
{
  // the specified register is the "black hole register", don't do anything
  if ( reg == '_' ) {
    return;
  }

  if ( reg >= '1' && reg <= '9' ) { // "kill ring" registers
    addToNumberedRegister( text );
  } else if ( reg == '+' ) { // system clipboard register
      QApplication::clipboard()->setText( text,  QClipboard::Clipboard );
  } else if ( reg == '*' ) { // system selection register
      QApplication::clipboard()->setText( text, QClipboard::Selection );
  } else {
    m_registers->insert( reg, text );
  }

  kDebug( 13070 ) << "Register " << reg << " set to " << getRegisterContent( reg );

  if ( reg == '0' || reg == '1' || reg == '-' ) {
    m_defaultRegister = reg;
    kDebug( 13070 ) << "Register " << '"' << " set to point to \"" << reg;
  }
}

void KateViGlobal::addMapping( ViMode mode, const QString &from, const QString &to )
{
  if ( !from.isEmpty() ) {
    switch ( mode ) {
    case NormalMode:
      m_normalModeMappings[ KateViKeyParser::getInstance()->encodeKeySequence( from ) ]
        = KateViKeyParser::getInstance()->encodeKeySequence( to );
      break;
    default:
      kDebug( 13070 ) << "Mapping not supported for given mode";
    }
  }
}

const QString KateViGlobal::getMapping( ViMode mode, const QString &from, bool decode ) const
{
    QString ret;
    switch ( mode ) {
    case NormalMode:
      ret = m_normalModeMappings.value( from );
      break;
    default:
      kDebug( 13070 ) << "Mapping not supported for given mode";
    }

    if ( decode ) {
      return KateViKeyParser::getInstance()->decodeKeySequence( ret );
    }
    return ret;
}

const QStringList KateViGlobal::getMappings( ViMode mode, bool decode ) const
{
  QStringList l;
  switch (mode ) {
  case NormalMode:
    foreach ( const QString &str, m_normalModeMappings.keys() ) {
      if ( decode ) {
        l << KateViKeyParser::getInstance()->decodeKeySequence( str );
      } else {
        l << str;
      }
    }
    break;
  default:
    kDebug( 13070 ) << "Mapping not supported for given mode";
  }

  return l;
}

void KateViGlobal::clearMappings( ViMode mode )
{
  switch (mode ) {
  case NormalMode:
    m_normalModeMappings.clear();
    break;
  default:
    kDebug( 13070 ) << "Mapping not supported for given mode";
  }
}
<|endoftext|>


<commit_before>/*************************************************************************/
/* spdlog - an extremely fast and easy to use c++11 logging library.     */
/* Copyright (c) 2014 Gabi Melman.                                       */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

//
// spdlog usage example
//
#include <iostream>
#include "spdlog/spdlog.h"

int main(int, char* [])
{
    namespace spd = spdlog;
    try
    {
        // Set log level to all loggers to DEBUG and above
        spd::set_level(spd::level::debug);

        //Create console, multithreaded logger
        auto console = spd::stdout_logger_mt("console");
        console->info("Welcome to spdlog!") ;
        console->info("An info message example {}..", 1);
        console->info() << "Streams are supported too  " << 1;

        console->info("Easy padding in numbers like {:08d}", 12);
        console->info("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
        console->info("Support for floats {:03.2f}", 1.23456);
        console->info("Positional args are {1} {0}..", "too", "supported");

        console->info("{:<30}", "left aligned");
        console->info("{:>30}", "right aligned");
        console->info("{:^30}", "centered");

        //Create a file rotating logger with 5mb size max and 3 rotated files
        auto file_logger = spd::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);
        file_logger->set_level(spd::level::info);
        for(int i = 0; i < 10; ++i)
		      file_logger->info("{} * {} equals {:>10}", i, i, i*i);

        //Customize msg format for all messages
        spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
        file_logger->info("This is another message with custom format");

        spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");

        SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
        SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);

        //
        // Asynchronous logging is very fast..
        // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
        //
        size_t q_size = 1048576; //queue size must be power of 2
        spdlog::set_async_mode(q_size);
        auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
        async_file->info() << "This is async log.." << "Should be very fast!";

		#ifdef __linux__
        // syslog example. linux only..
        std::string ident = "spdlog-example";
        auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
        syslog_logger->warn("This is warning that will end up in syslog. This is Linux only!");
		#endif

    }
    catch (const spd::spdlog_ex& ex)
    {
        std::cout << "Log failed: " << ex.what() << std::endl;
    }
}
<commit_msg>updated example<commit_after>/*************************************************************************/
/* spdlog - an extremely fast and easy to use c++11 logging library.     */
/* Copyright (c) 2014 Gabi Melman.                                       */
/*                                                                       */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the       */
/* "Software"), to deal in the Software without restriction, including   */
/* without limitation the rights to use, copy, modify, merge, publish,   */
/* distribute, sublicense, and/or sell copies of the Software, and to    */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions:                                             */
/*                                                                       */
/* The above copyright notice and this permission notice shall be        */
/* included in all copies or substantial portions of the Software.       */
/*                                                                       */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
/*************************************************************************/

//
// spdlog usage example
//
#include <iostream>
#include "spdlog/spdlog.h"

int main(int, char* [])
{
    namespace spd = spdlog;
    try
    {
        // Set log level to all loggers to debug and above
        spd::set_level(spd::level::debug);

        // Create console, multithreaded logger
        auto console = spd::stdout_logger_mt("console");
        console->info("Welcome to spdlog!") ;
        console->info("An info message example {}..", 1);
        console->info() << "Streams are supported too  " << 1;

        console->info("Easy padding in numbers like {:08d}", 12);
        console->info("Support for int: {0:d};  hex: {0:x};  oct: {0:o}; bin: {0:b}", 42);
        console->info("Support for floats {:03.2f}", 1.23456);
        console->info("Positional args are {1} {0}..", "too", "supported");

        console->info("{:<30}", "left aligned");
        console->info("{:>30}", "right aligned");
        console->info("{:^30}", "centered");

        // Create a file rotating logger with 5mb size max and 3 rotated files
        auto file_logger = spd::rotating_logger_mt("file_logger", "logs/mylogfile", 1048576 * 5, 3);
        file_logger->set_level(spd::level::info);
        for(int i = 0; i < 10; ++i)
		      file_logger->info("{} * {} equals {:>10}", i, i, i*i);

        // Customize msg format for all messages
        spd::set_pattern("*** [%H:%M:%S %z] [thread %t] %v ***");
        file_logger->info("This is another message with custom format");

        spd::get("console")->info("loggers can be retrieved from a global registry using the spdlog::get(logger_name) function");

        SPDLOG_TRACE(console, "Enabled only #ifdef SPDLOG_TRACE_ON..{} ,{}", 1, 3.23);
        SPDLOG_DEBUG(console, "Enabled only #ifdef SPDLOG_DEBUG_ON.. {} ,{}", 1, 3.23);

        //
        // Asynchronous logging is very fast..
        // Just call spdlog::set_async_mode(q_size) and all created loggers from now on will be asynchronous..
        //
        size_t q_size = 1048576; //queue size must be power of 2
        spdlog::set_async_mode(q_size);
        auto async_file= spd::daily_logger_st("async_file_logger", "logs/async_log.txt");
        async_file->info() << "This is async log.." << "Should be very fast!";

    	// syslog example. linux only..
		#ifdef __linux__
        std::string ident = "spdlog-example";
        auto syslog_logger = spd::syslog_logger("syslog", ident, LOG_PID);
        syslog_logger->warn("This is warning that will end up in syslog. This is Linux only!");
		#endif

    }
    catch (const spd::spdlog_ex& ex)
    {
        std::cout << "Log failed: " << ex.what() << std::endl;
    }
}
<|endoftext|>


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

#include "Common/Common.h"

// Server object model.
#include "../../Server/Client.h"
#include "../../Server/IClientHandler.h"
#include "../../Server/Services/Services.h"
#include "../../Server/IServerControl.h"
#include "../../Server/Config.h"
#include "ScreenshotSpreader.h"

// Hardware subsystem.
#include "Hardware/Hardware.h"

// Interaction protocol tool.
#include "Messages/ScreenshotMessage.h"

// QT is responsible for image capturing and resizing.
#include <QtGui/QtGui>
#include <QDesktopWidget>
#include <QApplication>

namespace RemotePC
{
	void ScreenshotSpreader::Handle(const Client& client, mc::IProtocolRef protocol, IServerControlRef /* server */)
	{
        if ( !client.IsScreenCaptureEnabled() )
            return;

        // Acquire mouse cursor position.
        RemotePC::ScreenPoint position = RemotePC::HardwareProvider::Instance().GetMouseControl()->GetPosition();

        // Calculate bounding box around current mouse position.
        float blockSize = 256.0f;
        float zoomLevel = client.GetZoomLevel();
        int imageSize = (int)( blockSize * zoomLevel );
        int leftX = position.x_ - imageSize / 2;
        int topY = position.y_ - imageSize / 2;
        int rightX = leftX + imageSize;
        int bottomY = topY + imageSize;

        // Find screen to which cursor currently belongs.
        QDesktopWidget* desktop = QApplication::desktop();
        int screenNumber = desktop->screenNumber(QPoint(position.x_, position.y_));
        QWidget* screen = desktop->screen(screenNumber);
        QRect geometry = screen->geometry();

        // Cut areas beyond the surface of the screen.
        int leftdX = ( leftX < geometry.left() ) ? ( geometry.left() - leftX ) : 0;
        int topdY = ( topY < geometry.top() ) ? ( geometry.top() - topY ) : 0;
        int rightdX = ( rightX > geometry.right() ) ? ( rightX - geometry.right() ) : 0;
        int bottomdY = ( bottomY >= geometry.bottom() ) ? ( bottomY - geometry.bottom() ) : 0;
        leftX += leftdX;
        topY += topdY;
        rightX += rightdX;
        bottomY += bottomdY;
        int fragmentWidth = imageSize - leftdX - rightdX;
        int fragmentHeight = imageSize - topdY - bottomdY;
        bool isBoundary = ( leftdX > 0 ) || ( topdY > 0 ) || ( rightdX > 0 ) || ( bottomdY > 0 );

        // Grab part of the screen.
        QPixmap fragment = QApplication::primaryScreen()->grabWindow(
            QApplication::desktop()->winId(),
            leftX, topY, fragmentWidth, fragmentHeight);

        // Check to see if anything was actually grabbed.
        fragmentWidth = fragment.width();
        fragmentHeight = fragment.height();
        if ( fragmentWidth <= 0 || fragmentHeight <= 0 )
        {
            return;
        }

        if ( isBoundary )
        {
            // Image was grabbed right next to one of screen edges.
            QPixmap temp(blockSize, blockSize);
            QPainter painter(&temp);
            painter.fillRect(0, 0, blockSize, blockSize, QColor(Qt::black));
            QRect source(0, 0, fragmentWidth, fragmentHeight);
            QRect target(
                leftdX * blockSize / imageSize, topdY * blockSize / imageSize,
                fragmentWidth * blockSize / imageSize, fragmentHeight * blockSize / imageSize);
            painter.drawPixmap(target, fragment, source);
            fragment = temp;
        }
        else
        {
            if ( imageSize != (int)blockSize )
            {
                // Image was grabbed from within the screen.
                fragment = fragment.scaled(
                    QSize(blockSize, blockSize),
                    Qt::KeepAspectRatio,
                    Qt::SmoothTransformation);
            }
        }

        // Construct screenshot message from QT image.
        QByteArray imageBytes;
        QBuffer imageBuffer(&imageBytes);
        imageBuffer.open(QIODevice::WriteOnly);
        #if !defined(IREMOTE_NO_QT_PLUGINS)
            fragment.save(&imageBuffer, "JPG", Config::Instance().GetSFBCompression());
        #else
            fragment.save(&imageBuffer, "PNG", Config::Instance().GetSFBCompression());
        #endif

        mc::IMessagePtr message(
            mc::Class< RemotePC::ScreenshotMessage >::Create(
                imageBytes.size(), imageBytes.constData() ) );

        // Send image to the client.
        protocol->Send( message );
	}
}
<commit_msg>RPC. Image quality is preserved better when scaling this way.<commit_after>/**
 * Copyright (c) 2013 Egor Pushkin. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "Common/Common.h"

// Server object model.
#include "../../Server/Client.h"
#include "../../Server/IClientHandler.h"
#include "../../Server/Services/Services.h"
#include "../../Server/IServerControl.h"
#include "../../Server/Config.h"
#include "ScreenshotSpreader.h"

// Hardware subsystem.
#include "Hardware/Hardware.h"

// Interaction protocol tool.
#include "Messages/ScreenshotMessage.h"

// QT is responsible for image capturing and resizing.
#include <QtGui/QtGui>
#include <QDesktopWidget>
#include <QApplication>

namespace RemotePC
{
	void ScreenshotSpreader::Handle(const Client& client, mc::IProtocolRef protocol, IServerControlRef /* server */)
	{
        if ( !client.IsScreenCaptureEnabled() )
            return;

        // Acquire mouse cursor position.
        RemotePC::ScreenPoint position = RemotePC::HardwareProvider::Instance().GetMouseControl()->GetPosition();

        // Calculate bounding box around current mouse position.
        float blockSize = 256.0f;
        float zoomLevel = client.GetZoomLevel();
        int imageSize = (int)( blockSize * zoomLevel );
        int leftX = position.x_ - imageSize / 2;
        int topY = position.y_ - imageSize / 2;
        int rightX = leftX + imageSize;
        int bottomY = topY + imageSize;

        // Find screen to which cursor currently belongs.
        QDesktopWidget* desktop = QApplication::desktop();
        int screenNumber = desktop->screenNumber(QPoint(position.x_, position.y_));
        QWidget* screen = desktop->screen(screenNumber);
        QRect geometry = screen->geometry();

        // Cut areas beyond the surface of the screen.
        int leftdX = ( leftX < geometry.left() ) ? ( geometry.left() - leftX ) : 0;
        int topdY = ( topY < geometry.top() ) ? ( geometry.top() - topY ) : 0;
        int rightdX = ( rightX > geometry.right() ) ? ( rightX - geometry.right() ) : 0;
        int bottomdY = ( bottomY >= geometry.bottom() ) ? ( bottomY - geometry.bottom() ) : 0;
        leftX += leftdX;
        topY += topdY;
        rightX += rightdX;
        bottomY += bottomdY;
        int fragmentWidth = imageSize - leftdX - rightdX;
        int fragmentHeight = imageSize - topdY - bottomdY;
        bool isBoundary = ( leftdX > 0 ) || ( topdY > 0 ) || ( rightdX > 0 ) || ( bottomdY > 0 );

        // Grab part of the screen.
        QPixmap fragment = QApplication::primaryScreen()->grabWindow(
            QApplication::desktop()->winId(),
            leftX, topY, fragmentWidth, fragmentHeight);

        // Check to see if anything was actually grabbed.
        fragmentWidth = fragment.width();
        fragmentHeight = fragment.height();
        if ( fragmentWidth <= 0 || fragmentHeight <= 0 )
        {
            return;
        }

        if ( isBoundary )
        {
            // Image was grabbed right next to one of screen edges.

            // Scale image first. QPainter's scaling does not always work even with QPainter::SmoothPixmapTransform.
            fragment = fragment.scaled(
                QSize(fragmentWidth * blockSize / imageSize, fragmentHeight * blockSize / imageSize),
                Qt::KeepAspectRatio,
                Qt::SmoothTransformation);

            // Locate grabbed fragment appropriately in the resulting image.
            QPixmap temp(blockSize, blockSize);
            QPainter painter(&temp);
            painter.fillRect(0, 0, blockSize, blockSize, QColor(Qt::black));
            painter.drawPixmap(QPoint(leftdX * blockSize / imageSize, topdY * blockSize / imageSize), fragment);
            fragment = temp;
        }
        else
        {
            if ( imageSize != (int)blockSize )
            {
                // Image was grabbed from within the screen.
                fragment = fragment.scaled(
                    QSize(blockSize, blockSize),
                    Qt::KeepAspectRatio,
                    Qt::SmoothTransformation);
            }
        }

        // Construct screenshot message from QT image.
        QByteArray imageBytes;
        QBuffer imageBuffer(&imageBytes);
        imageBuffer.open(QIODevice::WriteOnly);
        #if !defined(IREMOTE_NO_QT_PLUGINS)
            fragment.save(&imageBuffer, "JPG", Config::Instance().GetSFBCompression());
        #else
            fragment.save(&imageBuffer, "PNG", Config::Instance().GetSFBCompression());
        #endif

        // Construct message object.
        mc::IMessagePtr message(
            mc::Class< RemotePC::ScreenshotMessage >::Create(
                imageBytes.size(), imageBytes.constData() ) );

        // Send image to the client.
        protocol->Send( message );
	}
}
<|endoftext|>


<commit_before>/*
 Copyright (c) 2010, The Barbarian Group
 All rights reserved.

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and
	the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
	the following disclaimer in the documentation and/or other materials provided with the distribution.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
*/

#include "cinder/app/App.h"
#include "cinder/params/Params.h"

#include "AntTweakBar.h"

using namespace std;

namespace cinder { namespace params {

namespace {

bool mouseDown( app::MouseEvent event )
{
	TwMouseButtonID button;
	if( event.isLeft() )
		button = TW_MOUSE_LEFT;
	else if( event.isRight() )
		button = TW_MOUSE_RIGHT;
	else
		button = TW_MOUSE_MIDDLE;
	return TwMouseButton( TW_MOUSE_PRESSED, button ) != 0;
}

bool mouseUp( app::MouseEvent event )
{
	TwMouseButtonID button;
	if( event.isLeft() )
		button = TW_MOUSE_LEFT;
	else if( event.isRight() )
		button = TW_MOUSE_RIGHT;
	else
		button = TW_MOUSE_MIDDLE;
	return TwMouseButton( TW_MOUSE_RELEASED, button ) != 0;
}

bool mouseWheel( app::MouseEvent event )
{
	static float sWheelPos = 0;
	sWheelPos += event.getWheelIncrement();
	return TwMouseWheel( (int)(sWheelPos) ) != 0;
}

bool mouseMove( app::MouseEvent event )
{
	return TwMouseMotion( event.getX(), event.getY() ) != 0;
}

bool keyDown( app::KeyEvent event )
{
	int kmod = 0;
	if( event.isShiftDown() )
		kmod |= TW_KMOD_SHIFT;
	if( event.isControlDown() )
		kmod |= TW_KMOD_CTRL;
	if( event.isAltDown() )
		kmod |= TW_KMOD_ALT;
	return TwKeyPressed( event.getChar(), kmod ) != 0;
}

bool resize( app::ResizeEvent event )
{
	TwWindowSize( event.getWidth(), event.getHeight() );
	return false;
}

void TW_CALL implStdStringToClient( std::string& destinationClientString, const std::string& sourceLibraryString )
{
  // copy strings from the library to the client app
  destinationClientString = sourceLibraryString;
}

class AntMgr {
  public:
	AntMgr() {
		if( ! TwInit( TW_OPENGL, NULL ) ) {
			throw Exception();
		}

		app::App::get()->registerMouseDown( mouseDown );
		app::App::get()->registerMouseUp( mouseUp );
		app::App::get()->registerMouseWheel( mouseWheel );
		app::App::get()->registerMouseMove( mouseMove );
		app::App::get()->registerMouseDrag( mouseMove );
		app::App::get()->registerKeyDown( keyDown );
		app::App::get()->registerResize( resize );
	}

	~AntMgr() {
		TwTerminate();
	}
};

} // anonymous namespace

void initAntGl()
{
	static std::shared_ptr<AntMgr> mgr;
	if( ! mgr )
		mgr = std::shared_ptr<AntMgr>( new AntMgr );
}

InterfaceGl::InterfaceGl( const std::string &title, const Vec2i &size, const ColorA color )
{
	initAntGl();
	mBar = std::shared_ptr<TwBar>( TwNewBar( title.c_str() ), TwDeleteBar );
	char optionsStr[1024];
	sprintf( optionsStr, "`%s` size='%d %d' color='%d %d %d' alpha=%d", title.c_str(), size.x, size.y, (int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255), (int)(color.a * 255) );
	TwDefine( optionsStr );

	TwCopyStdStringToClientFunc( implStdStringToClient );
}

void InterfaceGl::draw()
{
	TwDraw();
}

void InterfaceGl::show( bool visible )
{
	int32_t visibleInt = ( visible ) ? 1 : 0;
	TwSetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
}

void InterfaceGl::hide()
{
	int32_t visibleInt = 0;
	TwSetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
}

bool InterfaceGl::isVisible() const
{
	int32_t visibleInt;
	TwGetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
	return visibleInt != 0;
}

void InterfaceGl::implAddParam( const std::string &name, void *param, int type, const std::string &optionsStr, bool readOnly )
{
	if( readOnly )
		TwAddVarRO( mBar.get(), name.c_str(), (TwType)type, param, optionsStr.c_str() );
	else
		TwAddVarRW( mBar.get(), name.c_str(), (TwType)type, param, optionsStr.c_str() );
}

void InterfaceGl::addParam( const std::string &name, bool *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_BOOLCPP, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, float *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_FLOAT, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, int32_t *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_INT32, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Vec3f *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_DIR3F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Quatf *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_QUAT4F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Color *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_COLOR3F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, ColorA *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_COLOR4F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, std::string *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_STDSTRING, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, const std::vector<std::string> &enumNames, int *param, const std::string &optionsStr, bool readOnly )
{
	TwEnumVal *ev = new TwEnumVal[enumNames.size()];
	for( size_t v = 0; v < enumNames.size(); ++v ) {
		ev[v].Value = v;
		ev[v].Label = const_cast<char*>( enumNames[v].c_str() );
	}

	TwType evType = TwDefineEnum( (name + "EnumType").c_str(), ev, enumNames.size() );

	if( readOnly )
		TwAddVarRO( mBar.get(), name.c_str(), evType, param, optionsStr.c_str() );
	else
		TwAddVarRW( mBar.get(), name.c_str(), evType, param, optionsStr.c_str() );

	delete [] ev;
}

void InterfaceGl::addSeparator( const std::string &name, const std::string &optionsStr )
{
	TwAddSeparator( mBar.get(), name.c_str(), optionsStr.c_str() );
}

void InterfaceGl::addText( const std::string &name, const std::string &optionsStr )
{
	TwAddButton( mBar.get(), name.c_str(), NULL, NULL, optionsStr.c_str() );
}

namespace { // anonymous namespace
void TW_CALL implButtonCallback( void *clientData )
{
	std::function<void ()> *fn = reinterpret_cast<std::function<void ()>*>( clientData );
	(*fn)();
}
} // anonymous namespace

void InterfaceGl::addButton( const std::string &name, const std::function<void ()> &callback, const std::string &optionsStr )
{
	std::shared_ptr<std::function<void ()> > callbackPtr( new std::function<void ()>( callback ) );
	mButtonCallbacks.push_back( callbackPtr );
	TwAddButton( mBar.get(), name.c_str(), implButtonCallback, (void*)callbackPtr.get(), optionsStr.c_str() );
}

void InterfaceGl::setOptions( const std::string &name, const std::string &optionsStr )
{
	std::string target = "`" + (std::string)TwGetBarName( mBar.get() ) + "`";
	if( !( name.empty() ) )
		target += "/`" + name + "`";

	TwDefine( ( target + " " + optionsStr ).c_str() );
}

} } // namespace cinder::params
<commit_msg>translate special keys to AntTweakBar<commit_after>/*
 Copyright (c) 2010, The Barbarian Group
 All rights reserved.

 Redistribution and use in source and binary forms, with or without modification, are permitted provided that
 the following conditions are met:

    * Redistributions of source code must retain the above copyright notice, this list of conditions and
	the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and
	the following disclaimer in the documentation and/or other materials provided with the distribution.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.
*/

#include "cinder/app/App.h"
#include "cinder/params/Params.h"

#include "AntTweakBar.h"

#include <boost/assign/list_of.hpp>

using namespace std;

namespace cinder { namespace params {

namespace {

#define SYNONYM(ck,ak) ((int)cinder::app::KeyEvent::KEY_ ## ck, TW_KEY_ ## ak)
#define HOMONYM(k) SYNONYM(k,k)
    std::map<int,TwKeySpecial> specialKeys = boost::assign::map_list_of
        HOMONYM(RIGHT)
        HOMONYM(LEFT)
        HOMONYM(BACKSPACE)
        HOMONYM(DELETE)
        HOMONYM(TAB)
        HOMONYM(F1)
        HOMONYM(F2)
        HOMONYM(F3)
        HOMONYM(F4)
        HOMONYM(F5)
        HOMONYM(F6)
        HOMONYM(F7)
        HOMONYM(F8)
        HOMONYM(F9)
        HOMONYM(F10)
        HOMONYM(F11)
        HOMONYM(F12)
        HOMONYM(F13)
        HOMONYM(F14)
        HOMONYM(F15)
        HOMONYM(HOME)
        HOMONYM(END)
        SYNONYM(PAGEUP,PAGE_UP)
        SYNONYM(PAGEDOWN,PAGE_DOWN)
        ;
#undef SYNONYM
#undef HOMONYM

bool mouseDown( app::MouseEvent event )
{
	TwMouseButtonID button;
	if( event.isLeft() )
		button = TW_MOUSE_LEFT;
	else if( event.isRight() )
		button = TW_MOUSE_RIGHT;
	else
		button = TW_MOUSE_MIDDLE;
	return TwMouseButton( TW_MOUSE_PRESSED, button ) != 0;
}

bool mouseUp( app::MouseEvent event )
{
	TwMouseButtonID button;
	if( event.isLeft() )
		button = TW_MOUSE_LEFT;
	else if( event.isRight() )
		button = TW_MOUSE_RIGHT;
	else
		button = TW_MOUSE_MIDDLE;
	return TwMouseButton( TW_MOUSE_RELEASED, button ) != 0;
}

bool mouseWheel( app::MouseEvent event )
{
	static float sWheelPos = 0;
	sWheelPos += event.getWheelIncrement();
	return TwMouseWheel( (int)(sWheelPos) ) != 0;
}

bool mouseMove( app::MouseEvent event )
{
	return TwMouseMotion( event.getX(), event.getY() ) != 0;
}

bool keyDown( app::KeyEvent event )
{
	int kmod = 0;
	if( event.isShiftDown() )
		kmod |= TW_KMOD_SHIFT;
	if( event.isControlDown() )
		kmod |= TW_KMOD_CTRL;
	if( event.isAltDown() )
		kmod |= TW_KMOD_ALT;
	return TwKeyPressed(
            (specialKeys.count( event.getCode() ) > 0)
                ? specialKeys[event.getCode()]
                : event.getChar(),
            kmod ) != 0;
}

bool resize( app::ResizeEvent event )
{
	TwWindowSize( event.getWidth(), event.getHeight() );
	return false;
}

void TW_CALL implStdStringToClient( std::string& destinationClientString, const std::string& sourceLibraryString )
{
  // copy strings from the library to the client app
  destinationClientString = sourceLibraryString;
}

class AntMgr {
  public:
	AntMgr() {
		if( ! TwInit( TW_OPENGL, NULL ) ) {
			throw Exception();
		}

		app::App::get()->registerMouseDown( mouseDown );
		app::App::get()->registerMouseUp( mouseUp );
		app::App::get()->registerMouseWheel( mouseWheel );
		app::App::get()->registerMouseMove( mouseMove );
		app::App::get()->registerMouseDrag( mouseMove );
		app::App::get()->registerKeyDown( keyDown );
		app::App::get()->registerResize( resize );
	}

	~AntMgr() {
		TwTerminate();
	}
};

} // anonymous namespace

void initAntGl()
{
	static std::shared_ptr<AntMgr> mgr;
	if( ! mgr )
		mgr = std::shared_ptr<AntMgr>( new AntMgr );
}

InterfaceGl::InterfaceGl( const std::string &title, const Vec2i &size, const ColorA color )
{
	initAntGl();
	mBar = std::shared_ptr<TwBar>( TwNewBar( title.c_str() ), TwDeleteBar );
	char optionsStr[1024];
	sprintf( optionsStr, "`%s` size='%d %d' color='%d %d %d' alpha=%d", title.c_str(), size.x, size.y, (int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255), (int)(color.a * 255) );
	TwDefine( optionsStr );

	TwCopyStdStringToClientFunc( implStdStringToClient );
}

void InterfaceGl::draw()
{
	TwDraw();
}

void InterfaceGl::show( bool visible )
{
	int32_t visibleInt = ( visible ) ? 1 : 0;
	TwSetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
}

void InterfaceGl::hide()
{
	int32_t visibleInt = 0;
	TwSetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
}

bool InterfaceGl::isVisible() const
{
	int32_t visibleInt;
	TwGetParam( mBar.get(), NULL, "visible", TW_PARAM_INT32, 1, &visibleInt );
	return visibleInt != 0;
}

void InterfaceGl::implAddParam( const std::string &name, void *param, int type, const std::string &optionsStr, bool readOnly )
{
	if( readOnly )
		TwAddVarRO( mBar.get(), name.c_str(), (TwType)type, param, optionsStr.c_str() );
	else
		TwAddVarRW( mBar.get(), name.c_str(), (TwType)type, param, optionsStr.c_str() );
}

void InterfaceGl::addParam( const std::string &name, bool *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_BOOLCPP, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, float *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_FLOAT, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, int32_t *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_INT32, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Vec3f *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_DIR3F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Quatf *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_QUAT4F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, Color *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_COLOR3F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, ColorA *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_COLOR4F, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, std::string *param, const std::string &optionsStr, bool readOnly )
{
	implAddParam( name, param, TW_TYPE_STDSTRING, optionsStr, readOnly );
}

void InterfaceGl::addParam( const std::string &name, const std::vector<std::string> &enumNames, int *param, const std::string &optionsStr, bool readOnly )
{
	TwEnumVal *ev = new TwEnumVal[enumNames.size()];
	for( size_t v = 0; v < enumNames.size(); ++v ) {
		ev[v].Value = v;
		ev[v].Label = const_cast<char*>( enumNames[v].c_str() );
	}

	TwType evType = TwDefineEnum( (name + "EnumType").c_str(), ev, enumNames.size() );

	if( readOnly )
		TwAddVarRO( mBar.get(), name.c_str(), evType, param, optionsStr.c_str() );
	else
		TwAddVarRW( mBar.get(), name.c_str(), evType, param, optionsStr.c_str() );

	delete [] ev;
}

void InterfaceGl::addSeparator( const std::string &name, const std::string &optionsStr )
{
	TwAddSeparator( mBar.get(), name.c_str(), optionsStr.c_str() );
}

void InterfaceGl::addText( const std::string &name, const std::string &optionsStr )
{
	TwAddButton( mBar.get(), name.c_str(), NULL, NULL, optionsStr.c_str() );
}

namespace { // anonymous namespace
void TW_CALL implButtonCallback( void *clientData )
{
	std::function<void ()> *fn = reinterpret_cast<std::function<void ()>*>( clientData );
	(*fn)();
}
} // anonymous namespace

void InterfaceGl::addButton( const std::string &name, const std::function<void ()> &callback, const std::string &optionsStr )
{
	std::shared_ptr<std::function<void ()> > callbackPtr( new std::function<void ()>( callback ) );
	mButtonCallbacks.push_back( callbackPtr );
	TwAddButton( mBar.get(), name.c_str(), implButtonCallback, (void*)callbackPtr.get(), optionsStr.c_str() );
}

void InterfaceGl::setOptions( const std::string &name, const std::string &optionsStr )
{
	std::string target = "`" + (std::string)TwGetBarName( mBar.get() ) + "`";
	if( !( name.empty() ) )
		target += "/`" + name + "`";

	TwDefine( ( target + " " + optionsStr ).c_str() );
}

} } // namespace cinder::params
<|endoftext|>


<commit_before>#pragma once

/* Liveness analysis */

//#include <crab/cfg/basic_block_traits.hpp>
#include <crab/domains/discrete_domains.hpp>
#include <crab/iterators/killgen_fixpoint_iterator.hpp>
#include <crab/support/debug.hpp>
#include <crab/support/stats.hpp>

#include <boost/range/iterator_range.hpp>
#include <unordered_map>

namespace crab {

namespace analyzer {

template <typename V>
using varset_domain = ikos::discrete_domain<V>;

/**
 * Define the main operations for the liveness variable analysis:
 * compute for each basic block the set of live variables, i.e.,
 * variables that might be used in the future
 **/
template <class CFG>
class liveness_analysis_operations
    : public crab::iterators::killgen_operations_api<
          CFG, varset_domain<typename CFG::variable_t>> {

public:
  using varset_domain_t = varset_domain<typename CFG::variable_t>;
  using basic_block_label_t = typename CFG::basic_block_label_t;

private:
  using parent_type =
      crab::iterators::killgen_operations_api<CFG, varset_domain_t>;
  using binding_t = std::pair<varset_domain_t, varset_domain_t>;
  using liveness_map_t = std::unordered_map<basic_block_label_t, binding_t>;

  liveness_map_t m_liveness_map;

public:
  liveness_analysis_operations(CFG cfg) : parent_type(cfg) {}

  virtual bool is_forward() { return false; }

  virtual varset_domain_t entry() {
    varset_domain_t res = varset_domain_t::bottom();
    if (this->m_cfg.has_func_decl()) {
      auto fdecl = this->m_cfg.get_func_decl();
      for (unsigned i = 0, e = fdecl.get_num_outputs(); i < e; ++i) {
        res += fdecl.get_output_name(i);
      }
    }
    return res;
  }

  virtual varset_domain_t merge(varset_domain_t d1, varset_domain_t d2) {
    return d1 | d2;
  }

  virtual void init_fixpoint() {
    for (auto &b :
         boost::make_iterator_range(this->m_cfg.begin(), this->m_cfg.end())) {
      varset_domain_t kill, gen;
      for (auto &s : boost::make_iterator_range(b.rbegin(), b.rend())) {
        auto const &live = s.get_live();
        for (auto d :
             boost::make_iterator_range(live.defs_begin(), live.defs_end())) {
          kill += d;
          gen -= d;
        }
        for (auto u :
             boost::make_iterator_range(live.uses_begin(), live.uses_end())) {
          gen += u;
        }
      }
      m_liveness_map.insert(std::make_pair(b.label(), binding_t(kill, gen)));
    }
  }

  virtual varset_domain_t analyze(const basic_block_label_t &bb_id,
                                  varset_domain_t in) {
    auto it = m_liveness_map.find(bb_id);
    assert(it != m_liveness_map.end());
    in -= it->second.first;
    in += it->second.second;
    return in;
  }

  virtual std::string name() { return "Liveness"; }
};

/** Live variable analysis **/
template <typename CFG>
class liveness_analysis : public crab::iterators::killgen_fixpoint_iterator<
                              CFG, liveness_analysis_operations<CFG>> {

  using liveness_analysis_operations_t = liveness_analysis_operations<CFG>;
  using killgen_fixpoint_iterator_t =
      crab::iterators::killgen_fixpoint_iterator<
          CFG, liveness_analysis_operations_t>;

  liveness_analysis(const liveness_analysis<CFG> &other) = delete;
  liveness_analysis<CFG> &
  operator=(const liveness_analysis<CFG> &other) = delete;

  using basic_block_t = typename CFG::basic_block_t;

public:
  using basic_block_label_t = typename CFG::basic_block_label_t;
  using statement_t = typename CFG::statement_t;
  using varname_t = typename CFG::varname_t;
  typedef
      typename liveness_analysis_operations_t::varset_domain_t varset_domain_t;

private:
  bool m_release_in;

public:
  liveness_analysis(CFG cfg, bool release_in = true)
      : killgen_fixpoint_iterator_t(cfg), m_release_in(release_in) {}

  void exec() {
    this->run();

    CRAB_LOG("liveness-live", for (auto p
                                   : boost::make_iterator_range(
                                       this->out_begin(), this->out_end())) {
      crab::outs() << basic_block_traits<basic_block_t>::to_string(p.first)
                   << " live variables=" << p.second << "\n";
      ;
    });

    if (m_release_in) {
      this->m_in_map.clear();
    }
  }

  varset_domain_t get(const basic_block_label_t &bb) const {
    auto it = this->m_out_map.find(bb);
    if (it != this->m_out_map.end()) {
      return it->second;
    } else {
      return varset_domain_t::bottom();
    }
  }

  void write(crab_os &o) const {
    o << "TODO: print liveness analysis results\n";
  }
};

template <typename CFG>
inline crab_os &operator<<(crab_os &o, const liveness_analysis<CFG> &l) {
  l.write(o);
  return o;
}

/**
 * Live and Dead variable analysis.
 **/
template <typename CFG> class live_and_dead_analysis {
public:
  using basic_block_label_t = typename CFG::basic_block_label_t;
  using basic_block_t = typename CFG::basic_block_t;
  using statement_t = typename CFG::statement_t;
  using varname_t = typename CFG::varname_t;
  using variable_t = typename CFG::variable_t;
  using varset_domain_t = varset_domain<variable_t>;

private:
  using liveness_analysis_t = liveness_analysis<CFG>;

  // the cfg
  CFG m_cfg;
  // liveness analysis
  std::unique_ptr<liveness_analysis_t> m_live;
  // precompute dead variables might be expensive so user can choose.
  bool m_ignore_dead;
  // map basic blocks to set of dead variables at the end of the
  // blocks
  std::unordered_map<basic_block_label_t, varset_domain_t> m_dead_map;

  // statistics
  unsigned m_max_live;
  unsigned m_total_live;
  unsigned m_total_blocks;

public:
  // for backward compatibility
  // XXX: maybe unused already
  using set_t = varset_domain_t;

  // If ignore_dead is true then dead symbols are not computed.
  live_and_dead_analysis(CFG cfg, bool ignore_dead = false)
      : m_cfg(cfg), m_live(new liveness_analysis_t(m_cfg)),
        m_ignore_dead(ignore_dead), m_max_live(0), m_total_live(0),
        m_total_blocks(0) {}

  live_and_dead_analysis(const live_and_dead_analysis &other) = delete;

  live_and_dead_analysis &
  operator=(const live_and_dead_analysis &other) = delete;

  void exec() {
    m_live->exec();
    if (!m_ignore_dead) {
      crab::ScopedCrabStats __st__("Liveness.precompute_dead_variables");
      /** Remove dead variables locally **/
      for (auto &bb : boost::make_iterator_range(m_cfg.begin(), m_cfg.end())) {
        varset_domain_t live_set = m_live->get(bb.label());
        if (live_set.is_bottom())
          continue;

        varset_domain_t dead_set = m_cfg.get_node(bb.label()).live();
        // dead variables = (USE(bb) U DEF(bb)) \ live_out(bb)
        dead_set -= live_set;
        CRAB_LOG("liveness",
                 crab::outs()
                     << basic_block_traits<basic_block_t>::to_string(bb.label())
                     << " dead variables=" << dead_set << "\n";);
        m_dead_map.insert(std::make_pair(bb.label(), std::move(dead_set)));
        // update statistics
        m_total_live += live_set.size();
	if (live_set.size() > m_max_live) {
	  m_max_live = live_set.size();
	}
        m_total_blocks++;
      }
    }
  }

  // Return the set of live variables at the exit of block bb
  varset_domain_t get(const basic_block_label_t &bb) const {
    return m_live->get(bb);
  }

  // Return the set of dead variables at the exit of block bb
  varset_domain_t dead_exit(const basic_block_label_t &bb) const {
    if (m_ignore_dead) {
      CRAB_WARN("Dead variables were not precomputed during liveness analysis");
    }
    auto it = m_dead_map.find(bb);
    if (it == m_dead_map.end()) {
      return varset_domain_t();
    } else {
      return it->second;
    }
  }

  void get_stats(unsigned &total_live, unsigned &max_live_per_blk,
                 unsigned &avg_live_per_blk) const {
    total_live = m_total_live;
    max_live_per_blk = m_max_live;
    avg_live_per_blk =
        (m_total_blocks == 0 ? 0 : (int)m_total_live / m_total_blocks);
  }

  void write(crab_os &o) const {
    o << "TODO: printing dead variable analysis results\n";
  }
};

template <typename CFG>
inline crab_os &operator<<(crab_os &o, const live_and_dead_analysis<CFG> &l) {
  l.write(o);
  return o;
}

} // end namespace analyzer
} // end namespace crab
<commit_msg>refactor(liveness): improve precision is block is unreachable<commit_after>#pragma once

/* Liveness analysis */

//#include <crab/cfg/basic_block_traits.hpp>
#include <crab/domains/discrete_domains.hpp>
#include <crab/iterators/killgen_fixpoint_iterator.hpp>
#include <crab/support/debug.hpp>
#include <crab/support/stats.hpp>

#include <boost/range/iterator_range.hpp>
#include <unordered_map>

namespace crab {

namespace analyzer {

template <typename V>
using varset_domain = ikos::discrete_domain<V>;

/**
 * Define the main operations for the liveness variable analysis:
 * compute for each basic block the set of live variables, i.e.,
 * variables that might be used in the future
 **/
template <class CFG>
class liveness_analysis_operations
    : public crab::iterators::killgen_operations_api<
          CFG, varset_domain<typename CFG::variable_t>> {

public:
  using varset_domain_t = varset_domain<typename CFG::variable_t>;
  using basic_block_label_t = typename CFG::basic_block_label_t;

private:
  using parent_type =
      crab::iterators::killgen_operations_api<CFG, varset_domain_t>;
  using binding_t = std::pair<varset_domain_t, varset_domain_t>;
  using liveness_map_t = std::unordered_map<basic_block_label_t, binding_t>;

  liveness_map_t m_liveness_map;
public:
  liveness_analysis_operations(CFG cfg) : parent_type(cfg) {}

  virtual bool is_forward() { return false; }

  virtual varset_domain_t entry() {
    varset_domain_t res = varset_domain_t::bottom();
    if (this->m_cfg.has_func_decl()) {
      auto fdecl = this->m_cfg.get_func_decl();
      for (unsigned i = 0, e = fdecl.get_num_outputs(); i < e; ++i) {
        res += fdecl.get_output_name(i);
      }
    }
    return res;
  }

  virtual varset_domain_t merge(varset_domain_t d1, varset_domain_t d2) {
    return d1 | d2;
  }

  virtual void init_fixpoint() {
    for (auto &b :
         boost::make_iterator_range(this->m_cfg.begin(), this->m_cfg.end())) {
      bool is_unreachable_block = false;
      varset_domain_t kill, gen;
      for (auto &s : boost::make_iterator_range(b.rbegin(), b.rend())) {
	if (s.is_unreachable()) {
	  is_unreachable_block = true;
	  break;
	}
        auto const &live = s.get_live();
        for (auto d :
             boost::make_iterator_range(live.defs_begin(), live.defs_end())) {
          kill += d;
          gen -= d;
        }
        for (auto u :
             boost::make_iterator_range(live.uses_begin(), live.uses_end())) {
          gen += u;
        }
      } // end for
      if (!is_unreachable_block) {
	m_liveness_map.insert(std::make_pair(b.label(), binding_t(kill, gen)));
      }
    } // end for
  }

  virtual varset_domain_t analyze(const basic_block_label_t &bb_id,
                                  varset_domain_t in) {
    auto it = m_liveness_map.find(bb_id);
    if (it != m_liveness_map.end()) {
      in -= it->second.first;
      in += it->second.second;
    } else {
      // bb_id is unreachable
      in = varset_domain_t::bottom(); // empty set (i.e., no live variables)
    }
    return in;
  }

  virtual std::string name() { return "Liveness"; }
};

/** Live variable analysis **/
template <typename CFG>
class liveness_analysis : public crab::iterators::killgen_fixpoint_iterator<
                              CFG, liveness_analysis_operations<CFG>> {

  using liveness_analysis_operations_t = liveness_analysis_operations<CFG>;
  using killgen_fixpoint_iterator_t =
      crab::iterators::killgen_fixpoint_iterator<
          CFG, liveness_analysis_operations_t>;

  liveness_analysis(const liveness_analysis<CFG> &other) = delete;
  liveness_analysis<CFG> &
  operator=(const liveness_analysis<CFG> &other) = delete;

  using basic_block_t = typename CFG::basic_block_t;

public:
  using basic_block_label_t = typename CFG::basic_block_label_t;
  using statement_t = typename CFG::statement_t;
  using varname_t = typename CFG::varname_t;
  typedef
      typename liveness_analysis_operations_t::varset_domain_t varset_domain_t;

private:
  bool m_release_in;

public:
  liveness_analysis(CFG cfg, bool release_in = true)
      : killgen_fixpoint_iterator_t(cfg), m_release_in(release_in) {}

  void exec() {
    this->run();

    CRAB_LOG("liveness-live", for (auto p
                                   : boost::make_iterator_range(
                                       this->out_begin(), this->out_end())) {
      crab::outs() << basic_block_traits<basic_block_t>::to_string(p.first)
                   << " OUT live variables=" << p.second << "\n";
      ;
    });

    if (m_release_in) {
      this->m_in_map.clear();
    }
  }

  varset_domain_t get(const basic_block_label_t &bb) const {
    auto it = this->m_out_map.find(bb);
    if (it != this->m_out_map.end()) {
      return it->second;
    } else {
      return varset_domain_t::bottom();
    }
  }

  void write(crab_os &o) const {
    o << "TODO: print liveness analysis results\n";
  }
};

template <typename CFG>
inline crab_os &operator<<(crab_os &o, const liveness_analysis<CFG> &l) {
  l.write(o);
  return o;
}

/**
 * Live and Dead variable analysis.
 **/
template <typename CFG> class live_and_dead_analysis {
public:
  using basic_block_label_t = typename CFG::basic_block_label_t;
  using basic_block_t = typename CFG::basic_block_t;
  using statement_t = typename CFG::statement_t;
  using varname_t = typename CFG::varname_t;
  using variable_t = typename CFG::variable_t;
  using varset_domain_t = varset_domain<variable_t>;

private:
  using liveness_analysis_t = liveness_analysis<CFG>;

  // the cfg
  CFG m_cfg;
  // liveness analysis
  std::unique_ptr<liveness_analysis_t> m_live;
  // precompute dead variables might be expensive so user can choose.
  bool m_ignore_dead;
  // map basic blocks to set of dead variables at the end of the
  // blocks
  std::unordered_map<basic_block_label_t, varset_domain_t> m_dead_map;

  // statistics
  unsigned m_max_live;
  unsigned m_total_live;
  unsigned m_total_blocks;

public:
  // for backward compatibility
  // XXX: maybe unused already
  using set_t = varset_domain_t;

  // If ignore_dead is true then dead symbols are not computed.
  live_and_dead_analysis(CFG cfg, bool ignore_dead = false)
      : m_cfg(cfg), m_live(new liveness_analysis_t(m_cfg)),
        m_ignore_dead(ignore_dead), m_max_live(0), m_total_live(0),
        m_total_blocks(0) {}

  live_and_dead_analysis(const live_and_dead_analysis &other) = delete;

  live_and_dead_analysis &
  operator=(const live_and_dead_analysis &other) = delete;

  void exec() {
    m_live->exec();
    if (!m_ignore_dead) {
      crab::ScopedCrabStats __st__("Liveness.precompute_dead_variables");
      /** Remove dead variables locally **/
      for (auto &bb : boost::make_iterator_range(m_cfg.begin(), m_cfg.end())) {
        varset_domain_t live_set = m_live->get(bb.label());
        if (live_set.is_bottom())
          continue;

        varset_domain_t dead_set = m_cfg.get_node(bb.label()).live();
        // dead variables = (USE(bb) U DEF(bb)) \ live_out(bb)
        dead_set -= live_set;
        CRAB_LOG("liveness",
                 crab::outs()
                     << basic_block_traits<basic_block_t>::to_string(bb.label())
                     << " dead variables=" << dead_set << "\n";);
        m_dead_map.insert(std::make_pair(bb.label(), std::move(dead_set)));
        // update statistics
        m_total_live += live_set.size();
	if (live_set.size() > m_max_live) {
	  m_max_live = live_set.size();
	}
        m_total_blocks++;
      }
    }
  }

  // Return the set of live variables at the exit of block bb
  varset_domain_t get(const basic_block_label_t &bb) const {
    return m_live->get(bb);
  }

  // Return the set of dead variables at the exit of block bb
  varset_domain_t dead_exit(const basic_block_label_t &bb) const {
    if (m_ignore_dead) {
      CRAB_WARN("Dead variables were not precomputed during liveness analysis");
    }
    auto it = m_dead_map.find(bb);
    if (it == m_dead_map.end()) {
      return varset_domain_t();
    } else {
      return it->second;
    }
  }

  void get_stats(unsigned &total_live, unsigned &max_live_per_blk,
                 unsigned &avg_live_per_blk) const {
    total_live = m_total_live;
    max_live_per_blk = m_max_live;
    avg_live_per_blk =
        (m_total_blocks == 0 ? 0 : (int)m_total_live / m_total_blocks);
  }

  void write(crab_os &o) const {
    o << "TODO: printing dead variable analysis results\n";
  }
};

template <typename CFG>
inline crab_os &operator<<(crab_os &o, const live_and_dead_analysis<CFG> &l) {
  l.write(o);
  return o;
}

} // end namespace analyzer
} // end namespace crab
<|endoftext|>


<commit_before>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core 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 Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_DIFFERENTIABLE_FUNCTION_HH
# define HPP_CORE_DIFFERENTIABLE_FUNCTION_HH

# include <boost/algorithm/string/replace.hpp>
# include <roboptim/core/indent.hh>
# include <hpp/core/fwd.hh>

namespace hpp {
  namespace core {
    /// Differentiable function of the robot configuration
    class DifferentiableFunction
    {
    public:
      virtual ~DifferentiableFunction () {}
      /// Evaluate the function at a given parameter.
      ///
      /// \note parameters should be of the correct size.
      void operator () (vectorOut_t result,
			ConfigurationIn_t argument) const
      {
	assert (result.size () == outputSize ());
	assert (argument.size () == inputSize ());
	impl_compute (result, argument);
      }
      /// Computes the jacobian.
      ///
      /// \retval jacobian jacobian will be stored in this argument
      /// \param argument point at which the jacobian will be computed
      void jacobian (matrixOut_t jacobian, ConfigurationIn_t argument) const
      {
	assert (argument.size () == inputSize ());
	assert (jacobian.rows () == outputSize ());
	assert (jacobian.cols () == inputDerivativeSize ());
	impl_jacobian (jacobian, argument);
      }

      /// Get dimension of input vector
      size_type inputSize () const
      {
	return inputSize_;
      }
      /// Get dimension of input derivative vector
      ///
      /// The dimension of configuration vectors might differ from the dimension
      /// of velocity vectors since some joints are represented by non minimal
      /// size vectors: e.g. quaternion for SO(3)
      size_type inputDerivativeSize () const
      {
	return inputDerivativeSize_;
      }
      /// Get dimension of output vector
      size_type  outputSize () const
      {
	return outputSize_;
      }
      /// \brief Get function name.
      ///
      /// \return Function name.
      const std::string& name () const
      {
	return name_;
      }

      /// Display object in a stream
      virtual std::ostream& print (std::ostream& o) const
      {
	if (this->name ().empty ())
	  return o << "Differentiable function";

	std::stringstream ss;
	ss << std::endl;
	char fill = o.fill (' ');
	ss << std::setw ((int)roboptim::indent (o))
	   << ""
	   << std::setfill (fill);
	std::string name = this->name ();
	boost::algorithm::replace_all (name, "\n", ss.str ());

	return o << name << " (differentiable function)";
      }

      /// Check whether this function is parametric.
      /// \return True if parametric.
      bool isParametric () const
      {
        return isParametric_;
      }

      /// Make the function parametric or non-parametric.
      /// \param value True if you want a parametric projector.
      /// \note When change from true to false, the level set parameters of any
      /// ConfigProjector containing the function should be recomputed using
      /// ConfigProjector::offset.
      void isParametric (const bool& value)
      {
        isParametric_ = value;
      }

    protected:
      /// \brief Concrete class constructor should call this constructor.
      ///
      /// \param inputSize function arity
      /// \param outputSize result size
      /// \param name function's name
      DifferentiableFunction (size_type inputSize,
			      size_type inputDerivativeSize,
			      size_type outputSize,
			      std::string name = std::string ()) :
	inputSize_ (inputSize), inputDerivativeSize_ (inputDerivativeSize),
	outputSize_ (outputSize), isParametric_ (false), name_ (name)
      {
      }

      /// User implementation of function evaluation
      virtual void impl_compute (vectorOut_t result,
				 ConfigurationIn_t argument) const = 0;

      virtual void impl_jacobian (matrixOut_t jacobian,
				  ConfigurationIn_t arg) const = 0;

    private:
      /// Dimension of input vector.
      size_type inputSize_;
      /// Dimension of input derivative
      size_type inputDerivativeSize_;
      /// Dimension of output vector
      size_type outputSize_;
      /// Whether this function is parametric
      bool isParametric_;
      std::string name_;
    }; // class DifferentiableFunction
    inline std::ostream&
    operator<< (std::ostream& os, const DifferentiableFunction& f)
    {
      return f.print (os);
    }
  } // namespace core
} // namespace hpp

#endif // HPP_CORE_DIFFERENTIABLE_FUNCTION_HH
<commit_msg>Add passive dofs to DifferentiableFunction.<commit_after>//
// Copyright (c) 2014 CNRS
// Authors: Florent Lamiraux
//
// This file is part of hpp-core
// hpp-core is free software: you can redistribute it
// and/or modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation, either version
// 3 of the License, or (at your option) any later version.
//
// hpp-core 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 Lesser Public License for more details.  You should have
// received a copy of the GNU Lesser General Public License along with
// hpp-core  If not, see
// <http://www.gnu.org/licenses/>.

#ifndef HPP_CORE_DIFFERENTIABLE_FUNCTION_HH
# define HPP_CORE_DIFFERENTIABLE_FUNCTION_HH

# include <boost/algorithm/string/replace.hpp>
# include <boost/assign/list_of.hpp>
# include <roboptim/core/indent.hh>
# include <hpp/core/fwd.hh>
# include <algorithm>

namespace hpp {
  namespace core {
    /// Differentiable function of the robot configuration
    class DifferentiableFunction
    {
    public:
      typedef std::pair <size_type, size_type> Interval_t;
      typedef std::vector <Interval_t> Intervals_t;

      virtual ~DifferentiableFunction () {}
      /// Evaluate the function at a given parameter.
      ///
      /// \note parameters should be of the correct size.
      void operator () (vectorOut_t result,
			ConfigurationIn_t argument) const
      {
	assert (result.size () == outputSize ());
	assert (argument.size () == inputSize ());
	impl_compute (result, argument);
      }
      /// Computes the jacobian.
      ///
      /// \retval jacobian jacobian will be stored in this argument
      /// \param argument point at which the jacobian will be computed
      void jacobian (matrixOut_t jacobian, ConfigurationIn_t argument) const
      {
	assert (argument.size () == inputSize ());
	assert (jacobian.rows () == outputSize ());
	assert (jacobian.cols () == inputDerivativeSize ());
	impl_jacobian (jacobian, argument);
        for (size_t i = 0; i < passiveDofs_.size(); i++)
          jacobian.middleCols (passiveDofs_[i].first, passiveDofs_[i].second).setZero ();
      }

      /// Get dimension of input vector
      size_type inputSize () const
      {
	return inputSize_;
      }
      /// Get dimension of input derivative vector
      ///
      /// The dimension of configuration vectors might differ from the dimension
      /// of velocity vectors since some joints are represented by non minimal
      /// size vectors: e.g. quaternion for SO(3)
      size_type inputDerivativeSize () const
      {
	return inputDerivativeSize_;
      }
      /// Get dimension of output vector
      size_type  outputSize () const
      {
	return outputSize_;
      }
      /// \brief Get function name.
      ///
      /// \return Function name.
      const std::string& name () const
      {
	return name_;
      }

      /// Display object in a stream
      virtual std::ostream& print (std::ostream& o) const
      {
	if (this->name ().empty ())
	  return o << "Differentiable function";

	std::stringstream ss;
	ss << std::endl;
	char fill = o.fill (' ');
	ss << std::setw ((int)roboptim::indent (o))
	   << ""
	   << std::setfill (fill);
	std::string name = this->name ();
	boost::algorithm::replace_all (name, "\n", ss.str ());

	return o << name << " (differentiable function)";
      }

      /// Check whether this function is parametric.
      /// \return True if parametric.
      bool isParametric () const
      {
        return isParametric_;
      }

      /// Make the function parametric or non-parametric.
      /// \param value True if you want a parametric projector.
      /// \note When change from true to false, the level set parameters of any
      /// ConfigProjector containing the function should be recomputed using
      /// ConfigProjector::offset.
      void isParametric (const bool& value)
      {
        isParametric_ = value;
      }

      /// Set passive DOFs. Passive DOF cannot be modified by this function.
      /// Corresponding columns of the jacobian are set to zero.
      const Intervals_t& passiveDofs (std::vector <size_type> dofs)
      {
        passiveDofs_.clear ();
        if (dofs.size () == 0) return passiveDofs_;
        std::sort (dofs.begin (), dofs.end ());
        std::vector <size_type>::iterator it =
          std::unique (dofs.begin (), dofs.end ());
        dofs.resize (std::distance (dofs.begin (), it));
        dofs.push_back (inputDerivativeSize_ + 1);
        size_type intStart = dofs[0], intEnd = dofs[0];
        for (size_t i = 1; i < dofs.size (); i++) {
          intEnd ++;
          if (intEnd == dofs[i]) {
            continue;
          } else {
            passiveDofs_.push_back (Interval_t (intStart, intEnd - intStart));
            intStart = intEnd = dofs[i];
          }
        }
        return passiveDofs_;
      }

    protected:
      /// \brief Concrete class constructor should call this constructor.
      ///
      /// \param inputSize function arity
      /// \param outputSize result size
      /// \param name function's name
      DifferentiableFunction (size_type inputSize,
			      size_type inputDerivativeSize,
			      size_type outputSize,
			      std::string name = std::string ()) :
	inputSize_ (inputSize), inputDerivativeSize_ (inputDerivativeSize),
	outputSize_ (outputSize), isParametric_ (false),
       passiveDofs_ (), name_ (name)
      {
      }

      /// User implementation of function evaluation
      virtual void impl_compute (vectorOut_t result,
				 ConfigurationIn_t argument) const = 0;

      virtual void impl_jacobian (matrixOut_t jacobian,
				  ConfigurationIn_t arg) const = 0;

    private:
      /// Dimension of input vector.
      size_type inputSize_;
      /// Dimension of input derivative
      size_type inputDerivativeSize_;
      /// Dimension of output vector
      size_type outputSize_;
      /// Whether this function is parametric
      bool isParametric_;
      /// Intervals of passive dofs
      Intervals_t passiveDofs_;
      std::string name_;
    }; // class DifferentiableFunction
    inline std::ostream&
    operator<< (std::ostream& os, const DifferentiableFunction& f)
    {
      return f.print (os);
    }
  } // namespace core
} // namespace hpp

#endif // HPP_CORE_DIFFERENTIABLE_FUNCTION_HH
<|endoftext|>