With the increased use of multi-character format units and keyword-only arguments these are increasingly difficult to make sense of. Split the string onto multiple lines, one per argument. While verbose it's easier to understand and add new arguments.
658 lines
20 KiB
C
658 lines
20 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
/** \file
|
|
* \ingroup pythonintern
|
|
*
|
|
* This file defines utility methods for `bpy.types.Gizmo`.
|
|
*/
|
|
|
|
#include <Python.h>
|
|
#include <stddef.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "BLI_alloca.h"
|
|
#include "BLI_utildefines.h"
|
|
|
|
#include "WM_api.h"
|
|
#include "WM_types.h"
|
|
|
|
#include "bpy_capi_utils.h"
|
|
#include "bpy_rna_gizmo.h"
|
|
|
|
#include "../generic/py_capi_utils.h"
|
|
#include "../generic/python_utildefines.h"
|
|
|
|
#include "RNA_access.h"
|
|
#include "RNA_enum_types.h"
|
|
#include "RNA_prototypes.h"
|
|
#include "RNA_types.h"
|
|
|
|
#include "bpy_rna.h"
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Parsing Utility Functions
|
|
*
|
|
* Functions used as callbacks for #PyArg_ParseTuple `O&` format string.
|
|
* \{ */
|
|
|
|
struct BPyGizmoWithTarget {
|
|
wmGizmo *gz; /* Must be first. */
|
|
wmGizmoProperty *gz_prop;
|
|
};
|
|
|
|
struct BPyGizmoWithTargetType {
|
|
wmGizmo *gz; /* Must be first. */
|
|
const wmGizmoPropertyType *gz_prop_type;
|
|
};
|
|
|
|
static int py_rna_gizmo_parse(PyObject *o, void *p)
|
|
{
|
|
/* No type checking (this is `self` not a user defined argument). */
|
|
BLI_assert(BPy_StructRNA_Check(o));
|
|
BLI_assert(RNA_struct_is_a(((const BPy_StructRNA *)o)->ptr.type, &RNA_Gizmo));
|
|
|
|
wmGizmo **gz_p = p;
|
|
*gz_p = ((const BPy_StructRNA *)o)->ptr.data;
|
|
return 1;
|
|
}
|
|
|
|
static int py_rna_gizmo_target_id_parse(PyObject *o, void *p)
|
|
{
|
|
struct BPyGizmoWithTarget *gizmo_with_target = p;
|
|
/* Must be set by `py_rna_gizmo_parse`. */
|
|
wmGizmo *gz = gizmo_with_target->gz;
|
|
BLI_assert(gz != NULL);
|
|
|
|
if (!PyUnicode_Check(o)) {
|
|
PyErr_Format(PyExc_TypeError, "expected a string (got %.200s)", Py_TYPE(o)->tp_name);
|
|
return 0;
|
|
}
|
|
const char *gz_prop_id = PyUnicode_AsUTF8(o);
|
|
wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, gz_prop_id);
|
|
if (gz_prop == NULL) {
|
|
PyErr_Format(PyExc_ValueError,
|
|
"Gizmo target property '%s.%s' not found!",
|
|
gz->type->idname,
|
|
gz_prop_id);
|
|
return 0;
|
|
}
|
|
gizmo_with_target->gz_prop = gz_prop;
|
|
return 1;
|
|
}
|
|
|
|
static int py_rna_gizmo_target_id_parse_and_ensure_is_valid(PyObject *o, void *p)
|
|
{
|
|
if (py_rna_gizmo_target_id_parse(o, p) == 0) {
|
|
return 0;
|
|
}
|
|
struct BPyGizmoWithTarget *gizmo_with_target = p;
|
|
wmGizmo *gz = gizmo_with_target->gz;
|
|
wmGizmoProperty *gz_prop = gizmo_with_target->gz_prop;
|
|
if (!WM_gizmo_target_property_is_valid(gz_prop)) {
|
|
const char *gz_prop_id = PyUnicode_AsUTF8(o);
|
|
PyErr_Format(PyExc_ValueError,
|
|
"Gizmo target property '%s.%s' has not been initialized, "
|
|
"Call \"target_set_prop\" first!",
|
|
gz->type->idname,
|
|
gz_prop_id);
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
static int py_rna_gizmo_target_type_id_parse(PyObject *o, void *p)
|
|
{
|
|
struct BPyGizmoWithTargetType *gizmo_with_target = p;
|
|
/* Must be set first. */
|
|
wmGizmo *gz = gizmo_with_target->gz;
|
|
BLI_assert(gz != NULL);
|
|
|
|
if (!PyUnicode_Check(o)) {
|
|
PyErr_Format(PyExc_TypeError, "expected a string (got %.200s)", Py_TYPE(o)->tp_name);
|
|
return 0;
|
|
}
|
|
const char *gz_prop_id = PyUnicode_AsUTF8(o);
|
|
const wmGizmoPropertyType *gz_prop_type = WM_gizmotype_target_property_find(gz->type,
|
|
gz_prop_id);
|
|
if (gz_prop_type == NULL) {
|
|
PyErr_Format(PyExc_ValueError,
|
|
"Gizmo target property '%s.%s' not found!",
|
|
gz->type->idname,
|
|
gz_prop_id);
|
|
return 0;
|
|
}
|
|
gizmo_with_target->gz_prop_type = gz_prop_type;
|
|
return 1;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Gizmo Target Property Define API
|
|
* \{ */
|
|
|
|
enum {
|
|
BPY_GIZMO_FN_SLOT_GET = 0,
|
|
BPY_GIZMO_FN_SLOT_SET,
|
|
BPY_GIZMO_FN_SLOT_RANGE_GET,
|
|
};
|
|
#define BPY_GIZMO_FN_SLOT_LEN (BPY_GIZMO_FN_SLOT_RANGE_GET + 1)
|
|
|
|
struct BPyGizmoHandlerUserData {
|
|
|
|
PyObject *fn_slots[BPY_GIZMO_FN_SLOT_LEN];
|
|
};
|
|
|
|
static void py_rna_gizmo_handler_get_cb(const wmGizmo *UNUSED(gz),
|
|
wmGizmoProperty *gz_prop,
|
|
void *value_p)
|
|
{
|
|
const PyGILState_STATE gilstate = PyGILState_Ensure();
|
|
|
|
struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data;
|
|
PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_GET], NULL);
|
|
if (ret == NULL) {
|
|
goto fail;
|
|
}
|
|
|
|
if (gz_prop->type->data_type == PROP_FLOAT) {
|
|
float *value = value_p;
|
|
if (gz_prop->type->array_length == 1) {
|
|
if ((*value = PyFloat_AsDouble(ret)) == -1.0f && PyErr_Occurred()) {
|
|
goto fail;
|
|
}
|
|
}
|
|
else {
|
|
if (PyC_AsArray(value,
|
|
sizeof(*value),
|
|
ret,
|
|
gz_prop->type->array_length,
|
|
&PyFloat_Type,
|
|
"Gizmo get callback: ") == -1) {
|
|
goto fail;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
|
|
goto fail;
|
|
}
|
|
|
|
Py_DECREF(ret);
|
|
|
|
PyGILState_Release(gilstate);
|
|
return;
|
|
|
|
fail:
|
|
PyErr_Print();
|
|
PyErr_Clear();
|
|
|
|
Py_XDECREF(ret);
|
|
|
|
PyGILState_Release(gilstate);
|
|
}
|
|
|
|
static void py_rna_gizmo_handler_set_cb(const wmGizmo *UNUSED(gz),
|
|
wmGizmoProperty *gz_prop,
|
|
const void *value_p)
|
|
{
|
|
const PyGILState_STATE gilstate = PyGILState_Ensure();
|
|
|
|
struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data;
|
|
|
|
PyObject *args = PyTuple_New(1);
|
|
|
|
if (gz_prop->type->data_type == PROP_FLOAT) {
|
|
const float *value = value_p;
|
|
PyObject *py_value;
|
|
if (gz_prop->type->array_length == 1) {
|
|
py_value = PyFloat_FromDouble(*value);
|
|
}
|
|
else {
|
|
py_value = PyC_Tuple_PackArray_F32(value, gz_prop->type->array_length);
|
|
}
|
|
if (py_value == NULL) {
|
|
goto fail;
|
|
}
|
|
PyTuple_SET_ITEM(args, 0, py_value);
|
|
}
|
|
else {
|
|
PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
|
|
goto fail;
|
|
}
|
|
|
|
PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_SET], args);
|
|
if (ret == NULL) {
|
|
goto fail;
|
|
}
|
|
Py_DECREF(args);
|
|
Py_DECREF(ret);
|
|
|
|
PyGILState_Release(gilstate);
|
|
return;
|
|
|
|
fail:
|
|
PyErr_Print();
|
|
PyErr_Clear();
|
|
|
|
Py_DECREF(args);
|
|
|
|
PyGILState_Release(gilstate);
|
|
}
|
|
|
|
static void py_rna_gizmo_handler_range_get_cb(const wmGizmo *UNUSED(gz),
|
|
wmGizmoProperty *gz_prop,
|
|
void *value_p)
|
|
{
|
|
struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data;
|
|
|
|
const PyGILState_STATE gilstate = PyGILState_Ensure();
|
|
|
|
PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_RANGE_GET], NULL);
|
|
if (ret == NULL) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!PyTuple_Check(ret)) {
|
|
PyErr_Format(PyExc_TypeError, "Expected a tuple, not %.200s", Py_TYPE(ret)->tp_name);
|
|
goto fail;
|
|
}
|
|
|
|
if (PyTuple_GET_SIZE(ret) != 2) {
|
|
PyErr_Format(PyExc_TypeError, "Expected a tuple of size 2, not %d", PyTuple_GET_SIZE(ret));
|
|
goto fail;
|
|
}
|
|
|
|
if (gz_prop->type->data_type == PROP_FLOAT) {
|
|
float range[2];
|
|
for (int i = 0; i < 2; i++) {
|
|
if (((range[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(ret, i))) == -1.0f && PyErr_Occurred()) ==
|
|
0) {
|
|
/* pass */
|
|
}
|
|
else {
|
|
goto fail;
|
|
}
|
|
}
|
|
memcpy(value_p, range, sizeof(range));
|
|
}
|
|
else {
|
|
PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
|
|
goto fail;
|
|
}
|
|
|
|
Py_DECREF(ret);
|
|
PyGILState_Release(gilstate);
|
|
return;
|
|
|
|
fail:
|
|
PyErr_Print();
|
|
PyErr_Clear();
|
|
|
|
Py_XDECREF(ret);
|
|
|
|
PyGILState_Release(gilstate);
|
|
}
|
|
|
|
static void py_rna_gizmo_handler_free_cb(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop)
|
|
{
|
|
struct BPyGizmoHandlerUserData *data = gz_prop->custom_func.user_data;
|
|
|
|
const PyGILState_STATE gilstate = PyGILState_Ensure();
|
|
for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
|
|
Py_XDECREF(data->fn_slots[i]);
|
|
}
|
|
PyGILState_Release(gilstate);
|
|
|
|
MEM_freeN(data);
|
|
}
|
|
|
|
PyDoc_STRVAR(
|
|
bpy_gizmo_target_set_handler_doc,
|
|
".. method:: target_set_handler(target, get, set, range=None):\n"
|
|
"\n"
|
|
" Assigns callbacks to a gizmos property.\n"
|
|
"\n"
|
|
" :arg get: Function that returns the value for this property (single value or sequence).\n"
|
|
" :type get: callable\n"
|
|
" :arg set: Function that takes a single value argument and applies it.\n"
|
|
" :type set: callable\n"
|
|
" :arg range: Function that returns a (min, max) tuple for gizmos that use a range.\n"
|
|
" :type range: callable\n");
|
|
static PyObject *bpy_gizmo_target_set_handler(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
|
|
{
|
|
const PyGILState_STATE gilstate = PyGILState_Ensure();
|
|
|
|
struct {
|
|
struct BPyGizmoWithTargetType gz_with_target_type;
|
|
PyObject *py_fn_slots[BPY_GIZMO_FN_SLOT_LEN];
|
|
} params = {
|
|
.gz_with_target_type = {NULL, NULL},
|
|
.py_fn_slots = {NULL},
|
|
};
|
|
|
|
/* NOTE: this is a counter-part to functions:
|
|
* 'Gizmo.target_set_prop & target_set_operator'
|
|
* (see: rna_wm_gizmo_api.c). conventions should match. */
|
|
static const char *const _keywords[] = {"self", "target", "get", "set", "range", NULL};
|
|
static _PyArg_Parser _parser = {
|
|
"O&" /* `self` */
|
|
"O&" /* `target` */
|
|
"|$" /* Optional keyword only arguments. */
|
|
"O" /* `get` */
|
|
"O" /* `set` */
|
|
"O" /* `range` */
|
|
":target_set_handler",
|
|
_keywords,
|
|
0,
|
|
};
|
|
if (!_PyArg_ParseTupleAndKeywordsFast(args,
|
|
kw,
|
|
&_parser,
|
|
/* `self` */
|
|
py_rna_gizmo_parse,
|
|
¶ms.gz_with_target_type.gz,
|
|
/* `target` */
|
|
py_rna_gizmo_target_type_id_parse,
|
|
¶ms.gz_with_target_type,
|
|
/* `get/set/range` */
|
|
¶ms.py_fn_slots[BPY_GIZMO_FN_SLOT_GET],
|
|
¶ms.py_fn_slots[BPY_GIZMO_FN_SLOT_SET],
|
|
¶ms.py_fn_slots[BPY_GIZMO_FN_SLOT_RANGE_GET])) {
|
|
goto fail;
|
|
}
|
|
|
|
wmGizmo *gz = params.gz_with_target_type.gz;
|
|
const wmGizmoPropertyType *gz_prop_type = params.gz_with_target_type.gz_prop_type;
|
|
|
|
{
|
|
const int slots_required = 2;
|
|
const int slots_start = 2;
|
|
for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
|
|
if (params.py_fn_slots[i] == NULL) {
|
|
if (i < slots_required) {
|
|
PyErr_Format(PyExc_ValueError, "Argument '%s' not given", _keywords[slots_start + i]);
|
|
goto fail;
|
|
}
|
|
}
|
|
else if (!PyCallable_Check(params.py_fn_slots[i])) {
|
|
PyErr_Format(PyExc_ValueError, "Argument '%s' not callable", _keywords[slots_start + i]);
|
|
goto fail;
|
|
}
|
|
}
|
|
}
|
|
|
|
struct BPyGizmoHandlerUserData *data = MEM_callocN(sizeof(*data), __func__);
|
|
|
|
for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
|
|
data->fn_slots[i] = params.py_fn_slots[i];
|
|
Py_XINCREF(params.py_fn_slots[i]);
|
|
}
|
|
|
|
WM_gizmo_target_property_def_func_ptr(gz,
|
|
gz_prop_type,
|
|
&(const struct wmGizmoPropertyFnParams){
|
|
.value_get_fn = py_rna_gizmo_handler_get_cb,
|
|
.value_set_fn = py_rna_gizmo_handler_set_cb,
|
|
.range_get_fn = py_rna_gizmo_handler_range_get_cb,
|
|
.free_fn = py_rna_gizmo_handler_free_cb,
|
|
.user_data = data,
|
|
});
|
|
|
|
PyGILState_Release(gilstate);
|
|
|
|
Py_RETURN_NONE;
|
|
|
|
fail:
|
|
PyGILState_Release(gilstate);
|
|
return NULL;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Gizmo Target Property Access API
|
|
* \{ */
|
|
|
|
PyDoc_STRVAR(bpy_gizmo_target_get_value_doc,
|
|
".. method:: target_get_value(target):\n"
|
|
"\n"
|
|
" Get the value of this target property.\n"
|
|
"\n"
|
|
" :arg target: Target property name.\n"
|
|
" :type target: string\n"
|
|
" :return: The value of the target property.\n"
|
|
" :rtype: Single value or array based on the target type\n");
|
|
static PyObject *bpy_gizmo_target_get_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
|
|
{
|
|
struct {
|
|
struct BPyGizmoWithTarget gz_with_target;
|
|
} params = {
|
|
.gz_with_target = {NULL, NULL},
|
|
};
|
|
|
|
static const char *const _keywords[] = {"self", "target", NULL};
|
|
static _PyArg_Parser _parser = {
|
|
"O&" /* `self` */
|
|
"O&" /* `target` */
|
|
":target_get_value",
|
|
_keywords,
|
|
0,
|
|
};
|
|
if (!_PyArg_ParseTupleAndKeywordsFast(args,
|
|
kw,
|
|
&_parser,
|
|
/* `self` */
|
|
py_rna_gizmo_parse,
|
|
¶ms.gz_with_target.gz,
|
|
/* `target` */
|
|
py_rna_gizmo_target_id_parse_and_ensure_is_valid,
|
|
¶ms.gz_with_target)) {
|
|
goto fail;
|
|
}
|
|
|
|
wmGizmo *gz = params.gz_with_target.gz;
|
|
wmGizmoProperty *gz_prop = params.gz_with_target.gz_prop;
|
|
|
|
const int array_len = WM_gizmo_target_property_array_length(gz, gz_prop);
|
|
switch (gz_prop->type->data_type) {
|
|
case PROP_FLOAT: {
|
|
if (array_len != 0) {
|
|
float *value = BLI_array_alloca(value, array_len);
|
|
WM_gizmo_target_property_float_get_array(gz, gz_prop, value);
|
|
return PyC_Tuple_PackArray_F32(value, array_len);
|
|
}
|
|
|
|
const float value = WM_gizmo_target_property_float_get(gz, gz_prop);
|
|
return PyFloat_FromDouble(value);
|
|
|
|
break;
|
|
}
|
|
default: {
|
|
PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
PyDoc_STRVAR(bpy_gizmo_target_set_value_doc,
|
|
".. method:: target_set_value(target):\n"
|
|
"\n"
|
|
" Set the value of this target property.\n"
|
|
"\n"
|
|
" :arg target: Target property name.\n"
|
|
" :type target: string\n");
|
|
static PyObject *bpy_gizmo_target_set_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
|
|
{
|
|
struct {
|
|
struct BPyGizmoWithTarget gz_with_target;
|
|
PyObject *value;
|
|
} params = {
|
|
.gz_with_target = {NULL, NULL},
|
|
.value = NULL,
|
|
};
|
|
|
|
static const char *const _keywords[] = {"self", "target", "value", NULL};
|
|
static _PyArg_Parser _parser = {
|
|
"O&" /* `self` */
|
|
"O&" /* `target` */
|
|
"O" /* `value` */
|
|
":target_set_value",
|
|
_keywords,
|
|
0,
|
|
};
|
|
if (!_PyArg_ParseTupleAndKeywordsFast(args,
|
|
kw,
|
|
&_parser,
|
|
/* `self` */
|
|
py_rna_gizmo_parse,
|
|
¶ms.gz_with_target.gz,
|
|
/* `target` */
|
|
py_rna_gizmo_target_id_parse_and_ensure_is_valid,
|
|
¶ms.gz_with_target,
|
|
/* `value` */
|
|
¶ms.value)) {
|
|
goto fail;
|
|
}
|
|
|
|
wmGizmo *gz = params.gz_with_target.gz;
|
|
wmGizmoProperty *gz_prop = params.gz_with_target.gz_prop;
|
|
|
|
const int array_len = WM_gizmo_target_property_array_length(gz, gz_prop);
|
|
switch (gz_prop->type->data_type) {
|
|
case PROP_FLOAT: {
|
|
if (array_len != 0) {
|
|
float *value = BLI_array_alloca(value, array_len);
|
|
if (PyC_AsArray(value,
|
|
sizeof(*value),
|
|
params.value,
|
|
gz_prop->type->array_length,
|
|
&PyFloat_Type,
|
|
"Gizmo target property array: ") == -1) {
|
|
goto fail;
|
|
}
|
|
WM_gizmo_target_property_float_set_array(BPY_context_get(), gz, gz_prop, value);
|
|
}
|
|
else {
|
|
float value;
|
|
if ((value = PyFloat_AsDouble(params.value)) == -1.0f && PyErr_Occurred()) {
|
|
goto fail;
|
|
}
|
|
WM_gizmo_target_property_float_set(BPY_context_get(), gz, gz_prop, value);
|
|
}
|
|
Py_RETURN_NONE;
|
|
}
|
|
default: {
|
|
PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
PyDoc_STRVAR(bpy_gizmo_target_get_range_doc,
|
|
".. method:: target_get_range(target):\n"
|
|
"\n"
|
|
" Get the range for this target property.\n"
|
|
"\n"
|
|
" :arg target: Target property name.\n"
|
|
" :return: The range of this property (min, max).\n"
|
|
" :rtype: tuple pair.\n");
|
|
static PyObject *bpy_gizmo_target_get_range(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
|
|
{
|
|
struct {
|
|
struct BPyGizmoWithTarget gz_with_target;
|
|
} params = {
|
|
.gz_with_target = {NULL, NULL},
|
|
};
|
|
|
|
static const char *const _keywords[] = {"self", "target", NULL};
|
|
static _PyArg_Parser _parser = {
|
|
"O&" /* `self` */
|
|
"O&" /* `target` */
|
|
":target_get_range",
|
|
_keywords,
|
|
0,
|
|
};
|
|
if (!_PyArg_ParseTupleAndKeywordsFast(args,
|
|
kw,
|
|
&_parser,
|
|
/* `self` */
|
|
py_rna_gizmo_parse,
|
|
¶ms.gz_with_target.gz,
|
|
/* `target` */
|
|
py_rna_gizmo_target_id_parse_and_ensure_is_valid,
|
|
¶ms.gz_with_target)) {
|
|
goto fail;
|
|
}
|
|
|
|
wmGizmo *gz = params.gz_with_target.gz;
|
|
wmGizmoProperty *gz_prop = params.gz_with_target.gz_prop;
|
|
|
|
switch (gz_prop->type->data_type) {
|
|
case PROP_FLOAT: {
|
|
float range[2];
|
|
WM_gizmo_target_property_float_range_get(gz, gz_prop, range);
|
|
return PyC_Tuple_PackArray_F32(range, 2);
|
|
}
|
|
default: {
|
|
PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
|
|
goto fail;
|
|
}
|
|
}
|
|
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
/** \} */
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/** \name Gizmo Module
|
|
* \{ */
|
|
|
|
bool BPY_rna_gizmo_module(PyObject *mod_par)
|
|
{
|
|
static PyMethodDef method_def_array[] = {
|
|
/* Gizmo Target Property Define API */
|
|
{"target_set_handler",
|
|
(PyCFunction)bpy_gizmo_target_set_handler,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
bpy_gizmo_target_set_handler_doc},
|
|
/* Gizmo Target Property Access API */
|
|
{"target_get_value",
|
|
(PyCFunction)bpy_gizmo_target_get_value,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
bpy_gizmo_target_get_value_doc},
|
|
{"target_set_value",
|
|
(PyCFunction)bpy_gizmo_target_set_value,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
bpy_gizmo_target_set_value_doc},
|
|
{"target_get_range",
|
|
(PyCFunction)bpy_gizmo_target_get_range,
|
|
METH_VARARGS | METH_KEYWORDS,
|
|
bpy_gizmo_target_get_range_doc},
|
|
/* no sentinel needed. */
|
|
};
|
|
|
|
for (int i = 0; i < ARRAY_SIZE(method_def_array); i++) {
|
|
PyMethodDef *m = &method_def_array[i];
|
|
PyObject *func = PyCFunction_New(m, NULL);
|
|
PyObject *func_inst = PyInstanceMethod_New(func);
|
|
char name_prefix[128];
|
|
PyOS_snprintf(name_prefix, sizeof(name_prefix), "_rna_gizmo_%s", m->ml_name);
|
|
/* TODO: return a type that binds nearly to a method. */
|
|
PyModule_AddObject(mod_par, name_prefix, func_inst);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/** \} */
|