Manipulator: Add API target_get/set/range wrappers

Allows Python manipulators access the values of target properties
needed for Python to make use of the general target property interface.
This commit is contained in:
Campbell Barton 2017-08-22 18:55:19 +10:00
parent bd935b5aed
commit f4fe405da9
3 changed files with 313 additions and 11 deletions

@ -618,7 +618,12 @@ class Manipulator(StructRNA, metaclass=OrderedMeta):
return delattr(properties, attr)
return super().__delattr__(attr)
target_set_handler = _bpy._rna_manipulator_target_set_handler
from _bpy import (
_rna_manipulator_target_set_handler as target_set_handler,
_rna_manipulator_target_get_value as target_get_value,
_rna_manipulator_target_set_value as target_set_value,
_rna_manipulator_target_get_range as target_get_range,
)
# Convenience wrappers around private `_gawain` module.
def draw_custom_shape(self, shape, *, matrix=None, select_id=None):

@ -71,6 +71,10 @@ static void rna_manipulator_draw_preset_facemap(
ED_manipulator_draw_preset_facemap(C, mpr, scene, ob, facemap, select_id);
}
/* -------------------------------------------------------------------- */
/** \name Manipulator Property Define
* \{ */
static void rna_manipulator_target_set_prop(
wmManipulator *mpr, ReportList *reports, const char *target_propname,
PointerRNA *ptr, const char *propname, int index)
@ -158,6 +162,27 @@ static PointerRNA rna_manipulator_target_set_operator(
return mpr->op_data.ptr;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Manipulator Property Access
* \{ */
static int rna_manipulator_target_is_valid(
wmManipulator *mpr, ReportList *reports, const char *target_propname)
{
wmManipulatorProperty *mpr_prop =
WM_manipulator_target_property_find(mpr, target_propname);
if (mpr_prop == NULL) {
BKE_reportf(reports, RPT_ERROR, "Manipulator target property '%s.%s' not found",
mpr->type->idname, target_propname);
return false;
}
return WM_manipulator_target_property_is_valid(mpr_prop);
}
/** \} */
#else
void RNA_api_manipulator(StructRNA *srna)
@ -218,6 +243,7 @@ void RNA_api_manipulator(StructRNA *srna)
/* -------------------------------------------------------------------- */
/* Property API */
/* Define Properties */
/* note, 'target_set_handler' is defined in 'bpy_rna_manipulator.c' */
func = RNA_def_function(srna, "target_set_prop", "rna_manipulator_target_set_prop");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
@ -243,6 +269,16 @@ void RNA_api_manipulator(StructRNA *srna)
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
RNA_def_function_return(func, parm);
/* Access Properties */
/* note, 'target_get', 'target_set' is defined in 'bpy_rna_manipulator.c' */
func = RNA_def_function(srna, "target_is_valid", "rna_manipulator_target_is_valid");
RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_string(func, "property", NULL, 0, "", "Property identifier");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
RNA_def_function_ui_description(func, "");
parm = RNA_def_boolean(func, "result", 0, "", "");
RNA_def_function_return(func, parm);
}

@ -30,6 +30,7 @@
#include "MEM_guardedalloc.h"
#include "BLI_utildefines.h"
#include "BLI_alloca.h"
#include "BKE_main.h"
@ -48,6 +49,11 @@
#include "bpy_rna.h"
/* -------------------------------------------------------------------- */
/** \name Manipulator Target Property Define API
* \{ */
enum {
BPY_MANIPULATOR_FN_SLOT_GET = 0,
BPY_MANIPULATOR_FN_SLOT_SET,
@ -75,7 +81,7 @@ static void py_rna_manipulator_handler_get_cb(
if (mpr_prop->type->data_type == PROP_FLOAT) {
float *value = value_p;
if (mpr_prop->type->array_length == 1) {
if (((*value = PyFloat_AsDouble(ret)) == -1.0f && PyErr_Occurred()) == 0) {
if ((*value = PyFloat_AsDouble(ret)) == -1.0f && PyErr_Occurred()) {
goto fail;
}
}
@ -333,20 +339,275 @@ fail:
return NULL;
}
int BPY_rna_manipulator_module(PyObject *mod_par)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Manipulator Target Property Access API
* \{ */
PyDoc_STRVAR(bpy_manipulator_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_manipulator_target_get_value(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
static PyMethodDef method_def = {
"target_set_handler", (PyCFunction)bpy_manipulator_target_set_handler, METH_VARARGS | METH_KEYWORDS,
bpy_manipulator_target_set_handler_doc};
struct {
PyObject *self;
char *target;
} params = {
.self = NULL,
.target = NULL,
};
PyObject *func = PyCFunction_New(&method_def, NULL);
PyObject *func_inst = PyInstanceMethod_New(func);
static const char * const _keywords[] = {"self", "target", NULL};
#define KW_FMT "Os:target_get_value"
#if PY_VERSION_HEX >= 0x03070000
static _PyArg_Parser _parser = {KW_FMT, _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(
args, kwds,
&_parser,
&params.self,
&params.target))
#else
if (!PyArg_ParseTupleAndKeywords(
args, kwds,
KW_FMT, (char **)_keywords,
&params.self,
&params.target))
#endif
{
goto fail;
}
#undef KW_FMT
wmManipulator *mpr = ((BPy_StructRNA *)params.self)->ptr.data;
/* TODO, return a type that binds nearly to a method. */
PyModule_AddObject(mod_par, "_rna_manipulator_target_set_handler", func_inst);
wmManipulatorProperty *mpr_prop =
WM_manipulator_target_property_find(mpr, params.target);
if (mpr_prop == NULL) {
PyErr_Format(PyExc_ValueError,
"Manipulator target property '%s.%s' not found",
mpr->type->idname, params.target);
goto fail;
}
return 0;
const int array_len = WM_manipulator_target_property_array_length(mpr, mpr_prop);
switch (mpr_prop->type->data_type) {
case PROP_FLOAT:
{
if (array_len != 0) {
float *value = BLI_array_alloca(value, array_len);
WM_manipulator_target_property_value_get_array(mpr, mpr_prop, value);
return PyC_Tuple_PackArray_F32(value, array_len);
}
else {
float value = WM_manipulator_target_property_value_get(mpr, mpr_prop);
return PyFloat_FromDouble(value);
}
break;
}
default:
{
PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
goto fail;
}
}
fail:
return NULL;
}
PyDoc_STRVAR(bpy_manipulator_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_manipulator_target_set_value(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
struct {
PyObject *self;
char *target;
PyObject *value;
} params = {
.self = NULL,
.target = NULL,
.value = NULL,
};
static const char * const _keywords[] = {"self", "target", "value", NULL};
#define KW_FMT "OsO:target_set_value"
#if PY_VERSION_HEX >= 0x03070000
static _PyArg_Parser _parser = {KW_FMT, _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(
args, kwds,
&_parser,
&params.self,
&params.target,
&params.value))
#else
if (!PyArg_ParseTupleAndKeywords(
args, kwds,
KW_FMT, (char **)_keywords,
&params.self,
&params.target,
&params.value))
#endif
{
goto fail;
}
#undef KW_FMT
wmManipulator *mpr = ((BPy_StructRNA *)params.self)->ptr.data;
wmManipulatorProperty *mpr_prop =
WM_manipulator_target_property_find(mpr, params.target);
if (mpr_prop == NULL) {
PyErr_Format(PyExc_ValueError,
"Manipulator target property '%s.%s' not found",
mpr->type->idname, params.target);
goto fail;
}
const int array_len = WM_manipulator_target_property_array_length(mpr, mpr_prop);
switch (mpr_prop->type->data_type) {
case PROP_FLOAT:
{
if (array_len != 0) {
float *value = BLI_array_alloca(value, array_len);
if (PyC_AsArray(value, params.value, mpr_prop->type->array_length, &PyFloat_Type, false,
"Manipulator target property array") == -1)
{
goto fail;
}
WM_manipulator_target_property_value_set_array(BPy_GetContext(), mpr, mpr_prop, value);
}
else {
float value;
if ((value = PyFloat_AsDouble(params.value)) == -1.0f && PyErr_Occurred()) {
goto fail;
}
WM_manipulator_target_property_value_set(BPy_GetContext(), mpr, mpr_prop, value);
}
Py_RETURN_NONE;
}
default:
{
PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
goto fail;
}
}
fail:
return NULL;
}
PyDoc_STRVAR(bpy_manipulator_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"
" :Get the range for this target property"
" :return: The range of this property (min, max).\n"
" :rtype: tuple pair.\n"
);
static PyObject *bpy_manipulator_target_get_range(PyObject *UNUSED(self), PyObject *args, PyObject *kwds)
{
struct {
PyObject *self;
char *target;
} params = {
.self = NULL,
.target = NULL,
};
static const char * const _keywords[] = {"self", "target", NULL};
#define KW_FMT "Os:target_get_range"
#if PY_VERSION_HEX >= 0x03070000
static _PyArg_Parser _parser = {KW_FMT, _keywords, 0};
if (!_PyArg_ParseTupleAndKeywordsFast(
args, kwds,
&_parser,
&params.self,
&params.target))
#else
if (!PyArg_ParseTupleAndKeywords(
args, kwds,
KW_FMT, (char **)_keywords,
&params.self,
&params.target))
#endif
{
goto fail;
}
#undef KW_FMT
wmManipulator *mpr = ((BPy_StructRNA *)params.self)->ptr.data;
wmManipulatorProperty *mpr_prop =
WM_manipulator_target_property_find(mpr, params.target);
if (mpr_prop == NULL) {
PyErr_Format(PyExc_ValueError,
"Manipulator target property '%s.%s' not found",
mpr->type->idname, params.target);
goto fail;
}
switch (mpr_prop->type->data_type) {
case PROP_FLOAT:
{
float range[2];
WM_manipulator_target_property_range_get(mpr, mpr_prop, range);
return PyC_Tuple_PackArray_F32(range, 2);
}
default:
{
PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
goto fail;
}
}
fail:
return NULL;
}
/** \} */
int BPY_rna_manipulator_module(PyObject *mod_par)
{
static PyMethodDef method_def_array[] = {
/* Manipulator Target Property Define API */
{"target_set_handler", (PyCFunction)bpy_manipulator_target_set_handler,
METH_VARARGS | METH_KEYWORDS, bpy_manipulator_target_set_handler_doc},
/* Manipulator Target Property Access API */
{"target_get_value", (PyCFunction)bpy_manipulator_target_get_value,
METH_VARARGS | METH_KEYWORDS, bpy_manipulator_target_get_value_doc},
{"target_set_value", (PyCFunction)bpy_manipulator_target_set_value,
METH_VARARGS | METH_KEYWORDS, bpy_manipulator_target_set_value_doc},
{"target_get_range", (PyCFunction)bpy_manipulator_target_get_range,
METH_VARARGS | METH_KEYWORDS, bpy_manipulator_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_manipulator_%s", m->ml_name);
/* TODO, return a type that binds nearly to a method. */
PyModule_AddObject(mod_par, name_prefix, func_inst);
}
return 0;
}