Blender V5.0
bpy_rna_gizmo.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <Python.h>
12#include <cstddef>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_alloca.h"
17#include "BLI_utildefines.h"
18
19#include "WM_types.hh"
20
21#include "bpy_capi_utils.hh"
22#include "bpy_rna_gizmo.hh"
23
25#include "../generic/python_compat.hh" /* IWYU pragma: keep. */
26
27#include "RNA_access.hh"
28#include "RNA_prototypes.hh"
29
30#include "bpy_rna.hh"
31
32/* -------------------------------------------------------------------- */
37
39 wmGizmo *gz; /* Must be first. */
41};
42
44 wmGizmo *gz; /* Must be first. */
46};
47
48static int py_rna_gizmo_parse(PyObject *o, void *p)
49{
50 /* No type checking (this is `self` not a user defined argument). */
52 BLI_assert(RNA_struct_is_a(((const BPy_StructRNA *)o)->ptr->type, &RNA_Gizmo));
53
54 wmGizmo **gz_p = static_cast<wmGizmo **>(p);
55 *gz_p = static_cast<wmGizmo *>(((const BPy_StructRNA *)o)->ptr->data);
56 return 1;
57}
58
59static int py_rna_gizmo_target_id_parse(PyObject *o, void *p)
60{
61 BPyGizmoWithTarget *gizmo_with_target = static_cast<BPyGizmoWithTarget *>(p);
62 /* Must be set by `py_rna_gizmo_parse`. */
63 wmGizmo *gz = gizmo_with_target->gz;
64 BLI_assert(gz != nullptr);
65
66 if (!PyUnicode_Check(o)) {
67 PyErr_Format(PyExc_TypeError, "expected a string (got %.200s)", Py_TYPE(o)->tp_name);
68 return 0;
69 }
70 const char *gz_prop_id = PyUnicode_AsUTF8(o);
71 wmGizmoProperty *gz_prop = WM_gizmo_target_property_find(gz, gz_prop_id);
72 if (gz_prop == nullptr) {
73 PyErr_Format(PyExc_ValueError,
74 "Gizmo target property '%s.%s' not found!",
75 gz->type->idname,
76 gz_prop_id);
77 return 0;
78 }
79 gizmo_with_target->gz_prop = gz_prop;
80 return 1;
81}
82
84{
85 if (py_rna_gizmo_target_id_parse(o, p) == 0) {
86 return 0;
87 }
88 BPyGizmoWithTarget *gizmo_with_target = static_cast<BPyGizmoWithTarget *>(p);
89 wmGizmo *gz = gizmo_with_target->gz;
90 wmGizmoProperty *gz_prop = gizmo_with_target->gz_prop;
92 const char *gz_prop_id = PyUnicode_AsUTF8(o);
93 PyErr_Format(PyExc_ValueError,
94 "Gizmo target property '%s.%s' has not been initialized, "
95 "Call \"target_set_prop\" first!",
96 gz->type->idname,
97 gz_prop_id);
98 return 0;
99 }
100 return 1;
101}
102
103static int py_rna_gizmo_target_type_id_parse(PyObject *o, void *p)
104{
105 BPyGizmoWithTargetType *gizmo_with_target = static_cast<BPyGizmoWithTargetType *>(p);
106 /* Must be set first. */
107 wmGizmo *gz = gizmo_with_target->gz;
108 BLI_assert(gz != nullptr);
109
110 if (!PyUnicode_Check(o)) {
111 PyErr_Format(PyExc_TypeError, "expected a string (got %.200s)", Py_TYPE(o)->tp_name);
112 return 0;
113 }
114 const char *gz_prop_id = PyUnicode_AsUTF8(o);
116 gz_prop_id);
117 if (gz_prop_type == nullptr) {
118 PyErr_Format(PyExc_ValueError,
119 "Gizmo target property '%s.%s' not found!",
120 gz->type->idname,
121 gz_prop_id);
122 return 0;
123 }
124 gizmo_with_target->gz_prop_type = gz_prop_type;
125 return 1;
126}
127
129
130/* -------------------------------------------------------------------- */
133
134enum {
138};
139#define BPY_GIZMO_FN_SLOT_LEN (BPY_GIZMO_FN_SLOT_RANGE_GET + 1)
140
145
146static void py_rna_gizmo_handler_get_cb(const wmGizmo * /*gz*/,
147 wmGizmoProperty *gz_prop,
148 void *value_p)
149{
150 const PyGILState_STATE gilstate = PyGILState_Ensure();
151
153 gz_prop->custom_func.user_data);
154 PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_GET], nullptr);
155 if (ret == nullptr) {
156 goto fail;
157 }
158
159 if (gz_prop->type->data_type == PROP_FLOAT) {
160 float *value = static_cast<float *>(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 {
174 goto fail;
175 }
176 }
177 }
178 else {
179 PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
180 goto fail;
181 }
182
183 Py_DECREF(ret);
184
185 PyGILState_Release(gilstate);
186 return;
187
188fail:
189 PyErr_Print();
190
191 Py_XDECREF(ret);
192
193 PyGILState_Release(gilstate);
194}
195
196static void py_rna_gizmo_handler_set_cb(const wmGizmo * /*gz*/,
197 wmGizmoProperty *gz_prop,
198 const void *value_p)
199{
200 const PyGILState_STATE gilstate = PyGILState_Ensure();
201
203 gz_prop->custom_func.user_data);
204
205 PyObject *args = PyTuple_New(1);
206 PyObject *ret;
207
208 if (gz_prop->type->data_type == PROP_FLOAT) {
209 const float *value = static_cast<const float *>(value_p);
210 PyObject *py_value;
211 if (gz_prop->type->array_length == 1) {
212 py_value = PyFloat_FromDouble(*value);
213 }
214 else {
215 py_value = PyC_Tuple_PackArray_F32(value, gz_prop->type->array_length);
216 }
217 if (py_value == nullptr) {
218 goto fail;
219 }
220 PyTuple_SET_ITEM(args, 0, py_value);
221 }
222 else {
223 PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
224 goto fail;
225 }
226
227 ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_SET], args);
228 if (ret == nullptr) {
229 goto fail;
230 }
231 Py_DECREF(args);
232 Py_DECREF(ret);
233
234 PyGILState_Release(gilstate);
235 return;
236
237fail:
238 PyErr_Print();
239
240 Py_DECREF(args);
241
242 PyGILState_Release(gilstate);
243}
244
246 wmGizmoProperty *gz_prop,
247 void *value_p)
248{
249 const PyGILState_STATE gilstate = PyGILState_Ensure();
250
252 gz_prop->custom_func.user_data);
253
254 PyObject *ret = PyObject_CallObject(data->fn_slots[BPY_GIZMO_FN_SLOT_RANGE_GET], nullptr);
255 if (ret == nullptr) {
256 goto fail;
257 }
258
259 if (!PyTuple_Check(ret)) {
260 PyErr_Format(PyExc_TypeError, "Expected a tuple, not %.200s", Py_TYPE(ret)->tp_name);
261 goto fail;
262 }
263
264 if (PyTuple_GET_SIZE(ret) != 2) {
265 PyErr_Format(PyExc_TypeError, "Expected a tuple of size 2, not %d", PyTuple_GET_SIZE(ret));
266 goto fail;
267 }
268
269 if (gz_prop->type->data_type == PROP_FLOAT) {
270 float range[2];
271 for (int i = 0; i < 2; i++) {
272 if (((range[i] = PyFloat_AsDouble(PyTuple_GET_ITEM(ret, i))) == -1.0f && PyErr_Occurred()) ==
273 0)
274 {
275 /* pass */
276 }
277 else {
278 goto fail;
279 }
280 }
281 memcpy(value_p, range, sizeof(range));
282 }
283 else {
284 PyErr_SetString(PyExc_AttributeError, "internal error, unsupported type");
285 goto fail;
286 }
287
288 Py_DECREF(ret);
289 PyGILState_Release(gilstate);
290 return;
291
292fail:
293 PyErr_Print();
294
295 Py_XDECREF(ret);
296
297 PyGILState_Release(gilstate);
298}
299
300static void py_rna_gizmo_handler_free_cb(const wmGizmo * /*gz*/, wmGizmoProperty *gz_prop)
301{
302 const PyGILState_STATE gilstate = PyGILState_Ensure();
303
305 gz_prop->custom_func.user_data);
306
307 for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
308 Py_XDECREF(data->fn_slots[i]);
309 }
310 PyGILState_Release(gilstate);
311
313}
314
316 /* Wrap. */
317 bpy_gizmo_target_set_handler_doc,
318 ".. method:: target_set_handler(target, get, set, range=None):\n"
319 "\n"
320 " Assigns callbacks to a gizmos property.\n"
321 "\n"
322 " :arg target: Target property name.\n"
323 " :type target: str\n"
324 " :arg get: Function that returns the value for this property (single value or sequence).\n"
325 " :type get: Callable[[], float | Sequence[float]]\n"
326 " :arg set: Function that takes a single value argument and applies it.\n"
327 " :type set: Callable[[tuple[float, ...]], Any]\n"
328 " :arg range: Function that returns a (min, max) tuple for gizmos that use a range. "
329 "The returned value is not used.\n"
330 " :type range: callable\n");
331static PyObject *bpy_gizmo_target_set_handler(PyObject * /*self*/, PyObject *args, PyObject *kw)
332{
333 struct {
334 BPyGizmoWithTargetType gz_with_target_type;
335 PyObject *py_fn_slots[BPY_GIZMO_FN_SLOT_LEN];
336 } params = {
337 {nullptr, nullptr},
338 {nullptr},
339 };
340
341 /* NOTE: this is a counter-part to functions:
342 * 'Gizmo.target_set_prop & target_set_operator'
343 * (see: rna_wm_gizmo_api.cc). conventions should match. */
344 static const char *const _keywords[] = {"self", "target", "get", "set", "range", nullptr};
345 static _PyArg_Parser _parser = {
347 "O&" /* `self` */
348 "O&" /* `target` */
349 "|$" /* Optional keyword only arguments. */
350 "O" /* `get` */
351 "O" /* `set` */
352 "O" /* `range` */
353 ":target_set_handler",
354 _keywords,
355 nullptr,
356 };
357
359 const wmGizmoPropertyType *gz_prop_type;
360 wmGizmo *gz;
361
362 if (!_PyArg_ParseTupleAndKeywordsFast(args,
363 kw,
364 &_parser,
365 /* `self` */
367 &params.gz_with_target_type.gz,
368 /* `target` */
370 &params.gz_with_target_type,
371 /* `get/set/range` */
372 &params.py_fn_slots[BPY_GIZMO_FN_SLOT_GET],
373 &params.py_fn_slots[BPY_GIZMO_FN_SLOT_SET],
374 &params.py_fn_slots[BPY_GIZMO_FN_SLOT_RANGE_GET]))
375 {
376 goto fail;
377 }
378
379 gz = params.gz_with_target_type.gz;
380 gz_prop_type = params.gz_with_target_type.gz_prop_type;
381
382 {
383 const int slots_required = 2;
384 const int slots_start = 2;
385 for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
386 if (params.py_fn_slots[i] == nullptr) {
387 if (i < slots_required) {
388 PyErr_Format(PyExc_ValueError, "Argument '%s' not given", _keywords[slots_start + i]);
389 goto fail;
390 }
391 }
392 else if (!PyCallable_Check(params.py_fn_slots[i])) {
393 PyErr_Format(PyExc_ValueError, "Argument '%s' not callable", _keywords[slots_start + i]);
394 goto fail;
395 }
396 }
397 }
398
400
401 for (int i = 0; i < BPY_GIZMO_FN_SLOT_LEN; i++) {
402 data->fn_slots[i] = params.py_fn_slots[i];
403 Py_XINCREF(params.py_fn_slots[i]);
404 }
405
406 {
407 wmGizmoPropertyFnParams fn_params{};
412 fn_params.user_data = data;
413 WM_gizmo_target_property_def_func_ptr(gz, gz_prop_type, &fn_params);
414 }
415
416 Py_RETURN_NONE;
417
418fail:
419 return nullptr;
420}
421
423
424/* -------------------------------------------------------------------- */
427
429 /* Wrap. */
430 bpy_gizmo_target_get_value_doc,
431 ".. method:: target_get_value(target):\n"
432 "\n"
433 " Get the value of this target property.\n"
434 "\n"
435 " :arg target: Target property name.\n"
436 " :type target: str\n"
437 " :return: The value of the target property as a value or array based on the target type.\n"
438 " :rtype: float | tuple[float, ...]\n");
439static PyObject *bpy_gizmo_target_get_value(PyObject * /*self*/, PyObject *args, PyObject *kw)
440{
441 struct {
442 BPyGizmoWithTarget gz_with_target;
443 } params = {
444 {nullptr, nullptr},
445 };
446
447 static const char *const _keywords[] = {"self", "target", nullptr};
448 static _PyArg_Parser _parser = {
450 "O&" /* `self` */
451 "O&" /* `target` */
452 ":target_get_value",
453 _keywords,
454 nullptr,
455 };
456
457 int array_len;
458 wmGizmo *gz;
459 wmGizmoProperty *gz_prop;
460
461 if (!_PyArg_ParseTupleAndKeywordsFast(args,
462 kw,
463 &_parser,
464 /* `self` */
466 &params.gz_with_target.gz,
467 /* `target` */
469 &params.gz_with_target))
470 {
471 goto fail;
472 }
473
474 gz = params.gz_with_target.gz;
475 gz_prop = params.gz_with_target.gz_prop;
476
477 array_len = WM_gizmo_target_property_array_length(gz, gz_prop);
478 switch (gz_prop->type->data_type) {
479 case PROP_FLOAT: {
480 if (array_len != 0) {
481 float *value = static_cast<float *>(BLI_array_alloca(value, array_len));
483 return PyC_Tuple_PackArray_F32(value, array_len);
484 }
485
486 const float value = WM_gizmo_target_property_float_get(gz, gz_prop);
487 return PyFloat_FromDouble(value);
488 }
489 default: {
490 PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
491 goto fail;
492 }
493 }
494
495fail:
496 return nullptr;
497}
498
500 /* Wrap. */
501 bpy_gizmo_target_set_value_doc,
502 ".. method:: target_set_value(target):\n"
503 "\n"
504 " Set the value of this target property.\n"
505 "\n"
506 " :arg target: Target property name.\n"
507 " :type target: str\n");
508static PyObject *bpy_gizmo_target_set_value(PyObject * /*self*/, PyObject *args, PyObject *kw)
509{
510 struct {
511 BPyGizmoWithTarget gz_with_target;
512 PyObject *value;
513 } params = {
514 {nullptr, nullptr},
515 nullptr,
516 };
517
518 static const char *const _keywords[] = {"self", "target", "value", nullptr};
519 static _PyArg_Parser _parser = {
521 "O&" /* `self` */
522 "O&" /* `target` */
523 "O" /* `value` */
524 ":target_set_value",
525 _keywords,
526 nullptr,
527 };
528
529 wmGizmo *gz;
530 wmGizmoProperty *gz_prop;
531 int array_len;
532
533 if (!_PyArg_ParseTupleAndKeywordsFast(args,
534 kw,
535 &_parser,
536 /* `self` */
538 &params.gz_with_target.gz,
539 /* `target` */
541 &params.gz_with_target,
542 /* `value` */
543 &params.value))
544 {
545 goto fail;
546 }
547
548 gz = params.gz_with_target.gz;
549 gz_prop = params.gz_with_target.gz_prop;
550
551 array_len = WM_gizmo_target_property_array_length(gz, gz_prop);
552 switch (gz_prop->type->data_type) {
553 case PROP_FLOAT: {
554 if (array_len != 0) {
555 float *value = static_cast<float *>(BLI_array_alloca(value, array_len));
556 if (PyC_AsArray(value,
557 sizeof(*value),
558 params.value,
559 gz_prop->type->array_length,
560 &PyFloat_Type,
561 "Gizmo target property array: ") == -1)
562 {
563 goto fail;
564 }
566 }
567 else {
568 float value;
569 if ((value = PyFloat_AsDouble(params.value)) == -1.0f && PyErr_Occurred()) {
570 goto fail;
571 }
573 }
574 Py_RETURN_NONE;
575 }
576 default: {
577 PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
578 goto fail;
579 }
580 }
581
582fail:
583 return nullptr;
584}
585
587 /* Wrap. */
588 bpy_gizmo_target_get_range_doc,
589 ".. method:: target_get_range(target):\n"
590 "\n"
591 " Get the range for this target property.\n"
592 "\n"
593 " :arg target: Target property name.\n"
594 " :return: The range of this property (min, max).\n"
595 " :rtype: tuple[float, float]\n");
596static PyObject *bpy_gizmo_target_get_range(PyObject * /*self*/, PyObject *args, PyObject *kw)
597{
598 struct {
599 BPyGizmoWithTarget gz_with_target;
600 } params = {
601 {nullptr, nullptr},
602 };
603
604 static const char *const _keywords[] = {"self", "target", nullptr};
605 static _PyArg_Parser _parser = {
607 "O&" /* `self` */
608 "O&" /* `target` */
609 ":target_get_range",
610 _keywords,
611 nullptr,
612 };
613
614 wmGizmo *gz;
615 wmGizmoProperty *gz_prop;
616
617 if (!_PyArg_ParseTupleAndKeywordsFast(args,
618 kw,
619 &_parser,
620 /* `self` */
622 &params.gz_with_target.gz,
623 /* `target` */
625 &params.gz_with_target))
626 {
627 goto fail;
628 }
629
630 gz = params.gz_with_target.gz;
631 gz_prop = params.gz_with_target.gz_prop;
632
633 switch (gz_prop->type->data_type) {
634 case PROP_FLOAT: {
635 float range[2];
637 return PyC_Tuple_PackArray_F32(range, 2);
638 }
639 default: {
640 PyErr_SetString(PyExc_RuntimeError, "Not yet supported type");
641 goto fail;
642 }
643 }
644
645fail:
646 return nullptr;
647}
648
650
651/* -------------------------------------------------------------------- */
654
655bool BPY_rna_gizmo_module(PyObject *mod_par)
656{
657
658#ifdef __GNUC__
659# ifdef __clang__
660# pragma clang diagnostic push
661# pragma clang diagnostic ignored "-Wcast-function-type"
662# else
663# pragma GCC diagnostic push
664# pragma GCC diagnostic ignored "-Wcast-function-type"
665# endif
666#endif
667
668 static PyMethodDef method_def_array[] = {
669 /* Gizmo Target Property Define API */
670 {"target_set_handler",
671 (PyCFunction)bpy_gizmo_target_set_handler,
672 METH_VARARGS | METH_KEYWORDS,
673 bpy_gizmo_target_set_handler_doc},
674 /* Gizmo Target Property Access API */
675 {"target_get_value",
676 (PyCFunction)bpy_gizmo_target_get_value,
677 METH_VARARGS | METH_KEYWORDS,
678 bpy_gizmo_target_get_value_doc},
679 {"target_set_value",
680 (PyCFunction)bpy_gizmo_target_set_value,
681 METH_VARARGS | METH_KEYWORDS,
682 bpy_gizmo_target_set_value_doc},
683 {"target_get_range",
684 (PyCFunction)bpy_gizmo_target_get_range,
685 METH_VARARGS | METH_KEYWORDS,
686 bpy_gizmo_target_get_range_doc},
687 /* no sentinel needed. */
688 };
689
690#ifdef __GNUC__
691# ifdef __clang__
692# pragma clang diagnostic pop
693# else
694# pragma GCC diagnostic pop
695# endif
696#endif
697
698 for (int i = 0; i < ARRAY_SIZE(method_def_array); i++) {
699 PyMethodDef *m = &method_def_array[i];
700 PyObject *func = PyCFunction_New(m, nullptr);
701 PyObject *func_inst = PyInstanceMethod_New(func);
702 char name_prefix[128];
703 PyOS_snprintf(name_prefix, sizeof(name_prefix), "_rna_gizmo_%s", m->ml_name);
704 /* TODO: return a type that binds nearly to a method. */
705 PyModule_AddObject(mod_par, name_prefix, func_inst);
706 }
707
708 return false;
709}
710
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:18
#define BLI_assert(a)
Definition BLI_assert.h:46
#define ARRAY_SIZE(arr)
Read Guarded memory(de)allocation.
@ PROP_FLOAT
Definition RNA_types.hh:164
BMesh const char void * data
struct bContext * BPY_context_get()
#define BPy_StructRNA_Check(v)
Definition bpy_rna.hh:73
static void py_rna_gizmo_handler_range_get_cb(const wmGizmo *, wmGizmoProperty *gz_prop, void *value_p)
static void py_rna_gizmo_handler_free_cb(const wmGizmo *, wmGizmoProperty *gz_prop)
bool BPY_rna_gizmo_module(PyObject *mod_par)
static int py_rna_gizmo_target_id_parse(PyObject *o, void *p)
static int py_rna_gizmo_target_id_parse_and_ensure_is_valid(PyObject *o, void *p)
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: str\n" " :arg get: Function that returns the value for this property (single value or sequence).\n" " :type get: Callable[[], float | Sequence[float]]\n" " :arg set: Function that takes a single value argument and applies it.\n" " :type set: Callable[[tuple[float, ...]], Any]\n" " :arg range: Function that returns a (min, max) tuple for gizmos that use a range. " "The returned value is not used.\n" " :type range: callable\n")
static PyObject * bpy_gizmo_target_set_handler(PyObject *, PyObject *args, PyObject *kw)
static PyObject * bpy_gizmo_target_set_value(PyObject *, PyObject *args, PyObject *kw)
static PyObject * bpy_gizmo_target_get_value(PyObject *, PyObject *args, PyObject *kw)
#define BPY_GIZMO_FN_SLOT_LEN
static PyObject * bpy_gizmo_target_get_range(PyObject *, PyObject *args, PyObject *kw)
static int py_rna_gizmo_target_type_id_parse(PyObject *o, void *p)
@ BPY_GIZMO_FN_SLOT_GET
@ BPY_GIZMO_FN_SLOT_RANGE_GET
@ BPY_GIZMO_FN_SLOT_SET
static void py_rna_gizmo_handler_get_cb(const wmGizmo *, wmGizmoProperty *gz_prop, void *value_p)
static void py_rna_gizmo_handler_set_cb(const wmGizmo *, wmGizmoProperty *gz_prop, const void *value_p)
static int py_rna_gizmo_parse(PyObject *o, void *p)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
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)
header-only compatibility defines.
Py_DECREF(oname)
#define PY_ARG_PARSER_HEAD_COMPAT()
return ret
bool RNA_struct_is_a(const StructRNA *type, const StructRNA *srna)
PyObject * fn_slots[BPY_GIZMO_FN_SLOT_LEN]
const wmGizmoPropertyType * gz_prop_type
wmGizmoProperty * gz_prop
wmGizmoPropertyFnGet value_get_fn
wmGizmoPropertyFnRangeGet range_get_fn
wmGizmoPropertyFnFree free_fn
wmGizmoPropertyFnSet value_set_fn
const wmGizmoPropertyType * type
struct wmGizmoProperty::@331027022007232055216276241130041346111314317052 custom_func
const char * idname
const wmGizmoType * type
i
Definition text_draw.cc:230
PointerRNA * ptr
Definition wm_files.cc:4238
void WM_gizmo_target_property_float_set(bContext *C, const wmGizmo *gz, wmGizmoProperty *gz_prop, const float value)
const wmGizmoPropertyType * WM_gizmotype_target_property_find(const wmGizmoType *gzt, 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)
int WM_gizmo_target_property_array_length(const wmGizmo *, wmGizmoProperty *gz_prop)
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)
wmGizmoProperty * WM_gizmo_target_property_find(wmGizmo *gz, const char *idname)
bool WM_gizmo_target_property_float_range_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, float range[2])