/* This file is part of the Pangolin Project. * http://github.com/stevenlovegrove/Pangolin * * Copyright (c) 2011 Steven Lovegrove * * 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. */ #pragma once #include #include #include #include #include namespace pangolin { PyObject* GetPangoVarAsPython(const std::string& name) { VarState::VarStoreContainer::iterator i = VarState::I().vars.find(name); if(i != VarState::I().vars.end()) { VarValueGeneric* var = i->second; try{ if( !strcmp(var->TypeId(), typeid(bool).name() ) ) { const bool val = Var(*var).Get(); return PyBool_FromLong( val ); }else if( !strcmp(var->TypeId(), typeid(short).name() ) || !strcmp(var->TypeId(), typeid(int).name() ) || !strcmp(var->TypeId(), typeid(long).name() ) ) { const long val = Var(*var).Get(); return PyLong_FromLong( val ); }else if( !strcmp(var->TypeId(), typeid(double).name() ) || !strcmp(var->TypeId(), typeid(float).name() ) ) { const double val = Var(*var).Get(); return PyFloat_FromDouble(val); }else{ const std::string val = var->str->Get(); #if PY_MAJOR_VERSION >= 3 return PyUnicode_FromString(val.c_str()); #else return PyString_FromString(val.c_str()); #endif } }catch(const std::exception&) { } } Py_RETURN_NONE; } void SetPangoVarFromPython(const std::string& name, PyObject* val) { try{ if (PyFloat_Check(val)) { pangolin::Var pango_var(name); pango_var = PyFloat_AsDouble(val); pango_var.Meta().gui_changed = true; }else if (PyLong_Check(val)) { pangolin::Var pango_var(name); pango_var = PyLong_AsLong(val); pango_var.Meta().gui_changed = true; }else if (PyBool_Check(val)) { pangolin::Var pango_var(name); pango_var = (val == Py_True) ? true : false; pango_var.Meta().gui_changed = true; } #if PY_MAJOR_VERSION >= 3 else if (PyUnicode_Check(val)) { pangolin::Var pango_var(name); pango_var = PyUnicode_AsUTF8(val); pango_var.Meta().gui_changed = true; } #else else if (PyString_Check(val)) { pangolin::Var pango_var(name); pango_var = PyString_AsString(val); pango_var.Meta().gui_changed = true; } else if (PyInt_Check(val)) { pangolin::Var pango_var(name); pango_var = PyInt_AsLong(val); pango_var.Meta().gui_changed = true; } #endif else { PyUniqueObj pystr = PyObject_Repr(val); #if PY_MAJOR_VERSION >= 3 const std::string str = PyUnicode_AsUTF8(pystr); #else const std::string str = PyString_AsString(pystr); #endif pangolin::Var pango_var(name); pango_var = str; pango_var.Meta().gui_changed = true; } FlagVarChanged(); }catch(const std::exception& e) { pango_print_error("%s\n", e.what()); } } struct PyVar { static PyTypeObject Py_type; PyObject_HEAD PyVar(PyTypeObject *type) { #if PY_MAJOR_VERSION >= 3 ob_base.ob_refcnt = 1; ob_base.ob_type = type; #else ob_refcnt = 1; ob_type = type; #endif } static void Py_dealloc(PyVar* self) { delete self; } static PyObject * Py_new(PyTypeObject *type, PyObject * /*args*/, PyObject * /*kwds*/) { PyVar* self = new PyVar(type); return (PyObject *)self; } static int Py_init(PyVar *self, PyObject *args, PyObject * /*kwds*/) { char* cNamespace = 0; if (!PyArg_ParseTuple(args, "s", &cNamespace)) return -1; self->ns = std::string(cNamespace); return 0; } static PyObject* Py_getattr(PyVar *self, char* name) { const std::string prefix = self->ns + "."; const std::string full_name = self->ns.empty() ? name : prefix + std::string(name); if( !strcmp(name, "__call__") || !strcmp(name, "__dict__") || !strcmp(name, "__methods__") || !strcmp(name, "__class__") ) { // Default behaviour #if PY_MAJOR_VERSION >= 3 return PyObject_GenericGetAttr((PyObject*)self, PyUnicode_FromString(name)); #else return PyObject_GenericGetAttr((PyObject*)self, PyString_FromString(name)); #endif } else if( !strcmp(name, "__members__") ) { const int nss = prefix.size(); PyObject* l = PyList_New(0); for(const std::string& s : VarState::I().var_adds) { if(!s.compare(0, nss, prefix)) { size_t dot = s.find_first_of('.', nss); std::string val = (dot != std::string::npos) ? s.substr(nss, dot - nss) : s.substr(nss); #if PY_MAJOR_VERSION >= 3 PyList_Append(l, PyUnicode_FromString(val.c_str())); #else PyList_Append(l, PyString_FromString(val.c_str())); #endif } } return l; }else if( pangolin::VarState::I().Exists(full_name) ) { return GetPangoVarAsPython(full_name); }else{ PyVar* obj = (PyVar*)PyVar::Py_new(&PyVar::Py_type,NULL,NULL); if(obj) { obj->ns = full_name; return PyObject_Init((PyObject *)obj,&PyVar::Py_type); } return (PyObject *)obj; } Py_RETURN_NONE; } static int Py_setattr(PyVar *self, char* name, PyObject* val) { const std::string full_name = self->ns.empty() ? name : self->ns + "." + std::string(name); SetPangoVarFromPython(full_name, val); return 0; } std::string ns; }; // The uninitialized variable can be ignored. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmissing-field-initializers" PyTypeObject PyVar::Py_type = { PyVarObject_HEAD_INIT(NULL,0) "pypangolin.Var", /* tp_name*/ sizeof(PyVar), /* tp_basicsize*/ 0, /* tp_itemsize*/ (destructor)PyVar::Py_dealloc, /* tp_dealloc*/ 0, /* tp_print*/ (getattrfunc)PyVar::Py_getattr, /* tp_getattr*/ (setattrfunc)PyVar::Py_setattr, /* tp_setattr*/ 0, /* tp_compare*/ 0, /* tp_repr*/ 0, /* tp_as_number*/ 0, /* tp_as_sequence*/ 0, /* tp_as_mapping*/ 0, /* tp_hash */ 0, /* tp_call*/ 0, /* tp_str*/ 0, /* tp_getattro*/ 0, /* tp_setattro*/ 0, /* tp_as_buffer*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags*/ "PyVar object", /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ 0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ (initproc)PyVar::Py_init, /* tp_init */ 0, /* tp_alloc */ (newfunc)PyVar::Py_new, /* tp_new */ 0, /* tp_free */ 0, /* tp_is_gc */ 0, /* tp_bases */ 0, /* tp_mro */ 0, /* tp_cache */ 0, /* tp_subclasses */ 0, /* tp_weaklist */ 0, /* tp_del */ 0 /* tp_version_tag */ }; #pragma GCC diagnostic pop }