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