Manipulator: Support click only manipulator's
[blender.git] / source / blender / windowmanager / manipulators / intern / wm_manipulator.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/manipulators/intern/wm_manipulator.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 #ifdef WITH_PYTHON
57 #include "BPY_extern.h"
58 #endif
59
60 /* only for own init/exit calls (wm_manipulatortype_init/wm_manipulatortype_free) */
61 #include "wm.h"
62
63 /* own includes */
64 #include "wm_manipulator_wmapi.h"
65 #include "wm_manipulator_intern.h"
66
67 static void wm_manipulator_register(
68         wmManipulatorGroup *mgroup, wmManipulator *mpr);
69
70 /**
71  * \note Follow #wm_operator_create convention.
72  */
73 static wmManipulator *wm_manipulator_create(
74         const wmManipulatorType *wt,
75         PointerRNA *properties)
76 {
77         BLI_assert(wt != NULL);
78         BLI_assert(wt->struct_size >= sizeof(wmManipulator));
79
80         wmManipulator *mpr = MEM_callocN(
81                 wt->struct_size + (sizeof(wmManipulatorProperty) * wt->target_property_defs_len), __func__);
82         mpr->type = wt;
83
84         /* initialize properties, either copy or create */
85         mpr->ptr = MEM_callocN(sizeof(PointerRNA), "wmManipulatorPtrRNA");
86         if (properties && properties->data) {
87                 mpr->properties = IDP_CopyProperty(properties->data);
88         }
89         else {
90                 IDPropertyTemplate val = {0};
91                 mpr->properties = IDP_New(IDP_GROUP, &val, "wmManipulatorProperties");
92         }
93         RNA_pointer_create(G.main->wm.first, wt->srna, mpr->properties, mpr->ptr);
94
95         WM_manipulator_properties_sanitize(mpr->ptr, 0);
96
97         unit_m4(mpr->matrix_space);
98         unit_m4(mpr->matrix_basis);
99         unit_m4(mpr->matrix_offset);
100
101         mpr->drag_part = -1;
102
103         return mpr;
104 }
105
106 wmManipulator *WM_manipulator_new_ptr(
107         const wmManipulatorType *wt, wmManipulatorGroup *mgroup,
108         PointerRNA *properties)
109 {
110         wmManipulator *mpr = wm_manipulator_create(wt, properties);
111
112         wm_manipulator_register(mgroup, mpr);
113
114         if (mpr->type->setup != NULL) {
115                 mpr->type->setup(mpr);
116         }
117
118         return mpr;
119 }
120
121 /**
122  * \param wt: Must be valid,
123  * if you need to check it exists use #WM_manipulator_new_ptr
124  * because callers of this function don't NULL check the return value.
125  */
126 wmManipulator *WM_manipulator_new(
127         const char *idname, wmManipulatorGroup *mgroup,
128         PointerRNA *properties)
129 {
130         const wmManipulatorType *wt = WM_manipulatortype_find(idname, false);
131         return WM_manipulator_new_ptr(wt, mgroup, properties);
132 }
133
134 /**
135  * Initialize default values and allocate needed memory for members.
136  */
137 static void manipulator_init(wmManipulator *mpr)
138 {
139         const float color_default[4] = {1.0f, 1.0f, 1.0f, 1.0f};
140
141         mpr->scale_basis = 1.0f;
142         mpr->line_width = 1.0f;
143
144         /* defaults */
145         copy_v4_v4(mpr->color, color_default);
146         copy_v4_v4(mpr->color_hi, color_default);
147 }
148
149 /**
150  * Register \a manipulator.
151  *
152  * \param name: name used to create a unique idname for \a manipulator in \a mgroup
153  *
154  * \note Not to be confused with type registration from RNA.
155  */
156 static void wm_manipulator_register(wmManipulatorGroup *mgroup, wmManipulator *mpr)
157 {
158         manipulator_init(mpr);
159         wm_manipulatorgroup_manipulator_register(mgroup, mpr);
160 }
161
162 /**
163  * \warning this doesn't check #wmManipulatorMap (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_manipulator_free(wmManipulator *mpr)
168 {
169 #ifdef WITH_PYTHON
170         if (mpr->py_instance) {
171                 /* do this first in case there are any __del__ functions or
172                  * similar that use properties */
173                 BPY_DECREF_RNA_INVALIDATE(mpr->py_instance);
174         }
175 #endif
176
177         if (mpr->op_data) {
178                 for (int i = 0; i < mpr->op_data_len; i++) {
179                         WM_operator_properties_free(&mpr->op_data[i].ptr);
180                 }
181                 MEM_freeN(mpr->op_data);
182         }
183
184         if (mpr->ptr != NULL) {
185                 WM_manipulator_properties_free(mpr->ptr);
186                 MEM_freeN(mpr->ptr);
187         }
188
189         if (mpr->type->target_property_defs_len != 0) {
190                 wmManipulatorProperty *mpr_prop_array = WM_manipulator_target_property_array(mpr);
191                 for (int i = 0; i < mpr->type->target_property_defs_len; i++) {
192                         wmManipulatorProperty *mpr_prop = &mpr_prop_array[i];
193                         if (mpr_prop->custom_func.free_fn) {
194                                 mpr_prop->custom_func.free_fn(mpr, mpr_prop);
195                         }
196                 }
197         }
198
199         MEM_freeN(mpr);
200 }
201
202 /**
203  * Free \a manipulator and unlink from \a manipulatorlist.
204  * \a manipulatorlist is allowed to be NULL.
205  */
206 void WM_manipulator_unlink(ListBase *manipulatorlist, wmManipulatorMap *mmap, wmManipulator *mpr, bContext *C)
207 {
208         if (mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) {
209                 wm_manipulatormap_highlight_set(mmap, C, NULL, 0);
210         }
211         if (mpr->state & WM_MANIPULATOR_STATE_MODAL) {
212                 wm_manipulatormap_modal_set(mmap, C, mpr, NULL, false);
213         }
214         /* Unlink instead of setting so we don't run callbacks. */
215         if (mpr->state & WM_MANIPULATOR_STATE_SELECT) {
216                 WM_manipulator_select_unlink(mmap, mpr);
217         }
218
219         if (manipulatorlist) {
220                 BLI_remlink(manipulatorlist, mpr);
221         }
222
223         BLI_assert(mmap->mmap_context.highlight != mpr);
224         BLI_assert(mmap->mmap_context.modal != mpr);
225
226         WM_manipulator_free(mpr);
227 }
228
229 /* -------------------------------------------------------------------- */
230 /** \name Manipulator Creation API
231  *
232  * API for defining data on manipulator creation.
233  *
234  * \{ */
235
236 struct wmManipulatorOpElem *WM_manipulator_operator_get(
237         wmManipulator *mpr, int part_index)
238 {
239         if (mpr->op_data && ((part_index >= 0) && (part_index < mpr->op_data_len))) {
240                 return &mpr->op_data[part_index];
241         }
242         return NULL;
243 }
244
245 PointerRNA *WM_manipulator_operator_set(
246         wmManipulator *mpr, int part_index,
247         wmOperatorType *ot, IDProperty *properties)
248 {
249         BLI_assert(part_index < 255);
250         /* We could pre-allocate these but using multiple is such a rare thing. */
251         if (part_index >= mpr->op_data_len) {
252                 mpr->op_data_len = part_index + 1;
253                 mpr->op_data = MEM_recallocN(mpr->op_data, sizeof(*mpr->op_data) * mpr->op_data_len);
254         }
255         wmManipulatorOpElem *mpop = &mpr->op_data[part_index];
256         mpop->type = ot;
257
258         if (mpop->ptr.data) {
259                 WM_operator_properties_free(&mpop->ptr);
260         }
261         WM_operator_properties_create_ptr(&mpop->ptr, ot);
262
263         if (properties) {
264                 mpop->ptr.data = properties;
265         }
266
267         return &mpop->ptr;
268 }
269
270 static void wm_manipulator_set_matrix_rotation_from_z_axis__internal(
271         float matrix[4][4], const float z_axis[3])
272 {
273         /* old code, seems we can use simpler method */
274 #if 0
275         const float z_global[3] = {0.0f, 0.0f, 1.0f};
276         float rot[3][3];
277
278         rotation_between_vecs_to_mat3(rot, z_global, z_axis);
279         copy_v3_v3(matrix[0], rot[0]);
280         copy_v3_v3(matrix[1], rot[1]);
281         copy_v3_v3(matrix[2], rot[2]);
282 #else
283         normalize_v3_v3(matrix[2], z_axis);
284         ortho_basis_v3v3_v3(matrix[0], matrix[1], matrix[2]);
285 #endif
286
287 }
288
289 static void wm_manipulator_set_matrix_rotation_from_yz_axis__internal(
290         float matrix[4][4], const float y_axis[3], const float z_axis[3])
291 {
292         normalize_v3_v3(matrix[1], y_axis);
293         normalize_v3_v3(matrix[2], z_axis);
294         cross_v3_v3v3(matrix[0], matrix[1], matrix[2]);
295         normalize_v3(matrix[0]);
296 }
297
298 /**
299  * wmManipulator.matrix utils.
300  */
301 void WM_manipulator_set_matrix_rotation_from_z_axis(
302         wmManipulator *mpr, const float z_axis[3])
303 {
304         wm_manipulator_set_matrix_rotation_from_z_axis__internal(mpr->matrix_basis, z_axis);
305 }
306 void WM_manipulator_set_matrix_rotation_from_yz_axis(
307         wmManipulator *mpr, const float y_axis[3], const float z_axis[3])
308 {
309         wm_manipulator_set_matrix_rotation_from_yz_axis__internal(mpr->matrix_basis, y_axis, z_axis);
310 }
311 void WM_manipulator_set_matrix_location(wmManipulator *mpr, const float origin[3])
312 {
313         copy_v3_v3(mpr->matrix_basis[3], origin);
314 }
315
316 /**
317  * wmManipulator.matrix_offset utils.
318  */
319 void WM_manipulator_set_matrix_offset_rotation_from_z_axis(
320         wmManipulator *mpr, const float z_axis[3])
321 {
322         wm_manipulator_set_matrix_rotation_from_z_axis__internal(mpr->matrix_offset, z_axis);
323 }
324 void WM_manipulator_set_matrix_offset_rotation_from_yz_axis(
325         wmManipulator *mpr, const float y_axis[3], const float z_axis[3])
326 {
327         wm_manipulator_set_matrix_rotation_from_yz_axis__internal(mpr->matrix_offset, y_axis, z_axis);
328 }
329 void WM_manipulator_set_matrix_offset_location(wmManipulator *mpr, const float offset[3])
330 {
331         copy_v3_v3(mpr->matrix_offset[3], offset);
332 }
333
334 void WM_manipulator_set_flag(wmManipulator *mpr, const int flag, const bool enable)
335 {
336         if (enable) {
337                 mpr->flag |= flag;
338         }
339         else {
340                 mpr->flag &= ~flag;
341         }
342 }
343
344 void WM_manipulator_set_scale(wmManipulator *mpr, const float scale)
345 {
346         mpr->scale_basis = scale;
347 }
348
349 void WM_manipulator_set_line_width(wmManipulator *mpr, const float line_width)
350 {
351         mpr->line_width = line_width;
352 }
353
354 /**
355  * Set manipulator rgba colors.
356  *
357  * \param col  Normal state color.
358  * \param col_hi  Highlighted state color.
359  */
360 void WM_manipulator_get_color(const wmManipulator *mpr, float color[4])
361 {
362         copy_v4_v4(color, mpr->color);
363 }
364 void WM_manipulator_set_color(wmManipulator *mpr, const float color[4])
365 {
366         copy_v4_v4(mpr->color, color);
367 }
368
369 void WM_manipulator_get_color_highlight(const wmManipulator *mpr, float color_hi[4])
370 {
371         copy_v4_v4(color_hi, mpr->color_hi);
372 }
373 void WM_manipulator_set_color_highlight(wmManipulator *mpr, const float color_hi[4])
374 {
375         copy_v4_v4(mpr->color_hi, color_hi);
376 }
377
378
379 /** \} */ // Manipulator Creation API
380
381
382 /* -------------------------------------------------------------------- */
383 /** \name Manipulator Callback Assignment
384  *
385  * \{ */
386
387 void WM_manipulator_set_fn_custom_modal(struct wmManipulator *mpr, wmManipulatorFnModal fn)
388 {
389         mpr->custom_modal = fn;
390 }
391
392 /** \} */
393
394
395 /* -------------------------------------------------------------------- */
396
397 /**
398  * Add/Remove \a manipulator to selection.
399  * Reallocates memory for selected manipulators so better not call for selecting multiple ones.
400  *
401  * \return if the selection has changed.
402  */
403 bool wm_manipulator_select_set_ex(
404         wmManipulatorMap *mmap, wmManipulator *mpr, bool select,
405         bool use_array, bool use_callback)
406 {
407         bool changed = false;
408
409         if (select) {
410                 if ((mpr->state & WM_MANIPULATOR_STATE_SELECT) == 0) {
411                         if (use_array) {
412                                 wm_manipulatormap_select_array_push_back(mmap, mpr);
413                         }
414                         mpr->state |= WM_MANIPULATOR_STATE_SELECT;
415                         changed = true;
416                 }
417         }
418         else {
419                 if (mpr->state & WM_MANIPULATOR_STATE_SELECT) {
420                         if (use_array) {
421                                 wm_manipulatormap_select_array_remove(mmap, mpr);
422                         }
423                         mpr->state &= ~WM_MANIPULATOR_STATE_SELECT;
424                         changed = true;
425                 }
426         }
427
428         /* In the case of unlinking we only want to remove from the array
429          * and not write to the external state */
430         if (use_callback && changed) {
431                 if (mpr->type->select_refresh) {
432                         mpr->type->select_refresh(mpr);
433                 }
434         }
435
436         return changed;
437 }
438
439 /* Remove from selection array without running callbacks. */
440 bool WM_manipulator_select_unlink(wmManipulatorMap *mmap, wmManipulator *mpr)
441 {
442         return wm_manipulator_select_set_ex(mmap, mpr, false, true, false);
443 }
444
445 bool WM_manipulator_select_set(wmManipulatorMap *mmap, wmManipulator *mpr, bool select)
446 {
447         return wm_manipulator_select_set_ex(mmap, mpr, select, true, true);
448 }
449
450 void WM_manipulator_highlight_set(wmManipulatorMap *mmap, wmManipulator *mpr)
451 {
452         wm_manipulatormap_highlight_set(mmap, NULL, mpr, mpr ? mpr->highlight_part : 0);
453 }
454
455 bool wm_manipulator_select_and_highlight(bContext *C, wmManipulatorMap *mmap, wmManipulator *mpr)
456 {
457         if (WM_manipulator_select_set(mmap, mpr, true)) {
458                 wm_manipulatormap_highlight_set(mmap, C, mpr, mpr->highlight_part);
459                 return true;
460         }
461         else {
462                 return false;
463         }
464 }
465
466 void wm_manipulator_calculate_scale(wmManipulator *mpr, const bContext *C)
467 {
468         const RegionView3D *rv3d = CTX_wm_region_view3d(C);
469         float scale = U.ui_scale;
470
471         if ((mpr->parent_mgroup->type->flag & WM_MANIPULATORGROUPTYPE_SCALE) == 0) {
472                 scale *= U.manipulator_size;
473                 if (rv3d) {
474                         /* 'ED_view3d_pixel_size' includes 'U.pixelsize', remove it. */
475                         float matrix_world[4][4];
476                         if (mpr->type->matrix_basis_get) {
477                                 float matrix_basis[4][4];
478                                 mpr->type->matrix_basis_get(mpr, matrix_basis);
479                                 mul_m4_m4m4(matrix_world, mpr->matrix_space, matrix_basis);
480                         }
481                         else {
482                                 mul_m4_m4m4(matrix_world, mpr->matrix_space, mpr->matrix_basis);
483                         }
484
485                         /* Exclude matrix_offset from scale. */
486                         scale *= ED_view3d_pixel_size(rv3d, matrix_world[3]) / U.pixelsize;
487                 }
488                 else {
489                         scale *= 0.02f;
490                 }
491         }
492
493         mpr->scale_final = mpr->scale_basis * scale;
494 }
495
496 static void manipulator_update_prop_data(wmManipulator *mpr)
497 {
498         /* manipulator property might have been changed, so update manipulator */
499         if (mpr->type->property_update) {
500                 wmManipulatorProperty *mpr_prop_array = WM_manipulator_target_property_array(mpr);
501                 for (int i = 0; i < mpr->type->target_property_defs_len; i++) {
502                         wmManipulatorProperty *mpr_prop = &mpr_prop_array[i];
503                         if (WM_manipulator_target_property_is_valid(mpr_prop)) {
504                                 mpr->type->property_update(mpr, mpr_prop);
505                         }
506                 }
507         }
508 }
509
510 void wm_manipulator_update(wmManipulator *mpr, const bContext *C, const bool refresh_map)
511 {
512         if (refresh_map) {
513                 manipulator_update_prop_data(mpr);
514         }
515         wm_manipulator_calculate_scale(mpr, C);
516 }
517
518 int wm_manipulator_is_visible(wmManipulator *mpr)
519 {
520         if (mpr->flag & WM_MANIPULATOR_HIDDEN) {
521                 return 0;
522         }
523         if ((mpr->state & WM_MANIPULATOR_STATE_MODAL) &&
524             !(mpr->flag & (WM_MANIPULATOR_DRAW_MODAL | WM_MANIPULATOR_DRAW_VALUE)))
525         {
526                 /* don't draw while modal (dragging) */
527                 return 0;
528         }
529         if ((mpr->flag & WM_MANIPULATOR_DRAW_HOVER) &&
530             !(mpr->state & WM_MANIPULATOR_STATE_HIGHLIGHT) &&
531             !(mpr->state & WM_MANIPULATOR_STATE_SELECT)) /* still draw selected manipulators */
532         {
533                 /* update but don't draw */
534                 return WM_MANIPULATOR_IS_VISIBLE_UPDATE;
535         }
536
537         return WM_MANIPULATOR_IS_VISIBLE_UPDATE | WM_MANIPULATOR_IS_VISIBLE_DRAW;
538 }
539
540 void WM_manipulator_calc_matrix_final_params(
541         const wmManipulator *mpr,
542         const struct WM_ManipulatorMatrixParams *params,
543         float r_mat[4][4])
544 {
545         const float (* const matrix_space)[4]  = params->matrix_space  ? params->matrix_space  : mpr->matrix_space;
546         const float (* const matrix_basis)[4]  = params->matrix_basis  ? params->matrix_basis  : mpr->matrix_basis;
547         const float (* const matrix_offset)[4] = params->matrix_offset ? params->matrix_offset : mpr->matrix_offset;
548         const float *scale_final = params->scale_final ? params->scale_final : &mpr->scale_final;
549
550         float final_matrix[4][4];
551         if (params->matrix_basis == NULL && mpr->type->matrix_basis_get) {
552                 mpr->type->matrix_basis_get(mpr, final_matrix);
553         }
554         else {
555                 copy_m4_m4(final_matrix, matrix_basis);
556         }
557
558         if (mpr->flag & WM_MANIPULATOR_DRAW_NO_SCALE) {
559                 mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
560         }
561         else {
562                 if (mpr->flag & WM_MANIPULATOR_DRAW_OFFSET_SCALE) {
563                         mul_mat3_m4_fl(final_matrix, *scale_final);
564                         mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
565                 }
566                 else {
567                         mul_m4_m4m4(final_matrix, final_matrix, matrix_offset);
568                         mul_mat3_m4_fl(final_matrix, *scale_final);
569                 }
570         }
571
572         mul_m4_m4m4(r_mat, matrix_space, final_matrix);
573 }
574
575 void WM_manipulator_calc_matrix_final(const wmManipulator *mpr, float r_mat[4][4])
576 {
577         WM_manipulator_calc_matrix_final_params(
578                 mpr,
579                 &((struct WM_ManipulatorMatrixParams) {
580                     .matrix_space = NULL,
581                     .matrix_basis = NULL,
582                     .matrix_offset = NULL,
583                     .scale_final = NULL,
584                 }), r_mat
585         );
586 }
587
588 /** \name Manipulator Propery Access
589  *
590  * Matches `WM_operator_properties` conventions.
591  *
592  * \{ */
593
594
595 void WM_manipulator_properties_create_ptr(PointerRNA *ptr, wmManipulatorType *wt)
596 {
597         RNA_pointer_create(NULL, wt->srna, NULL, ptr);
598 }
599
600 void WM_manipulator_properties_create(PointerRNA *ptr, const char *wtstring)
601 {
602         const wmManipulatorType *wt = WM_manipulatortype_find(wtstring, false);
603
604         if (wt)
605                 WM_manipulator_properties_create_ptr(ptr, (wmManipulatorType *)wt);
606         else
607                 RNA_pointer_create(NULL, &RNA_ManipulatorProperties, NULL, ptr);
608 }
609
610 /* similar to the function above except its uses ID properties
611  * used for keymaps and macros */
612 void WM_manipulator_properties_alloc(PointerRNA **ptr, IDProperty **properties, const char *wtstring)
613 {
614         if (*properties == NULL) {
615                 IDPropertyTemplate val = {0};
616                 *properties = IDP_New(IDP_GROUP, &val, "wmOpItemProp");
617         }
618
619         if (*ptr == NULL) {
620                 *ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
621                 WM_manipulator_properties_create(*ptr, wtstring);
622         }
623
624         (*ptr)->data = *properties;
625
626 }
627
628 void WM_manipulator_properties_sanitize(PointerRNA *ptr, const bool no_context)
629 {
630         RNA_STRUCT_BEGIN (ptr, prop)
631         {
632                 switch (RNA_property_type(prop)) {
633                         case PROP_ENUM:
634                                 if (no_context)
635                                         RNA_def_property_flag(prop, PROP_ENUM_NO_CONTEXT);
636                                 else
637                                         RNA_def_property_clear_flag(prop, PROP_ENUM_NO_CONTEXT);
638                                 break;
639                         case PROP_POINTER:
640                         {
641                                 StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
642
643                                 /* recurse into manipulator properties */
644                                 if (RNA_struct_is_a(ptype, &RNA_ManipulatorProperties)) {
645                                         PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
646                                         WM_manipulator_properties_sanitize(&opptr, no_context);
647                                 }
648                                 break;
649                         }
650                         default:
651                                 break;
652                 }
653         }
654         RNA_STRUCT_END;
655 }
656
657
658 /** set all props to their default,
659  * \param do_update Only update un-initialized props.
660  *
661  * \note, theres nothing specific to manipulators here.
662  * this could be made a general function.
663  */
664 bool WM_manipulator_properties_default(PointerRNA *ptr, const bool do_update)
665 {
666         bool changed = false;
667         RNA_STRUCT_BEGIN (ptr, prop)
668         {
669                 switch (RNA_property_type(prop)) {
670                         case PROP_POINTER:
671                         {
672                                 StructRNA *ptype = RNA_property_pointer_type(ptr, prop);
673                                 if (ptype != &RNA_Struct) {
674                                         PointerRNA opptr = RNA_property_pointer_get(ptr, prop);
675                                         changed |= WM_manipulator_properties_default(&opptr, do_update);
676                                 }
677                                 break;
678                         }
679                         default:
680                                 if ((do_update == false) || (RNA_property_is_set(ptr, prop) == false)) {
681                                         if (RNA_property_reset(ptr, prop, -1)) {
682                                                 changed = true;
683                                         }
684                                 }
685                                 break;
686                 }
687         }
688         RNA_STRUCT_END;
689
690         return changed;
691 }
692
693 /* remove all props without PROP_SKIP_SAVE */
694 void WM_manipulator_properties_reset(wmManipulator *mpr)
695 {
696         if (mpr->ptr->data) {
697                 PropertyRNA *iterprop;
698                 iterprop = RNA_struct_iterator_property(mpr->type->srna);
699
700                 RNA_PROP_BEGIN (mpr->ptr, itemptr, iterprop)
701                 {
702                         PropertyRNA *prop = itemptr.data;
703
704                         if ((RNA_property_flag(prop) & PROP_SKIP_SAVE) == 0) {
705                                 const char *identifier = RNA_property_identifier(prop);
706                                 RNA_struct_idprops_unset(mpr->ptr, identifier);
707                         }
708                 }
709                 RNA_PROP_END;
710         }
711 }
712
713 void WM_manipulator_properties_clear(PointerRNA *ptr)
714 {
715         IDProperty *properties = ptr->data;
716
717         if (properties) {
718                 IDP_ClearProperty(properties);
719         }
720 }
721
722 void WM_manipulator_properties_free(PointerRNA *ptr)
723 {
724         IDProperty *properties = ptr->data;
725
726         if (properties) {
727                 IDP_FreeProperty(properties);
728                 MEM_freeN(properties);
729                 ptr->data = NULL; /* just in case */
730         }
731 }
732
733 /** \} */