Docs: correct doxy comments
[blender.git] / source / blender / windowmanager / gizmo / intern / wm_gizmo.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2014 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/windowmanager/gizmo/intern/wm_gizmo.c
27  *  \ingroup wm
28  */
29
30 #include "MEM_guardedalloc.h"
31
32 #include "BLI_listbase.h"
33 #include "BLI_math.h"
34 #include "BLI_string.h"
35 #include "BLI_string_utils.h"
36
37 #include "BKE_context.h"
38
39 #include "GPU_batch.h"
40 #include "GPU_glew.h"
41 #include "GPU_immediate.h"
42
43 #include "RNA_access.h"
44 #include "RNA_define.h"
45
46 #include "BKE_global.h"
47 #include "BKE_main.h"
48 #include "BKE_idprop.h"
49
50 #include "WM_api.h"
51 #include "WM_types.h"
52
53 #include "ED_screen.h"
54 #include "ED_view3d.h"
55
56 #include "UI_interface.h"
57
58 #ifdef WITH_PYTHON
59 #include "BPY_extern.h"
60 #endif
61
62 /* only for own init/exit calls (wm_gizmotype_init/wm_gizmotype_free) */
63 #include "wm.h"
64
65 /* own includes */
66 #include "wm_gizmo_wmapi.h"
67 #include "wm_gizmo_intern.h"
68
69 static void wm_gizmo_register(
70         wmGizmoGroup *gzgroup, wmGizmo *gz);
71
72 /**
73  * \note Follow #wm_operator_create convention.
74  */
75 static wmGizmo *wm_gizmo_create(
76         const wmGizmoType *gzt,
77         PointerRNA *properties)
78 {
79         BLI_assert(gzt != NULL);
80         BLI_assert(gzt->struct_size >= sizeof(wmGizmo));
81
82         wmGizmo *gz = MEM_callocN(
83                 gzt->struct_size + (sizeof(wmGizmoProperty) * gzt->target_property_defs_len), __func__);
84         gz->type = gzt;
85
86         /* initialize properties, either copy or create */
87         gz->ptr = MEM_callocN(sizeof(PointerRNA), "wmGizmoPtrRNA");
88         if (properties && properties->data) {
89                 gz->properties = IDP_CopyProperty(properties->data);
90         }
91         else {
92                 IDPropertyTemplate val = {0};
93                 gz->properties = IDP_New(IDP_GROUP, &val, "wmGizmoProperties");
94         }
95         RNA_pointer_create(G_MAIN->wm.first, gzt->srna, gz->properties, gz->ptr);
96
97         WM_gizmo_properties_sanitize(gz->ptr, 0);
98
99         unit_m4(gz->matrix_space);
100         unit_m4(gz->matrix_basis);
101         unit_m4(gz->matrix_offset);
102
103         gz->drag_part = -1;
104
105         return gz;
106 }
107
108 wmGizmo *WM_gizmo_new_ptr(
109         const wmGizmoType *gzt, wmGizmoGroup *gzgroup,
110         PointerRNA *properties)
111 {
112         wmGizmo *gz = wm_gizmo_create(gzt, properties);
113
114         wm_gizmo_register(gzgroup, gz);
115
116         if (gz->type->setup != NULL) {
117                 gz->type->setup(gz);
118         }
119
120         return gz;
121 }
122
123 /**
124  * \param name: Must be a valid gizmo type name,
125  * if you need to check it exists use #WM_gizmo_new_ptr
126  * because callers of this function don't NULL check the return value.
127  */
128 wmGizmo *WM_gizmo_new(
129         const char *idname, wmGizmoGroup *gzgroup,
130         PointerRNA *properties)
131 {
132         const wmGizmoType *gzt = WM_gizmotype_find(idname, false);
133         return WM_gizmo_new_ptr(gzt, gzgroup, properties);
134 }
135
136 /**
137  * Initialize default values and allocate needed memory for members.
138  */
139 static void gizmo_init(wmGizmo *gz)
140 {
141         const float color_default[4] = {1.0f, 1.0f, 1.0f, 1.0f};
142
143         gz->scale_basis = 1.0f;
144         gz->line_width = 1.0f;
145
146         /* defaults */
147         copy_v4_v4(gz->color, color_default);
148         copy_v4_v4(gz->color_hi, color_default);
149 }
150
151 /**
152  * Register \a gizmo.
153  *
154  * \note Not to be confused with type registration from RNA.
155  */
156 static void wm_gizmo_register(wmGizmoGroup *gzgroup, wmGizmo *gz)
157 {
158         gizmo_init(gz);
159         wm_gizmogroup_gizmo_register(gzgroup, gz);
160 }
161
162 /**
163  * \warning this doesn't check #wmGizmoMap (highlight, selection etc).
164  * Typical use is when freeing the windowing data,
165  * where caller can manage clearing selection, highlight... etc.
166  */
167 void WM_gizmo_free(wmGizmo *gz)
168 {
169         if (gz->type->free != NULL) {
170                 gz->type->free(gz);
171         }
172
173 #ifdef WITH_PYTHON
174         if (gz->py_instance) {
175                 /* do this first in case there are any __del__ functions or
176                  * similar that use properties */
177                 BPY_DECREF_RNA_INVALIDATE(gz->py_instance);
178         }
179 #endif
180
181         if (gz->op_data) {
182                 for (int i = 0; i < gz->op_data_len; i++) {
183                         WM_operator_properties_free(&gz->op_data[i].ptr);
184                 }
185                 MEM_freeN(gz->op_data);
186         }
187
188         if (gz->ptr != NULL) {
189                 WM_gizmo_properties_free(gz->ptr);
190                 MEM_freeN(gz->ptr);
191         }
192
193         if (gz->type->target_property_defs_len != 0) {
194                 wmGizmoProperty *gz_prop_array = WM_gizmo_target_property_array(gz);
195                 for (int i = 0; i < gz->type->target_property_defs_len; i++) {
196                         wmGizmoProperty *gz_prop = &gz_prop_array[i];
197                         if (gz_prop->custom_func.free_fn) {
198                                 gz_prop->custom_func.free_fn(gz, gz_prop);
199                         }
200                 }
201         }
202
203         MEM_freeN(gz);
204 }
205
206 /**
207  * Free \a gizmo and unlink from \a gizmolist.
208  * \a gizmolist is allowed to be NULL.
209  */
210 void WM_gizmo_unlink(ListBase *gizmolist, wmGizmoMap *gzmap, wmGizmo *gz, bContext *C)
211 {
212         if (gz->state & WM_GIZMO_STATE_HIGHLIGHT) {
213                 wm_gizmomap_highlight_set(gzmap, C, NULL, 0);
214         }
215         if (gz->state & WM_GIZMO_STATE_MODAL) {
216                 wm_gizmomap_modal_set(gzmap, C, gz, NULL, false);
217         }
218         /* Unlink instead of setting so we don't run callbacks. */
219         if (gz->state & WM_GIZMO_STATE_SELECT) {
220                 WM_gizmo_select_unlink(gzmap, gz);
221         }
222
223         if (gizmolist) {
224                 BLI_remlink(gizmolist, gz);
225         }
226
227         BLI_assert(gzmap->gzmap_context.highlight != gz);
228         BLI_assert(gzmap->gzmap_context.modal != gz);
229
230         WM_gizmo_free(gz);
231 }
232
233 /* -------------------------------------------------------------------- */
234 /** \name Gizmo Creation API
235  *
236  * API for defining data on gizmo creation.
237  *
238  * \{ */
239
240 struct wmGizmoOpElem *WM_gizmo_operator_get(
241         wmGizmo *gz, int part_index)
242 {
243         if (gz->op_data && ((part_index >= 0) && (part_index < gz->op_data_len))) {
244                 return &gz->op_data[part_index];
245         }
246         return NULL;
247 }
248
249 PointerRNA *WM_gizmo_operator_set(
250         wmGizmo *gz, int part_index,
251         wmOperatorType *ot, IDProperty *properties)
252 {
253         BLI_assert(part_index < 255);
254         /* We could pre-allocate these but using multiple is such a rare thing. */
255         if (part_index >= gz->op_data_len) {
256                 gz->op_data_len = part_index + 1;
257                 gz->op_data = MEM_recallocN(gz->op_data, sizeof(*gz->op_data) * gz->op_data_len);
258         }
259         wmGizmoOpElem *gzop = &gz->op_data[part_index];
260         gzop->type = ot;
261
262         if (gzop->ptr.data) {
263                 WM_operator_properties_free(&gzop->ptr);
264         }
265         WM_operator_properties_create_ptr(&gzop->ptr, ot);
266
267         if (properties) {
268                 gzop->ptr.data = properties;
269         }
270
271         return &gzop->ptr;
272 }
273
274 static void wm_gizmo_set_matrix_rotation_from_z_axis__internal(
275         float matrix[4][4], const float z_axis[3])
276 {
277         /* old code, seems we can use simpler method */
278 #if 0
279         const float z_global[3] = {0.0f, 0.0f, 1.0f};
280         float rot[3][3];
281
282         rotation_between_vecs_to_mat3(rot, z_global, z_axis);
283         copy_v3_v3(matrix[0], rot[0]);
284         copy_v3_v3(matrix[1], rot[1]);
285         copy_v3_v3(matrix[2], rot[2]);
286 #else
287         normalize_v3_v3(matrix[2], z_axis);
288         ortho_basis_v3v3_v3(matrix[0], matrix[1], matrix[2]);
289 #endif
290
291 }
292
293 static void wm_gizmo_set_matrix_rotation_from_yz_axis__internal(
294         float matrix[4][4], const float y_axis[3], const float z_axis[3])
295 {
296         normalize_v3_v3(matrix[1], y_axis);
297         normalize_v3_v3(matrix[2], z_axis);
298         cross_v3_v3v3(matrix[0], matrix[1], matrix[2]);
299         normalize_v3(matrix[0]);
300 }
301
302 /**
303  * wmGizmo.matrix utils.
304  */
305 void WM_gizmo_set_matrix_rotation_from_z_axis(
306         wmGizmo *gz, const float z_axis[3])
307 {
308         wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_basis, z_axis);
309 }
310 void WM_gizmo_set_matrix_rotation_from_yz_axis(
311         wmGizmo *gz, const float y_axis[3], const float z_axis[3])
312 {
313         wm_gizmo_set_matrix_rotation_from_yz_axis__internal(gz->matrix_basis, y_axis, z_axis);
314 }
315 void WM_gizmo_set_matrix_location(wmGizmo *gz, const float origin[3])
316 {
317         copy_v3_v3(gz->matrix_basis[3], origin);
318 }
319
320 /**
321  * wmGizmo.matrix_offset utils.
322  */
323 void WM_gizmo_set_matrix_offset_rotation_from_z_axis(
324         wmGizmo *gz, const float z_axis[3])
325 {
326         wm_gizmo_set_matrix_rotation_from_z_axis__internal(gz->matrix_offset, z_axis);
327 }
328 void WM_gizmo_set_matrix_offset_rotation_from_yz_axis(
329         wmGizmo *gz, const float y_axis[3], const float z_axis[3])
330 {
331         wm_gizmo_set_matrix_rotation_from_yz_axis__internal(gz->matrix_offset, y_axis, z_axis);
332 }
333 void WM_gizmo_set_matrix_offset_location(wmGizmo *gz, const float offset[3])
334 {
335         copy_v3_v3(gz->matrix_offset[3], offset);
336 }
337
338 void WM_gizmo_set_flag(wmGizmo *gz, const int flag, const bool enable)
339 {
340         if (enable) {
341                 gz->flag |= flag;
342         }
343         else {
344                 gz->flag &= ~flag;
345         }
346 }
347
348 void WM_gizmo_set_scale(wmGizmo *gz, const float scale)
349 {
350         gz->scale_basis = scale;
351 }
352
353 void WM_gizmo_set_line_width(wmGizmo *gz, const float line_width)
354 {
355         gz->line_width = line_width;
356 }
357
358 void WM_gizmo_get_color(const wmGizmo *gz, float color[4])
359 {
360         copy_v4_v4(color, gz->color);
361 }
362 void WM_gizmo_set_color(wmGizmo *gz, const float color[4])
363 {
364         copy_v4_v4(gz->color, color);
365 }
366
367 void WM_gizmo_get_color_highlight(const wmGizmo *gz, float color_hi[4])
368 {
369         copy_v4_v4(color_hi, gz->color_hi);
370 }
371 void WM_gizmo_set_color_highlight(wmGizmo *gz, const float color_hi[4])
372 {
373         copy_v4_v4(gz->color_hi, color_hi);
374 }
375
376
377 /** \} */ // Gizmo Creation API
378
379
380 /* -------------------------------------------------------------------- */
381 /** \name Gizmo Callback Assignment
382  *
383  * \{ */
384
385 void WM_gizmo_set_fn_custom_modal(struct wmGizmo *gz, wmGizmoFnModal fn)
386 {
387         gz->custom_modal = fn;
388 }
389
390 /** \} */
391
392
393 /* -------------------------------------------------------------------- */
394
395 /**
396  * Add/Remove \a gizmo to selection.
397  * Reallocates memory for selected gizmos so better not call for selecting multiple ones.
398  *
399  * \return if the selection has changed.
400  */
401 bool wm_gizmo_select_set_ex(
402         wmGizmoMap *gzmap, wmGizmo *gz, bool select,
403         bool use_array, bool use_callback)
404 {
405         bool changed = false;
406
407         if (select) {
408                 if ((gz->state & WM_GIZMO_STATE_SELECT) == 0) {
409                         if (use_array) {
410                                 wm_gizmomap_select_array_push_back(gzmap, gz);
411                         }
412                         gz->state |= WM_GIZMO_STATE_SELECT;
413                         changed = true;
414                 }
415         }
416         else {
417                 if (gz->state & WM_GIZMO_STATE_SELECT) {
418                         if (use_array) {
419                                 wm_gizmomap_select_array_remove(gzmap, gz);
420                         }
421                         gz->state &= ~WM_GIZMO_STATE_SELECT;
422                         changed = true;
423                 }
424         }
425
426         /* In the case of unlinking we only want to remove from the array
427          * and not write to the external state */
428         if (use_callback && changed) {
429                 if (gz->type->select_refresh) {
430                         gz->type->select_refresh(gz);
431                 }
432         }
433
434         return changed;
435 }
436
437 /* Remove from selection array without running callbacks. */
438 bool WM_gizmo_select_unlink(wmGizmoMap *gzmap, wmGizmo *gz)
439 {
440         return wm_gizmo_select_set_ex(gzmap, gz, false, true, false);
441 }
442
443 bool WM_gizmo_select_set(wmGizmoMap *gzmap, wmGizmo *gz, bool select)
444 {
445         return wm_gizmo_select_set_ex(gzmap, gz, select, true, true);
446 }
447
448 void WM_gizmo_highlight_set(wmGizmoMap *gzmap, wmGizmo *gz)
449 {
450         wm_gizmomap_highlight_set(gzmap, NULL, gz, gz ? gz->highlight_part : 0);
451 }
452
453 bool wm_gizmo_select_and_highlight(bContext *C, wmGizmoMap *gzmap, wmGizmo *gz)
454 {
455         if (WM_gizmo_select_set(gzmap, gz, true)) {
456                 wm_gizmomap_highlight_set(gzmap, C, gz, gz->highlight_part);
457                 return true;
458         }
459         else {
460                 return false;
461         }
462 }
463
464 /**
465  * Special function to run from setup so gizmos start out interactive.
466  *
467  * We could do this when linking them, but this complicates things since the window update code needs to run first.
468  */
469 void WM_gizmo_modal_set_from_setup(
470         struct wmGizmoMap *gzmap, struct bContext *C,
471         struct wmGizmo *gz, int part_index, const wmEvent *event)
472 {
473         gz->highlight_part = part_index;
474         WM_gizmo_highlight_set(gzmap, gz);
475         if (false) {
476                 wm_gizmomap_modal_set(gzmap, C, gz, event, true);
477         }
478         else {
479                 /* WEAK: but it works. */
480                 WM_operator_name_call(C, "GIZMOGROUP_OT_gizmo_tweak", WM_OP_INVOKE_DEFAULT, NULL);
481         }
482 }
483
484 void wm_gizmo_calculate_scale(wmGizmo *gz, const bContext *C)
485 {
486         const RegionView3D *rv3d = CTX_wm_region_view3d(C);
487         float scale = UI_DPI_FAC;
488
489         if ((gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_SCALE) == 0) {
490                 scale *= U.gizmo_size;
491                 if (rv3d) {
492                         /* 'ED_view3d_pixel_size' includes 'U.pixelsize', remove it. */
493                         float matrix_world[4][4];
494                         if (gz->type->matrix_basis_get) {
495                                 float matrix_basis[4][4];
496                                 gz->type->matrix_basis_get(gz, matrix_basis);
497                                 mul_m4_m4m4(matrix_world, gz->matrix_space, matrix_basis);
498                         }
499                         else {
500                                 mul_m4_m4m4(matrix_world, gz->matrix_space, gz->matrix_basis);
501                         }
502
503                         /* Exclude matrix_offset from scale. */
504                         scale *= ED_view3d_pixel_size_no_ui_scale(rv3d, matrix_world[3]);
505                 }
506                 else {
507                         scale *= 0.02f;
508                 }
509         }
510
511         gz->scale_final = gz->scale_basis * scale;
512 }
513
514 static void gizmo_update_prop_data(wmGizmo *gz)
515 {
516         /* gizmo property might have been changed, so update gizmo */
517         if (gz->type->property_update) {
518                 wmGizmoProperty *gz_prop_array = WM_gizmo_target_property_array(gz);
519                 for (int i = 0; i < gz->type->target_property_defs_len; i++) {
520                         wmGizmoProperty *gz_prop = &gz_prop_array[i];
521                         if (WM_gizmo_target_property_is_valid(gz_prop)) {
522                                 gz->type->property_update(gz, gz_prop);
523                         }
524                 }
525         }
526 }
527
528 void wm_gizmo_update(wmGizmo *gz, const bContext *C, const bool refresh_map)
529 {
530         if (refresh_map) {
531                 gizmo_update_prop_data(gz);
532         }
533         wm_gizmo_calculate_scale(gz, C);
534 }
535
536 int wm_gizmo_is_visible(wmGizmo *gz)
537 {
538         if (gz->flag & WM_GIZMO_HIDDEN) {
539                 return 0;
540         }
541         if ((gz->state & WM_GIZMO_STATE_MODAL) &&
542             !(gz->flag & (WM_GIZMO_DRAW_MODAL | WM_GIZMO_DRAW_VALUE)))
543         {
544                 /* don't draw while modal (dragging) */
545                 return 0;
546         }
547         if ((gz->flag & WM_GIZMO_DRAW_HOVER) &&
548             !(gz->state & WM_GIZMO_STATE_HIGHLIGHT) &&
549             !(gz->state & WM_GIZMO_STATE_SELECT)) /* still draw selected gizmos */
550         {
551                 /* update but don't draw */
552                 return WM_GIZMO_IS_VISIBLE_UPDATE;
553         }
554
555         return WM_GIZMO_IS_VISIBLE_UPDATE | WM_GIZMO_IS_VISIBLE_DRAW;
556 }
557
558 void WM_gizmo_calc_matrix_final_params(
559         const wmGizmo *gz,
560         const struct WM_GizmoMatrixParams *params,
561         float r_mat[4][4])
562 {
563         const float (* const matrix_space)[4]  = params->matrix_space  ? params->matrix_space  : gz->matrix_space;
564         const float (* const matrix_basis)[4]  = params->matrix_basis  ? params->matrix_basis  : gz->matrix_basis;
565         const float (* const matrix_offset)[4] = params->matrix_offset ? params->matrix_offset : gz->matrix_offset;
566         const float *scale_final = params->scale_final ? params->scale_final : &gz->scale_final;
567
568         float final_matrix[4][4];
569         if (params->matrix_basis == NULL && gz->type->matrix_basis_get) {
570                 gz->type->matrix_basis_get(gz, final_matrix);
571         }
572         else {
573                 copy_m4_m4(final_matrix, matrix_basis);
574         }
575
576         if (gz->flag & WM_GIZMO_DRAW_NO_SCALE) {
577                 mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
578         }
579         else {
580                 if (gz->flag & WM_GIZMO_DRAW_OFFSET_SCALE) {
581                         mul_mat3_m4_fl(final_matrix, *scale_final);
582                         mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
583                 }
584                 else {
585                         mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
586                         mul_mat3_m4_fl(final_matrix, *scale_final);
587                 }
588         }
589
590         mul_m4_m4m4(r_mat, matrix_space, final_matrix);
591 }
592
593 void WM_gizmo_calc_matrix_final_no_offset(const wmGizmo *gz, float r_mat[4][4])
594 {
595         float mat_identity[4][4];
596         unit_m4(mat_identity);
597
598         WM_gizmo_calc_matrix_final_params(
599                 gz,
600                 &((struct WM_GizmoMatrixParams) {
601                     .matrix_space = NULL,
602                     .matrix_basis = NULL,
603                     .matrix_offset = mat_identity,
604                     .scale_final = NULL,
605                 }), r_mat
606         );
607 }
608
609 void WM_gizmo_calc_matrix_final(const wmGizmo *gz, float r_mat[4][4])
610 {
611         WM_gizmo_calc_matrix_final_params(
612                 gz,
613                 &((struct WM_GizmoMatrixParams) {
614                     .matrix_space = NULL,
615                     .matrix_basis = NULL,
616                     .matrix_offset = NULL,
617                     .scale_final = NULL,
618                 }), r_mat
619         );
620 }
621
622 /** \name Gizmo Property Access
623  *
624  * Matches `WM_operator_properties` conventions.
625  *
626  * \{ */
627
628
629 void WM_gizmo_properties_create_ptr(PointerRNA *ptr, wmGizmoType *gzt)
630 {
631         RNA_pointer_create(NULL, gzt->srna, NULL, ptr);
632 }
633
634 void WM_gizmo_properties_create(PointerRNA *ptr, const char *gtstring)
635 {
636         const wmGizmoType *gzt = WM_gizmotype_find(gtstring, false);
637
638         if (gzt)
639                 WM_gizmo_properties_create_ptr(ptr, (wmGizmoType *)gzt);
640         else
641                 RNA_pointer_create(NULL, &RNA_GizmoProperties, NULL, ptr);
642 }
643
644 /* similar to the function above except its uses ID properties
645  * used for keymaps and macros */
646 void WM_gizmo_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *gtstring)
647 {
648         if (*properties == NULL) {
649                 IDPropertyTemplate val = {0};
650                 *properties = IDP_New(IDP_GROUP, &val, "wmOpItemProp");
651         }
652
653         if (*ptr == NULL) {
654                 *ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
655                 WM_gizmo_properties_create(*ptr, gtstring);
656         }
657
658         (*ptr)->data = *properties;
659
660 }
661
662 void WM_gizmo_properties_sanitize(PointerRNA *ptr, const bool no_context)
663 {
664         RNA_STRUCT_BEGIN (ptr, prop)
665         {
666                 switch (RNA_property_type(prop)) {
667                         case PROP_ENUM:
668                                 if (no_context)
669                                         RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
670                                 else
671                                         RNA_def_property_clear_flag(prop, PROP_ENUM_NO_CONTEXT);
672                                 break;
673                         case PROP_POINTER:
674                         {
675                                 StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
676
677                                 /* recurse into gizmo properties */
678                                 if (RNA_struct_is_a(ptype, &RNA_GizmoProperties)) {
679                                         PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
680                                         WM_gizmo_properties_sanitize(&opptr, no_context);
681                                 }
682                                 break;
683                         }
684                         default:
685                                 break;
686                 }
687         }
688         RNA_STRUCT_END;
689 }
690
691
692 /** set all props to their default,
693  * \param do_update Only update un-initialized props.
694  *
695  * \note, there's nothing specific to gizmos here.
696  * this could be made a general function.
697  */
698 bool WM_gizmo_properties_default(PointerRNA *ptr, const bool do_update)
699 {
700         bool changed = false;
701         RNA_STRUCT_BEGIN (ptr, prop)
702         {
703                 switch (RNA_property_type(prop)) {
704                         case PROP_POINTER:
705                         {
706                                 StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
707                                 if (ptype != &RNA_Struct) {
708                                         PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
709                                         changed |= WM_gizmo_properties_default(&opptr, do_update);
710                                 }
711                                 break;
712                         }
713                         default:
714                                 if ((do_update == false) || (RNA_property_is_set(ptr, prop) == false)) {
715                                         if (RNA_property_reset(ptr, prop, -1)) {
716                                                 changed = true;
717                                         }
718                                 }
719                                 break;
720                 }
721         }
722         RNA_STRUCT_END;
723
724         return changed;
725 }
726
727 /* remove all props without PROP_SKIP_SAVE */
728 void WM_gizmo_properties_reset(wmGizmo *gz)
729 {
730         if (gz->ptr->data) {
731                 PropertyRNA *iterprop;
732                 iterprop = RNA_struct_iterator_property(gz->type->srna);
733
734                 RNA_PROP_BEGIN (gz->ptr, itemptr, iterprop)
735                 {
736                         PropertyRNA *prop = itemptr.data;
737
738                         if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
739                                 const char *identifier = RNA_property_identifier(prop);
740                                 RNA_struct_idprops_unset(gz->ptr, identifier);
741                         }
742                 }
743                 RNA_PROP_END;
744         }
745 }
746
747 void WM_gizmo_properties_clear(PointerRNA *ptr)
748 {
749         IDProperty *properties = ptr->data;
750
751         if (properties) {
752                 IDP_ClearProperty(properties);
753         }
754 }
755
756 void WM_gizmo_properties_free(PointerRNA *ptr)
757 {
758         IDProperty *properties = ptr->data;
759
760         if (properties) {
761                 IDP_FreeProperty(properties);
762                 MEM_freeN(properties);
763                 ptr->data = NULL; /* just in case */
764         }
765 }
766
767 /** \} */
768
769 /** \name General Utilities
770  *
771  * \{ */
772
773 bool WM_gizmo_context_check_drawstep(const struct bContext *C, eWM_GizmoFlagMapDrawStep step)
774 {
775         switch (step) {
776                 case WM_GIZMOMAP_DRAWSTEP_2D:
777                 {
778                         break;
779                 }
780                 case WM_GIZMOMAP_DRAWSTEP_3D:
781                 {
782                         wmWindowManager *wm = CTX_wm_manager(C);
783                         if (ED_screen_animation_playing(wm)) {
784                                 return false;
785                         }
786                         break;
787                 }
788         }
789         return true;
790 }
791
792 /** \} */