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