Blender  V3.3
bpy_rna_gizmo.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
9 #include <Python.h>
10 #include <stddef.h>
11 
12 #include "MEM_guardedalloc.h"
13 
14 #include "BLI_alloca.h"
15 #include "BLI_utildefines.h"
16 
17 #include "WM_api.h"
18 #include "WM_types.h"
19 
20 #include "bpy_capi_utils.h"
21 #include "bpy_rna_gizmo.h"
22 
23 #include "../generic/py_capi_utils.h"
24 #include "../generic/python_utildefines.h"
25 
26 #include "RNA_access.h"
27 #include "RNA_enum_types.h"
28 #include "RNA_prototypes.h"
29 #include "RNA_types.h"
30 
31 #include "bpy_rna.h"
32 
33 /* -------------------------------------------------------------------- */
40  wmGizmo *gz; /* Must be first. */
42 };
43 
45  wmGizmo *gz; /* Must be first. */
47 };
48 
49 static int py_rna_gizmo_parse(PyObject *o, void *p)
50 {
51  /* No type checking (this is `self` not a user defined argument). */
53  BLI_assert(RNA_struct_is_a(((const BPy_StructRNA *)o)->ptr.type, &RNA_Gizmo));
54 
55  wmGizmo **gz_p = p;
56  *gz_p = ((const BPy_StructRNA *)o)->ptr.data;
57  return 1;
58 }
59 
60 static int py_rna_gizmo_target_id_parse(PyObject *o, void *p)
61 {
62  struct BPyGizmoWithTarget *gizmo_with_target = p;
63  /* Must be set by `py_rna_gizmo_parse`. */
64  wmGizmo *gz = gizmo_with_target->gz;
65  BLI_assert(gz != NULL);
66 
67  if (!PyUnicode_Check(o)) {
68  PyErr_Format(PyExc_TypeError, "expected a string (got %.200s)", Py_TYPE(o)->tp_name);
69  return 0;
70  }
71  const char *gz_prop_id = PyUnicode_AsUTF8(o);
73  if (gz_prop == NULL) {
74  PyErr_Format(PyExc_ValueError,
75  "Gizmo target property '%s.%s' not found!",
76  gz->type->idname,
77  gz_prop_id);
78  return 0;
79  }
80  gizmo_with_target->gz_prop = gz_prop;
81  return 1;
82 }
83 
84 static int py_rna_gizmo_target_id_parse_and_ensure_is_valid(PyObject *o, void *p)
85 {
86  if (py_rna_gizmo_target_id_parse(o, p) == 0) {
87  return 0;
88  }
89  struct BPyGizmoWithTarget *gizmo_with_target = p;
90  wmGizmo *gz = gizmo_with_target->gz;
91  wmGizmoProperty *gz_prop = gizmo_with_target->gz_prop;
93  const char *gz_prop_id = PyUnicode_AsUTF8(o);
94  PyErr_Format(PyExc_ValueError,
95  "Gizmo target property '%s.%s' has not been initialized, "
96  "Call \"target_set_prop\" first!",
97  gz->type->idname,
98  gz_prop_id);
99  return 0;
100  }
101  return 1;
102 }
103 
104 static int py_rna_gizmo_target_type_id_parse(PyObject *o, void *p)
105 {
106  struct BPyGizmoWithTargetType *gizmo_with_target = p;
107  /* Must be set first. */
108  wmGizmo *gz = gizmo_with_target->gz;
109  BLI_assert(gz != NULL);
110 
111  if (!PyUnicode_Check(o)) {
112  PyErr_Format(PyExc_TypeError, "expected a string (got %.200s)", Py_TYPE(o)->tp_name);
113  return 0;
114  }
115  const char *gz_prop_id = PyUnicode_AsUTF8(o);
117  gz_prop_id);
118  if (gz_prop_type == NULL) {
119  PyErr_Format(PyExc_ValueError,
120  "Gizmo target property '%s.%s' not found!",
121  gz->type->idname,
122  gz_prop_id);
123  return 0;
124  }
125  gizmo_with_target->gz_prop_type = gz_prop_type;
126  return 1;
127 }
128 
131 /* -------------------------------------------------------------------- */
135 enum {
139 };
140 #define BPY_GIZMO_FN_SLOT_LEN (BPY_GIZMO_FN_SLOT_RANGE_GET + 1)
141 
143 
145 };
146 
148  wmGizmoProperty *gz_prop,
149  void *value_p)
150 {
151  const PyGILState_STATE gilstate = PyGILState_Ensure();
152 
154  PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_GET], NULL);
155  if (ret == NULL) {
156  goto fail;
157  }
158 
159  if (gz_prop->type->data_type == PROP_FLOAT) {
160  float *value = value_p;
161  if (gz_prop->type->array_length == 1) {
162  if ((*value = PyFloat_AsDouble(ret)) == -1.0f && PyErr_Occurred()) {
163  goto fail;
164  }
165  }
166  else {
167  if (PyC_AsArray(value,
168  sizeof(*value),
169  ret,
170  gz_prop->type->array_length,
171  &PyFloat_Type,
172  "Gizmo get callback: ") == -1) {
173  goto fail;
174  }
175  }
176  }
177  else {
178  PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
179  goto fail;
180  }
181 
182  Py_DECREF(ret);
183 
184  PyGILState_Release(gilstate);
185  return;
186 
187 fail:
188  PyErr_Print();
189  PyErr_Clear();
190 
191  Py_XDECREF(ret);
192 
193  PyGILState_Release(gilstate);
194 }
195 
197  wmGizmoProperty *gz_prop,
198  const void *value_p)
199 {
200  const PyGILState_STATE gilstate = PyGILState_Ensure();
201 
203 
204  PyObject *args = PyTuple_New(1);
205 
206  if (gz_prop->type->data_type == PROP_FLOAT) {
207  const float *value = value_p;
208  PyObject *py_value;
209  if (gz_prop->type->array_length == 1) {
210  py_value = PyFloat_FromDouble(*value);
211  }
212  else {
213  py_value = PyC_Tuple_PackArray_F32(value, gz_prop->type->array_length);
214  }
215  if (py_value == NULL) {
216  goto fail;
217  }
218  PyTuple_SET_ITEM(args, 0, py_value);
219  }
220  else {
221  PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
222  goto fail;
223  }
224 
225  PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_SET], args);
226  if (ret == NULL) {
227  goto fail;
228  }
229  Py_DECREF(args);
230  Py_DECREF(ret);
231 
232  PyGILState_Release(gilstate);
233  return;
234 
235 fail:
236  PyErr_Print();
237  PyErr_Clear();
238 
239  Py_DECREF(args);
240 
241  PyGILState_Release(gilstate);
242 }
243 
245  wmGizmoProperty *gz_prop,
246  void *value_p)
247 {
249 
250  const PyGILState_STATE gilstate = PyGILState_Ensure();
251 
252  PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_RANGE_GET], NULL);
253  if (ret == NULL) {
254  goto fail;
255  }
256 
257  if (!PyTuple_Check(ret)) {
258  PyErr_Format(PyExc_TypeError, "Expected a tuple, not %.200s", Py_TYPE(ret)->tp_name);
259  goto fail;
260  }
261 
262  if (PyTuple_GET_SIZE(ret) != 2) {
263  PyErr_Format(PyExc_TypeError, "Expected a tuple of size 2, not %d", PyTuple_GET_SIZE(ret));
264  goto fail;
265  }
266 
267  if (gz_prop->type->data_type == PROP_FLOAT) {
268  float range[2];
269  for (int i = 0; i < 2; i++) {
270  if (((range[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(ret, i))) == -1.0f && PyErr_Occurred()) ==
271  0) {
272  /* pass */
273  }
274  else {
275  goto fail;
276  }
277  }
278  memcpy(value_p, range, sizeof(range));
279  }
280  else {
281  PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
282  goto fail;
283  }
284 
285  Py_DECREF(ret);
286  PyGILState_Release(gilstate);
287  return;
288 
289 fail:
290  PyErr_Print();
291  PyErr_Clear();
292 
293  Py_XDECREF(ret);
294 
295  PyGILState_Release(gilstate);
296 }
297 
299 {
301 
302  const PyGILState_STATE gilstate = PyGILState_Ensure();
303  for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
304  Py_XDECREF(data->fn_slots[i]);
305  }
306  PyGILState_Release(gilstate);
307 
308  MEM_freeN(data);
309 }
310 
312  bpy_gizmo_target_set_handler_doc,
313  ".. method:: target_set_handler(target, get, set, range=None):\n"
314  "\n"
315  " Assigns callbacks to a gizmos property.\n"
316  "\n"
317  " :arg target: Target property name.\n"
318  " :type target: string\n"
319  " :arg get: Function that returns the value for this property (single value or sequence).\n"
320  " :type get: callable\n"
321  " :arg set: Function that takes a single value argument and applies it.\n"
322  " :type set: callable\n"
323  " :arg range: Function that returns a (min, max) tuple for gizmos that use a range.\n"
324  " :type range: callable\n");
325 static PyObject *bpy_gizmo_target_set_handler(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
326 {
327  const PyGILState_STATE gilstate = PyGILState_Ensure();
328 
329  struct {
330  struct BPyGizmoWithTargetType gz_with_target_type;
331  PyObject *py_fn_slots[BPY_GIZMO_FN_SLOT_LEN];
332  } params = {
333  .gz_with_target_type = {NULL, NULL},
334  .py_fn_slots = {NULL},
335  };
336 
337  /* NOTE: this is a counter-part to functions:
338  * 'Gizmo.target_set_prop & target_set_operator'
339  * (see: rna_wm_gizmo_api.c). conventions should match. */
340  static const char *const _keywords[] = {"self", "target", "get", "set", "range", NULL};
341  static _PyArg_Parser _parser = {
342  "O&" /* `self` */
343  "O&" /* `target` */
344  "|$" /* Optional keyword only arguments. */
345  "O" /* `get` */
346  "O" /* `set` */
347  "O" /* `range` */
348  ":target_set_handler",
349  _keywords,
350  0,
351  };
352  if (!_PyArg_ParseTupleAndKeywordsFast(args,
353  kw,
354  &_parser,
355  /* `self` */
357  &params.gz_with_target_type.gz,
358  /* `target` */
360  &params.gz_with_target_type,
361  /* `get/set/range` */
362  &params.py_fn_slots[BPY_GIZMO_FN_SLOT_GET],
363  &params.py_fn_slots[BPY_GIZMO_FN_SLOT_SET],
364  &params.py_fn_slots[BPY_GIZMO_FN_SLOT_RANGE_GET])) {
365  goto fail;
366  }
367 
368  wmGizmo *gz = params.gz_with_target_type.gz;
369  const wmGizmoPropertyType *gz_prop_type = params.gz_with_target_type.gz_prop_type;
370 
371  {
372  const int slots_required = 2;
373  const int slots_start = 2;
374  for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
375  if (params.py_fn_slots[i] == NULL) {
376  if (i < slots_required) {
377  PyErr_Format(PyExc_ValueError, "Argument '%s' not given", _keywords[slots_start + i]);
378  goto fail;
379  }
380  }
381  else if (!PyCallable_Check(params.py_fn_slots[i])) {
382  PyErr_Format(PyExc_ValueError, "Argument '%s' not callable", _keywords[slots_start + i]);
383  goto fail;
384  }
385  }
386  }
387 
388  struct BPyGizmoHandlerUserData *data = MEM_callocN(sizeof(*data), __func__);
389 
390  for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
391  data->fn_slots[i] = params.py_fn_slots[i];
392  Py_XINCREF(params.py_fn_slots[i]);
393  }
394 
396  gz_prop_type,
397  &(const struct wmGizmoPropertyFnParams){
398  .value_get_fn = py_rna_gizmo_handler_get_cb,
399  .value_set_fn = py_rna_gizmo_handler_set_cb,
400  .range_get_fn = py_rna_gizmo_handler_range_get_cb,
401  .free_fn = py_rna_gizmo_handler_free_cb,
402  .user_data = data,
403  });
404 
405  PyGILState_Release(gilstate);
406 
407  Py_RETURN_NONE;
408 
409 fail:
410  PyGILState_Release(gilstate);
411  return NULL;
412 }
413 
416 /* -------------------------------------------------------------------- */
420 PyDoc_STRVAR(bpy_gizmo_target_get_value_doc,
421  ".. method:: target_get_value(target):\n"
422  "\n"
423  " Get the value of this target property.\n"
424  "\n"
425  " :arg target: Target property name.\n"
426  " :type target: string\n"
427  " :return: The value of the target property.\n"
428  " :rtype: Single value or array based on the target type\n");
429 static PyObject *bpy_gizmo_target_get_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
430 {
431  struct {
432  struct BPyGizmoWithTarget gz_with_target;
433  } params = {
434  .gz_with_target = {NULL, NULL},
435  };
436 
437  static const char *const _keywords[] = {"self", "target", NULL};
438  static _PyArg_Parser _parser = {
439  "O&" /* `self` */
440  "O&" /* `target` */
441  ":target_get_value",
442  _keywords,
443  0,
444  };
445  if (!_PyArg_ParseTupleAndKeywordsFast(args,
446  kw,
447  &_parser,
448  /* `self` */
450  &params.gz_with_target.gz,
451  /* `target` */
453  &params.gz_with_target)) {
454  goto fail;
455  }
456 
457  wmGizmo *gz = params.gz_with_target.gz;
458  wmGizmoProperty *gz_prop = params.gz_with_target.gz_prop;
459 
460  const int array_len = WM_gizmo_target_property_array_length(gz, gz_prop);
461  switch (gz_prop->type->data_type) {
462  case PROP_FLOAT: {
463  if (array_len != 0) {
464  float *value = BLI_array_alloca(value, array_len);
466  return PyC_Tuple_PackArray_F32(value, array_len);
467  }
468 
469  const float value = WM_gizmo_target_property_float_get(gz, gz_prop);
470  return PyFloat_FromDouble(value);
471 
472  break;
473  }
474  default: {
475  PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
476  goto fail;
477  }
478  }
479 
480 fail:
481  return NULL;
482 }
483 
484 PyDoc_STRVAR(bpy_gizmo_target_set_value_doc,
485  ".. method:: target_set_value(target):\n"
486  "\n"
487  " Set the value of this target property.\n"
488  "\n"
489  " :arg target: Target property name.\n"
490  " :type target: string\n");
491 static PyObject *bpy_gizmo_target_set_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
492 {
493  struct {
494  struct BPyGizmoWithTarget gz_with_target;
495  PyObject *value;
496  } params = {
497  .gz_with_target = {NULL, NULL},
498  .value = NULL,
499  };
500 
501  static const char *const _keywords[] = {"self", "target", "value", NULL};
502  static _PyArg_Parser _parser = {
503  "O&" /* `self` */
504  "O&" /* `target` */
505  "O" /* `value` */
506  ":target_set_value",
507  _keywords,
508  0,
509  };
510  if (!_PyArg_ParseTupleAndKeywordsFast(args,
511  kw,
512  &_parser,
513  /* `self` */
515  &params.gz_with_target.gz,
516  /* `target` */
518  &params.gz_with_target,
519  /* `value` */
520  &params.value)) {
521  goto fail;
522  }
523 
524  wmGizmo *gz = params.gz_with_target.gz;
525  wmGizmoProperty *gz_prop = params.gz_with_target.gz_prop;
526 
527  const int array_len = WM_gizmo_target_property_array_length(gz, gz_prop);
528  switch (gz_prop->type->data_type) {
529  case PROP_FLOAT: {
530  if (array_len != 0) {
531  float *value = BLI_array_alloca(value, array_len);
532  if (PyC_AsArray(value,
533  sizeof(*value),
534  params.value,
536  &PyFloat_Type,
537  "Gizmo target property array: ") == -1) {
538  goto fail;
539  }
541  }
542  else {
543  float value;
544  if ((value = PyFloat_AsDouble(params.value)) == -1.0f && PyErr_Occurred()) {
545  goto fail;
546  }
548  }
549  Py_RETURN_NONE;
550  }
551  default: {
552  PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
553  goto fail;
554  }
555  }
556 
557 fail:
558  return NULL;
559 }
560 
561 PyDoc_STRVAR(bpy_gizmo_target_get_range_doc,
562  ".. method:: target_get_range(target):\n"
563  "\n"
564  " Get the range for this target property.\n"
565  "\n"
566  " :arg target: Target property name.\n"
567  " :return: The range of this property (min, max).\n"
568  " :rtype: tuple pair.\n");
569 static PyObject *bpy_gizmo_target_get_range(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
570 {
571  struct {
572  struct BPyGizmoWithTarget gz_with_target;
573  } params = {
574  .gz_with_target = {NULL, NULL},
575  };
576 
577  static const char *const _keywords[] = {"self", "target", NULL};
578  static _PyArg_Parser _parser = {
579  "O&" /* `self` */
580  "O&" /* `target` */
581  ":target_get_range",
582  _keywords,
583  0,
584  };
585  if (!_PyArg_ParseTupleAndKeywordsFast(args,
586  kw,
587  &_parser,
588  /* `self` */
590  &params.gz_with_target.gz,
591  /* `target` */
593  &params.gz_with_target)) {
594  goto fail;
595  }
596 
597  wmGizmo *gz = params.gz_with_target.gz;
598  wmGizmoProperty *gz_prop = params.gz_with_target.gz_prop;
599 
600  switch (gz_prop->type->data_type) {
601  case PROP_FLOAT: {
602  float range[2];
604  return PyC_Tuple_PackArray_F32(range, 2);
605  }
606  default: {
607  PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
608  goto fail;
609  }
610  }
611 
612 fail:
613  return NULL;
614 }
615 
618 /* -------------------------------------------------------------------- */
622 bool BPY_rna_gizmo_module(PyObject *mod_par)
623 {
624  static PyMethodDef method_def_array[] = {
625  /* Gizmo Target Property Define API */
626  {"target_set_handler",
627  (PyCFunction)bpy_gizmo_target_set_handler,
628  METH_VARARGS | METH_KEYWORDS,
629  bpy_gizmo_target_set_handler_doc},
630  /* Gizmo Target Property Access API */
631  {"target_get_value",
632  (PyCFunction)bpy_gizmo_target_get_value,
633  METH_VARARGS | METH_KEYWORDS,
634  bpy_gizmo_target_get_value_doc},
635  {"target_set_value",
636  (PyCFunction)bpy_gizmo_target_set_value,
637  METH_VARARGS | METH_KEYWORDS,
638  bpy_gizmo_target_set_value_doc},
639  {"target_get_range",
640  (PyCFunction)bpy_gizmo_target_get_range,
641  METH_VARARGS | METH_KEYWORDS,
642  bpy_gizmo_target_get_range_doc},
643  /* no sentinel needed. */
644  };
645 
646  for (int i = 0; i < ARRAY_SIZE(method_def_array); i++) {
647  PyMethodDef *m = &method_def_array[i];
648  PyObject *func = PyCFunction_New(m, NULL);
649  PyObject *func_inst = PyInstanceMethod_New(func);
650  char name_prefix[128];
651  PyOS_snprintf(name_prefix, sizeof(name_prefix), "_rna_gizmo_%s", m->ml_name);
652  /* TODO: return a type that binds nearly to a method. */
653  PyModule_AddObject(mod_par, name_prefix, func_inst);
654  }
655 
656  return false;
657 }
658 
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:22
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define ARRAY_SIZE(arr)
#define UNUSED(x)
Read Guarded memory(de)allocation.
@ PROP_FLOAT
Definition: RNA_types.h:61
struct bContext * BPY_context_get(void)
#define BPy_StructRNA_Check(v)
Definition: bpy_rna.h:66
static PyObject * bpy_gizmo_target_get_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
static void py_rna_gizmo_handler_range_get_cb(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, void *value_p)
bool BPY_rna_gizmo_module(PyObject *mod_par)
static int py_rna_gizmo_target_id_parse(PyObject *o, void *p)
Definition: bpy_rna_gizmo.c:60
static void py_rna_gizmo_handler_set_cb(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, const void *value_p)
static int py_rna_gizmo_target_id_parse_and_ensure_is_valid(PyObject *o, void *p)
Definition: bpy_rna_gizmo.c:84
static PyObject * bpy_gizmo_target_get_range(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
static PyObject * bpy_gizmo_target_set_value(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
#define BPY_GIZMO_FN_SLOT_LEN
static PyObject * bpy_gizmo_target_set_handler(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
static void py_rna_gizmo_handler_get_cb(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, void *value_p)
static int py_rna_gizmo_target_type_id_parse(PyObject *o, void *p)
static void py_rna_gizmo_handler_free_cb(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop)
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 target: Target property name.\n" " :type target: string\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")
@ BPY_GIZMO_FN_SLOT_GET
@ BPY_GIZMO_FN_SLOT_RANGE_GET
@ BPY_GIZMO_FN_SLOT_SET
static int py_rna_gizmo_parse(PyObject *o, void *p)
Definition: bpy_rna_gizmo.c:49
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
int PyC_AsArray(void *array, const size_t array_item_size, PyObject *value, const Py_ssize_t length, const PyTypeObject *type, const char *error_prefix)
PyObject * PyC_Tuple_PackArray_F32(const float *array, uint len)
return ret
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
Definition: rna_access.c:695
PyObject * fn_slots[BPY_GIZMO_FN_SLOT_LEN]
const wmGizmoPropertyType * gz_prop_type
Definition: bpy_rna_gizmo.c:46
wmGizmoProperty * gz_prop
Definition: bpy_rna_gizmo.c:41
struct StructRNA * type
Definition: RNA_types.h:37
void * data
Definition: RNA_types.h:38
const struct wmGizmoPropertyType * type
struct wmGizmoProperty::@1185 custom_func
const char * idname
struct PointerRNA * ptr
const struct wmGizmoType * type
PointerRNA * ptr
Definition: wm_files.c:3480
void WM_gizmo_target_property_float_set(bContext *C, const wmGizmo *gz, wmGizmoProperty *gz_prop, const float value)
wmGizmoProperty * WM_gizmo_target_property_find(wmGizmo *gz, const char *idname)
bool WM_gizmo_target_property_is_valid(const wmGizmoProperty *gz_prop)
void WM_gizmo_target_property_float_get_array(const wmGizmo *gz, wmGizmoProperty *gz_prop, float *value)
void WM_gizmo_target_property_def_func_ptr(wmGizmo *gz, const wmGizmoPropertyType *gz_prop_type, const wmGizmoPropertyFnParams *params)
float WM_gizmo_target_property_float_get(const wmGizmo *gz, wmGizmoProperty *gz_prop)
void WM_gizmo_target_property_float_set_array(bContext *C, const wmGizmo *gz, wmGizmoProperty *gz_prop, const float *value)
const wmGizmoPropertyType * WM_gizmotype_target_property_find(const wmGizmoType *gzt, const char *idname)
int WM_gizmo_target_property_array_length(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop)
bool WM_gizmo_target_property_float_range_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, float range[2])