Blender V5.0
transform_gizmo_2d.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12
13#include "MEM_guardedalloc.h"
14
15#include "BLI_math_matrix.h"
16#include "BLI_math_rotation.h"
17#include "BLI_math_vector.h"
19
20#include "DNA_object_types.h"
21#include "DNA_screen_types.h"
22#include "DNA_sequence_types.h"
23#include "DNA_space_types.h"
24#include "DNA_view3d_types.h"
25
26#include "BKE_context.hh"
27#include "BKE_global.hh"
28#include "BKE_layer.hh"
29
30#include "RNA_access.hh"
31
32#include "UI_resources.hh"
33#include "UI_view2d.hh"
34
35#include "WM_api.hh"
36#include "WM_message.hh"
37#include "WM_types.hh"
38
39#include "ED_gizmo_library.hh"
40#include "ED_gizmo_utils.hh"
41#include "ED_image.hh"
42#include "ED_mask.hh"
43#include "ED_screen.hh"
44#include "ED_uvedit.hh"
45
46#include "SEQ_channels.hh"
47#include "SEQ_iterator.hh"
48#include "SEQ_sequencer.hh"
49#include "SEQ_transform.hh"
50
51#include "transform.hh"
52#include "transform_gizmo.hh"
53
54namespace blender::ed::transform {
55
56/* -------------------------------------------------------------------- */
59
61{
63 return false;
64 }
65
66 if ((U.gizmo_flag & USER_GIZMO_DRAW) == 0) {
67 return false;
68 }
69
70 if (G.moving) {
71 return false;
72 }
73
74 ScrArea *area = CTX_wm_area(C);
75 if (area == nullptr) {
76 return false;
77 }
78
79 /* NOTE: below this is assumed to be a tool gizmo.
80 * If there are cases that need to check other flags - this function could be split. */
81 switch (area->spacetype) {
82 case SPACE_IMAGE: {
83 const SpaceImage *sima = static_cast<const SpaceImage *>(area->spacedata.first);
84 Object *obedit = CTX_data_edit_object(C);
85 if (!(ED_space_image_show_uvedit(sima, obedit) || ED_space_image_show_mask(sima))) {
86 return false;
87 }
88 break;
89 }
90 case SPACE_SEQ: {
91 const SpaceSeq *sseq = static_cast<const SpaceSeq *>(area->spacedata.first);
93 return false;
94 }
95 if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
96 return false;
97 }
98 Scene *scene = CTX_data_scene(C);
99 Editing *ed = seq::editing_get(scene);
100 if (ed == nullptr) {
101 return false;
102 }
103 break;
104 }
105 }
106
107 return true;
108}
109
111 wmMsgBus *mbus, /* Additional args. */
112 bScreen *screen,
113 ScrArea *area,
114 ARegion *region)
115{
116 wmMsgSubscribeValue msg_sub_value_gz_tag_refresh{};
117 msg_sub_value_gz_tag_refresh.owner = region;
118 msg_sub_value_gz_tag_refresh.user_data = gzgroup->parent_gzmap;
119 msg_sub_value_gz_tag_refresh.notify = WM_gizmo_do_msg_notify_tag_refresh;
120
121 switch (area->spacetype) {
122 case SPACE_IMAGE: {
123 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
124 PointerRNA ptr = RNA_pointer_create_discrete(&screen->id, &RNA_SpaceImageEditor, sima);
125 {
126 const PropertyRNA *props[] = {
127 &rna_SpaceImageEditor_pivot_point,
128 (sima->around == V3D_AROUND_CURSOR) ? &rna_SpaceImageEditor_cursor_location : nullptr,
129 };
130 for (int i = 0; i < ARRAY_SIZE(props); i++) {
131 if (props[i] == nullptr) {
132 continue;
133 }
134 WM_msg_subscribe_rna(mbus, &ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
135 }
136 }
137 break;
138 }
139 }
140}
141
143
144/* -------------------------------------------------------------------- */
153
154/* Axes as index. */
155enum {
158
160};
161
165
166 /* Current origin in view space, used to update widget origin for possible view changes. */
167 float origin[2];
168 float min[2];
169 float max[2];
170 float rotation;
171
173};
174
175/* **************** Utilities **************** */
176
177static void gizmo2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi)
178{
179 const float alpha = 0.6f;
180 const float alpha_hi = 1.0f;
181 int col_id;
182
183 switch (axis_idx) {
185 col_id = TH_AXIS_X;
186 break;
188 col_id = TH_AXIS_Y;
189 break;
190 default:
191 BLI_assert(0);
192 col_id = TH_AXIS_Y;
193 break;
194 }
195
196 UI_GetThemeColor4fv(col_id, r_col);
197
198 copy_v4_v4(r_col_hi, r_col);
199 r_col[3] *= alpha;
200 r_col_hi[3] *= alpha_hi;
201}
202
204{
205 const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
206 const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_2d", true);
207 const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
208
210
211 ggd->translate_xy[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
212 ggd->translate_xy[1] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
213 ggd->translate_xy[2] = WM_gizmo_new_ptr(gzt_button, gzgroup, nullptr);
214 ggd->cage = WM_gizmo_new_ptr(gzt_cage, gzgroup, nullptr);
215
216 RNA_enum_set(ggd->cage->ptr,
217 "transform",
220 RNA_enum_set(ggd->cage->ptr,
221 "draw_options",
224
225 return ggd;
226}
227
231static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max)
232{
233 float min_buf[2], max_buf[2];
234 if (r_min == nullptr) {
235 r_min = min_buf;
236 }
237 if (r_max == nullptr) {
238 r_max = max_buf;
239 }
240
241 ScrArea *area = CTX_wm_area(C);
242 bool has_select = false;
243 if (area->spacetype == SPACE_IMAGE) {
244 const SpaceImage *sima = static_cast<const SpaceImage *>(area->spacedata.first);
245 switch (sima->mode) {
246 case SI_MODE_UV: {
247 Scene *scene = CTX_data_scene(C);
248 ViewLayer *view_layer = CTX_data_view_layer(C);
249 Vector<Object *> objects =
251 scene, view_layer, nullptr);
252 if (ED_uvedit_minmax_multi(scene, objects, r_min, r_max)) {
253 has_select = true;
254 }
255 break;
256 }
257 case SI_MODE_MASK: {
258 if (ED_mask_selected_minmax(C, r_min, r_max, false)) {
259 has_select = true;
260 }
261 break;
262 }
263 default:
264 break;
265 }
266 }
267 else if (area->spacetype == SPACE_SEQ) {
268 Scene *scene = CTX_data_scene(C);
269 Editing *ed = seq::editing_get(scene);
272 VectorSet strips = seq::query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
273 strips.remove_if([&](Strip *strip) { return (strip->flag & SELECT) == 0; });
274 int selected_strips = strips.size();
275 if (selected_strips > 0) {
276 has_select = true;
278 scene, strips, selected_strips != 1);
279 copy_v2_v2(r_min, box.min);
280 copy_v2_v2(r_max, box.max);
281 }
282 if (selected_strips > 1) {
283 /* Don't draw the cage as transforming multiple strips isn't currently very useful as it
284 * doesn't behave as one would expect.
285 *
286 * This is because our current transform system doesn't support shearing which would make the
287 * scaling transforms of the bounding box behave weirdly.
288 * In addition to this, the rotation of the bounding box can not currently be hooked up
289 * properly to read the result from the transform system (when transforming multiple strips).
290 */
291 const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
292 if (pivot_point == V3D_AROUND_CURSOR) {
293 SpaceSeq *sseq = static_cast<SpaceSeq *>(area->spacedata.first);
294 const float2 cursor_pixel = seq::image_preview_unit_to_px(scene, sseq->cursor);
295 copy_v2_v2(r_center, cursor_pixel);
296 }
297 else {
298 mid_v2_v2v2(r_center, r_min, r_max);
299 }
300 zero_v2(r_min);
301 zero_v2(r_max);
302 return has_select;
303 }
304 }
305
306 if (has_select == false) {
307 zero_v2(r_min);
308 zero_v2(r_max);
309 }
310
311 mid_v2_v2v2(r_center, r_min, r_max);
312 return has_select;
313}
314
316{
317 ScrArea *area = CTX_wm_area(C);
318 if (area->spacetype != SPACE_SEQ) {
319 return V3D_ORIENT_GLOBAL;
320 }
321
322 Scene *scene = CTX_data_scene(C);
323 Editing *ed = seq::editing_get(scene);
326 VectorSet strips = seq::query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
327 strips.remove_if([&](Strip *strip) { return (strip->flag & SELECT) == 0; });
328
329 bool use_local_orient = strips.size() == 1;
330
331 if (use_local_orient) {
332 return V3D_ORIENT_LOCAL;
333 }
334 return V3D_ORIENT_GLOBAL;
335}
336
337static float gizmo2d_calc_rotation(const bContext *C)
338{
339 ScrArea *area = CTX_wm_area(C);
340 if (area->spacetype != SPACE_SEQ) {
341 return 0.0f;
342 }
343
344 Scene *scene = CTX_data_scene(C);
345 Editing *ed = seq::editing_get(scene);
348 VectorSet strips = seq::query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
349 strips.remove_if([&](Strip *strip) { return (strip->flag & SELECT) == 0; });
350
351 if (strips.size() == 1) {
352 /* Only return the strip rotation if only one is selected. */
353 for (Strip *strip : strips) {
356 return transform->rotation * mirror[0] * mirror[1];
357 }
358 }
359
360 return 0.0f;
361}
362
363static bool seq_get_strip_pivot_median(const Scene *scene, float r_pivot[2])
364{
365 zero_v2(r_pivot);
366
367 Editing *ed = seq::editing_get(scene);
370 VectorSet strips = seq::query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
371 strips.remove_if([&](Strip *strip) { return (strip->flag & SELECT) == 0; });
372 bool has_select = !strips.is_empty();
373
374 if (has_select) {
375 for (Strip *strip : strips) {
377 add_v2_v2(r_pivot, origin);
378 }
379 mul_v2_fl(r_pivot, 1.0f / strips.size());
380 }
381
382 return has_select;
383}
384
385static bool gizmo2d_calc_transform_pivot(const bContext *C, float r_pivot[2])
386{
387 ScrArea *area = CTX_wm_area(C);
388 Scene *scene = CTX_data_scene(C);
389 bool has_select = false;
390
391 if (area->spacetype == SPACE_IMAGE) {
392 const SpaceImage *sima = static_cast<const SpaceImage *>(area->spacedata.first);
393 ViewLayer *view_layer = CTX_data_view_layer(C);
394 switch (sima->mode) {
395 case SI_MODE_UV:
397 sima, scene, view_layer, r_pivot, sima->around, &has_select);
398 break;
399 case SI_MODE_MASK:
400 ED_mask_center_from_pivot_ex(C, area, r_pivot, sima->around, &has_select);
401 break;
402 default:
403 break;
404 }
405 }
406 else if (area->spacetype == SPACE_SEQ) {
407 SpaceSeq *sseq = static_cast<SpaceSeq *>(area->spacedata.first);
408 const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
409
410 if (pivot_point == V3D_AROUND_CURSOR) {
411 const float2 cursor_pixel = seq::image_preview_unit_to_px(scene, sseq->cursor);
412 copy_v2_v2(r_pivot, cursor_pixel);
413
414 Editing *ed = seq::editing_get(scene);
417 VectorSet strips = seq::query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
418 strips.remove_if([&](Strip *strip) { return (strip->flag & SELECT) == 0; });
419 has_select = !strips.is_empty();
420 }
421 else if (pivot_point == V3D_AROUND_CENTER_BOUNDS) {
422 has_select = gizmo2d_calc_bounds(C, r_pivot, nullptr, nullptr);
423 }
424 else {
425 has_select = seq_get_strip_pivot_median(scene, r_pivot);
426 }
427 }
428 else {
429 BLI_assert_msg(0, "Unhandled space type!");
430 }
431 return has_select;
432}
433
437BLI_INLINE void gizmo2d_origin_to_region(ARegion *region, float *r_origin)
438{
439 UI_view2d_view_to_region_fl(&region->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]);
440}
441
446 wmGizmo *widget,
447 const wmEvent * /*event*/,
448 eWM_GizmoFlagTweak /*tweak_flag*/)
449{
450 ARegion *region = CTX_wm_region(C);
451 float origin[3];
452
454 gizmo2d_origin_to_region(region, origin);
455 WM_gizmo_set_matrix_location(widget, origin);
456
458
460}
461
462static void gizmo2d_xform_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
463{
464 wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
465 GizmoGroup2D *ggd = gizmogroup2d_init(gzgroup);
466 gzgroup->customdata = ggd;
467
468 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
469 wmGizmo *gz = ggd->translate_xy[i];
470
471 /* Custom handler! */
473
474 if (i < 2) {
475 float color[4], color_hi[4];
476 gizmo2d_get_axis_color(i, color, color_hi);
477
478 /* Set up widget data. */
479 RNA_float_set(gz->ptr, "length", 0.8f);
480 float axis[3] = {0.0f};
481 axis[i] = 1.0f;
483
484 float offset[3] = {0, 0, 0};
485 offset[2] = 0.18f;
488
491 WM_gizmo_set_color_highlight(gz, color_hi);
492
493 WM_gizmo_set_scale(gz, 1.0f);
494 }
495 else {
496 float color[4], color_hi[4];
498 copy_v4_v4(color_hi, color);
499 color[3] *= 0.6f;
500
501 PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
502 RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
503
504 RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
505 /* Make the center low alpha. */
506 WM_gizmo_set_line_width(gz, 2.0f);
507 RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
509 WM_gizmo_set_color_highlight(gz, color_hi);
510
511 WM_gizmo_set_scale(gz, 0.2f);
512 }
513
514 /* Assign operator. */
515 PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_translate, nullptr);
516 if (i < 2) {
517 bool constraint[3] = {false};
518 constraint[i] = true;
519 if (RNA_struct_find_property(ptr, "constraint_axis")) {
520 RNA_boolean_set_array(ptr, "constraint_axis", constraint);
521 }
522 }
523
524 RNA_boolean_set(ptr, "release_confirm", true);
525 }
526
527 {
528 wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
529 wmOperatorType *ot_rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true);
531
532 /* Assign operator. */
533 ptr = WM_gizmo_operator_set(ggd->cage, 0, ot_translate, nullptr);
534 RNA_boolean_set(ptr, "release_confirm", true);
535
536 const bool constraint_x[3] = {true, false, false};
537 const bool constraint_y[3] = {false, true, false};
538
540 PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
541 PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
542 RNA_property_boolean_set(ptr, prop_release_confirm, true);
543 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
545 RNA_property_boolean_set(ptr, prop_release_confirm, true);
546 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
548 RNA_property_boolean_set(ptr, prop_release_confirm, true);
549 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
551 RNA_property_boolean_set(ptr, prop_release_confirm, true);
552 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
553
555 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, nullptr);
556 RNA_property_boolean_set(ptr, prop_release_confirm, true);
558 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y, ot_resize, nullptr);
559 RNA_property_boolean_set(ptr, prop_release_confirm, true);
561 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y, ot_resize, nullptr);
562 RNA_property_boolean_set(ptr, prop_release_confirm, true);
564 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y, ot_resize, nullptr);
565 RNA_property_boolean_set(ptr, prop_release_confirm, true);
566 ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE, ot_rotate, nullptr);
567 RNA_property_boolean_set(ptr, prop_release_confirm, true);
568 }
569}
570
571static void rotate_around_center_v2(float point[2], const float center[2], const float angle)
572{
573 float tmp[2];
574
575 sub_v2_v2v2(tmp, point, center);
576 rotate_v2_v2fl(point, tmp, angle);
577 add_v2_v2(point, center);
578}
579
580static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
581{
582 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(gzgroup->customdata);
583 bool has_select;
584 if (ggd->no_cage) {
585 has_select = gizmo2d_calc_transform_pivot(C, ggd->origin);
586 }
587 else {
588 has_select = gizmo2d_calc_bounds(C, ggd->origin, ggd->min, ggd->max);
590 }
591
592 bool show_cage = !ggd->no_cage && !equals_v2v2(ggd->min, ggd->max);
593
594 if (has_select == false) {
595 /* Nothing selected. Disable gizmo drawing and return. */
596 ggd->cage->flag |= WM_GIZMO_HIDDEN;
597 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
599 }
600 return;
601 }
602
603 if (!show_cage) {
604 /* Disable cage gizmo drawing and return. */
605 ggd->cage->flag |= WM_GIZMO_HIDDEN;
606 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
608 }
609 return;
610 }
611
612 /* We will show the cage gizmo! Setup all necessary data. */
613 ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
614 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
616 }
617}
618
620{
621 ARegion *region = CTX_wm_region(C);
622 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(gzgroup->customdata);
623 float origin[3] = {UNPACK2(ggd->origin), 0.0f};
624
625 gizmo2d_origin_to_region(region, origin);
626
627 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
628 wmGizmo *gz = ggd->translate_xy[i];
630 }
631
633 /* Define the bounding box of the gizmo in the offset transform matrix. */
635 const float min_gizmo_pixel_size = 0.001f; /* Draw Gizmo larger than this many pixels. */
636 const float min_scale_axis_x = min_gizmo_pixel_size / ggd->cage->matrix_space[0][0];
637 const float min_scale_axis_y = min_gizmo_pixel_size / ggd->cage->matrix_space[1][1];
638 ggd->cage->matrix_offset[0][0] = max_ff(min_scale_axis_x, ggd->max[0] - ggd->min[0]);
639 ggd->cage->matrix_offset[1][1] = max_ff(min_scale_axis_y, ggd->max[1] - ggd->min[1]);
640
641 ScrArea *area = CTX_wm_area(C);
642
643 if (area->spacetype == SPACE_SEQ) {
644 Scene *scene = CTX_data_scene(C);
645 seq_get_strip_pivot_median(scene, origin);
646
647 float matrix_rotate[4][4];
648 unit_m4(matrix_rotate);
649 copy_v3_v3(matrix_rotate[3], origin);
650 rotate_m4(matrix_rotate, 'Z', ggd->rotation);
652 mul_m4_m4m4(ggd->cage->matrix_basis, matrix_rotate, ggd->cage->matrix_basis);
653
654 float mid[2];
655 sub_v2_v2v2(mid, origin, ggd->origin);
656 mul_v2_fl(mid, -1.0f);
657 copy_v2_v2(ggd->cage->matrix_offset[3], mid);
658 }
659 else {
660 const float origin_aa[3] = {UNPACK2(ggd->origin), 0.0f};
662 }
663}
664
666 wmGizmoGroup *gzgroup,
667 wmGizmo * /*gz*/,
668 const wmEvent * /*event*/)
669{
670 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(gzgroup->customdata);
671 wmGizmoOpElem *gzop;
672 const float *mid = ggd->origin;
673 const float *min = ggd->min;
674 const float *max = ggd->max;
675
676 /* Define the different transform center points that will be used when grabbing the corners or
677 * rotating with the gizmo.
678 *
679 * The coordinates are referred to as their cardinal directions:
680 * N
681 * o
682 *NW | NE
683 * x-----------x
684 * | |
685 *W| C |E
686 * | |
687 * x-----------x
688 *SW S SE
689 */
690 float n[3] = {mid[0], max[1], 0.0f};
691 float w[3] = {min[0], mid[1], 0.0f};
692 float e[3] = {max[0], mid[1], 0.0f};
693 float s[3] = {mid[0], min[1], 0.0f};
694
695 float nw[3] = {min[0], max[1], 0.0f};
696 float ne[3] = {max[0], max[1], 0.0f};
697 float sw[3] = {min[0], min[1], 0.0f};
698 float se[3] = {max[0], min[1], 0.0f};
699
700 float c[3] = {mid[0], mid[1], 0.0f};
701
702 float orient_matrix[3][3];
703 unit_m3(orient_matrix);
704
705 ScrArea *area = CTX_wm_area(C);
706
707 if (ggd->rotation != 0.0f && area->spacetype == SPACE_SEQ) {
708 float origin[3];
709 Scene *scene = CTX_data_scene(C);
710 seq_get_strip_pivot_median(scene, origin);
711 /* We need to rotate the cardinal points so they align with the rotated bounding box. */
712
713 rotate_around_center_v2(n, origin, ggd->rotation);
714 rotate_around_center_v2(w, origin, ggd->rotation);
715 rotate_around_center_v2(e, origin, ggd->rotation);
716 rotate_around_center_v2(s, origin, ggd->rotation);
717
718 rotate_around_center_v2(nw, origin, ggd->rotation);
719 rotate_around_center_v2(ne, origin, ggd->rotation);
720 rotate_around_center_v2(sw, origin, ggd->rotation);
721 rotate_around_center_v2(se, origin, ggd->rotation);
722
723 rotate_around_center_v2(c, origin, ggd->rotation);
724
725 axis_angle_to_mat3_single(orient_matrix, 'Z', ggd->rotation);
726 }
727
728 int orient_type = gizmo2d_calc_transform_orientation(C);
729
731 PropertyRNA *prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
732 PropertyRNA *prop_mouse_dir = RNA_struct_find_property(&gzop->ptr, "mouse_dir_constraint");
733 RNA_property_float_set_array(&gzop->ptr, prop_center_override, e);
734 RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[0]);
735 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
737 RNA_property_float_set_array(&gzop->ptr, prop_center_override, w);
738 RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[0]);
739 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
741 RNA_property_float_set_array(&gzop->ptr, prop_center_override, n);
742 RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[1]);
743 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
745 RNA_property_float_set_array(&gzop->ptr, prop_center_override, s);
746 RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[1]);
747 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
748
750 RNA_property_float_set_array(&gzop->ptr, prop_center_override, ne);
752 RNA_property_float_set_array(&gzop->ptr, prop_center_override, se);
754 RNA_property_float_set_array(&gzop->ptr, prop_center_override, nw);
756 RNA_property_float_set_array(&gzop->ptr, prop_center_override, sw);
757
759 RNA_property_float_set_array(&gzop->ptr, prop_center_override, c);
760}
761
771
773{
774 gizmo2d_xform_setup(C, gzgroup);
775 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(gzgroup->customdata);
776 ggd->no_cage = true;
777}
778
780 wmGizmoGroup *gzgroup,
781 wmMsgBus *mbus)
782{
783 bScreen *screen = CTX_wm_screen(C);
784 ScrArea *area = CTX_wm_area(C);
785 ARegion *region = CTX_wm_region(C);
786 gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
787}
788
795
797
798/* -------------------------------------------------------------------- */
806
812
814{
815 const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
816 const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
817
819
820 ggd->gizmo_xy[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
821 ggd->gizmo_xy[1] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
822 ggd->gizmo_xy[2] = WM_gizmo_new_ptr(gzt_button, gzgroup, nullptr);
823
824 return ggd;
825}
826
827static void gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
828{
829 GizmoGroup_Resize2D *ggd = static_cast<GizmoGroup_Resize2D *>(gzgroup->customdata);
830 float origin[3];
831 const bool has_select = gizmo2d_calc_transform_pivot(C, origin);
832
833 if (has_select == false) {
834 for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
835 ggd->gizmo_xy[i]->flag |= WM_GIZMO_HIDDEN;
836 }
837 }
838 else {
839 for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
841 }
842 copy_v2_v2(ggd->origin, origin);
844 }
845}
846
848{
849 ARegion *region = CTX_wm_region(C);
850 GizmoGroup_Resize2D *ggd = static_cast<GizmoGroup_Resize2D *>(gzgroup->customdata);
851 float origin[3] = {UNPACK2(ggd->origin), 0.0f};
852
853 gizmo2d_origin_to_region(region, origin);
854
855 for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
856 wmGizmo *gz = ggd->gizmo_xy[i];
858
859 if (i < 2) {
860 float axis[3] = {0.0f}, rotated_axis[3];
861 axis[i] = 1.0f;
862 rotate_v3_v3v3fl(rotated_axis, axis, float3{0, 0, 1}, ggd->rotation);
864 }
865 }
866}
867
868static void gizmo2d_resize_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
869{
870
871 wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
873 gzgroup->customdata = ggd;
874
875 for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
876 wmGizmo *gz = ggd->gizmo_xy[i];
877
878 /* Custom handler! */
880
881 if (i < 2) {
882 float color[4], color_hi[4];
883 gizmo2d_get_axis_color(i, color, color_hi);
884
885 /* Set up widget data. */
886 RNA_float_set(gz->ptr, "length", 1.0f);
887 RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
888
891 WM_gizmo_set_color_highlight(gz, color_hi);
892
893 WM_gizmo_set_scale(gz, 1.0f);
894 }
895 else {
896 float color[4], color_hi[4];
898 copy_v4_v4(color_hi, color);
899 color[3] *= 0.6f;
900
901 PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
902 RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
903
904 RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
905 /* Make the center low alpha. */
906 WM_gizmo_set_line_width(gz, 2.0f);
907 RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
909 WM_gizmo_set_color_highlight(gz, color_hi);
910
911 WM_gizmo_set_scale(gz, 1.2f);
912 }
913
914 /* Assign operator. */
915 PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_resize, nullptr);
916 if (i < 2) {
917 bool constraint[3] = {false};
918 constraint[i] = true;
919 if (RNA_struct_find_property(ptr, "constraint_axis")) {
920 RNA_boolean_set_array(ptr, "constraint_axis", constraint);
921 }
922 }
923 RNA_boolean_set(ptr, "release_confirm", true);
924 }
925}
926
928 wmGizmoGroup * /*gzgroup*/,
929 wmGizmo *gz,
930 const wmEvent * /*event*/)
931{
932 wmGizmoOpElem *gzop;
933 int orient_type = gizmo2d_calc_transform_orientation(C);
934
935 gzop = WM_gizmo_operator_get(gz, 0);
936 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
937}
938
940 wmGizmoGroup *gzgroup,
941 wmMsgBus *mbus)
942{
943 bScreen *screen = CTX_wm_screen(C);
944 ScrArea *area = CTX_wm_area(C);
945 ARegion *region = CTX_wm_region(C);
946 gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
947}
948
959
961
962/* -------------------------------------------------------------------- */
970
975
977{
978 const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
979
981
982 ggd->gizmo = WM_gizmo_new_ptr(gzt_button, gzgroup, nullptr);
983
984 return ggd;
985}
986
987static void gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
988{
989 GizmoGroup_Rotate2D *ggd = static_cast<GizmoGroup_Rotate2D *>(gzgroup->customdata);
990 float origin[3];
991 const bool has_select = gizmo2d_calc_transform_pivot(C, origin);
992
993 if (has_select == false) {
994 ggd->gizmo->flag |= WM_GIZMO_HIDDEN;
995 }
996 else {
997 ggd->gizmo->flag &= ~WM_GIZMO_HIDDEN;
998 copy_v2_v2(ggd->origin, origin);
999 }
1000}
1001
1003{
1004 ARegion *region = CTX_wm_region(C);
1005 GizmoGroup_Rotate2D *ggd = static_cast<GizmoGroup_Rotate2D *>(gzgroup->customdata);
1006 float origin[3] = {UNPACK2(ggd->origin), 0.0f};
1007
1008 gizmo2d_origin_to_region(region, origin);
1009
1010 wmGizmo *gz = ggd->gizmo;
1011 WM_gizmo_set_matrix_location(gz, origin);
1012}
1013
1014static void gizmo2d_rotate_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
1015{
1016
1017 wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_rotate", true);
1019 gzgroup->customdata = ggd;
1020
1021 /* Other setup functions iterate over axis. */
1022 {
1023 wmGizmo *gz = ggd->gizmo;
1024
1025 /* Custom handler! */
1027 WM_gizmo_set_scale(gz, 1.2f);
1028
1029 {
1030 float color[4];
1032
1033 PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
1034 RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
1035
1036 RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
1037 /* Make the center low alpha. */
1038 WM_gizmo_set_line_width(gz, 2.0f);
1039 RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
1042 }
1043
1044 /* Assign operator. */
1045 PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_resize, nullptr);
1046 RNA_boolean_set(ptr, "release_confirm", true);
1047 }
1048}
1049
1051 wmGizmoGroup *gzgroup,
1052 wmMsgBus *mbus)
1053{
1054 bScreen *screen = CTX_wm_screen(C);
1055 ScrArea *area = CTX_wm_area(C);
1056 ARegion *region = CTX_wm_region(C);
1057 gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
1058}
1059
1069
1071
1072} // namespace blender::ed::transform
bScreen * CTX_wm_screen(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Object * CTX_data_edit_object(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
blender::Vector< Object * > BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(const Scene *scene, ViewLayer *view_layer, const View3D *v3d)
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define BLI_INLINE
MINLINE float max_ff(float a, float b)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
void unit_m3(float m[3][3])
void rotate_m4(float mat[4][4], char axis, float angle)
void unit_m4(float m[4][4])
void axis_angle_to_mat3_single(float R[3][3], char axis, float angle)
MINLINE void copy_v4_v4(float r[4], const float a[4])
void rotate_v3_v3v3fl(float r[3], const float p[3], const float axis[3], float angle)
MINLINE void mul_v2_fl(float r[2], float f)
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v2_v2(float r[2], const float a[2])
MINLINE bool equals_v2v2(const float v1[2], const float v2[2]) ATTR_WARN_UNUSED_RESULT
void mid_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
MINLINE void zero_v2(float r[2])
void rotate_v2_v2fl(float r[2], const float p[2], float angle)
#define UNPACK2(a)
#define ARRAY_SIZE(arr)
Object is a sort of wrapper for general info.
@ SPACE_SEQ
@ SPACE_IMAGE
@ SEQ_DRAW_IMG_IMBUF
@ SI_MODE_MASK
@ SI_MODE_UV
@ SEQ_GIZMO_HIDE
@ SEQ_GIZMO_HIDE_TOOL
@ USER_GIZMO_DRAW
@ V3D_AROUND_CENTER_BOUNDS
@ V3D_AROUND_CURSOR
@ V3D_ORIENT_GLOBAL
@ V3D_ORIENT_LOCAL
@ OPERATOR_RUNNING_MODAL
@ ED_GIZMO_CAGE_DRAW_FLAG_CORNER_HANDLES
@ ED_GIZMO_CAGE_DRAW_FLAG_XFORM_CENTER_HANDLE
@ ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y
@ ED_GIZMO_CAGE2D_PART_ROTATE
@ ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y
@ ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y
@ ED_GIZMO_CAGE2D_PART_SCALE_MIN_X
@ ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y
@ ED_GIZMO_CAGE2D_PART_SCALE_MAX_X
@ ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y
@ ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y
@ ED_GIZMO_BUTTON_SHOW_BACKDROP
@ ED_GIZMO_CAGE_XFORM_FLAG_SCALE
@ ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE
@ ED_GIZMO_CAGE_XFORM_FLAG_ROTATE
@ ED_GIZMO_ARROW_STYLE_BOX
bool ED_gizmo_poll_or_unlink_delayed_from_tool(const bContext *C, wmGizmoGroupType *gzgt)
bool ED_space_image_show_uvedit(const SpaceImage *sima, Object *obedit)
bool ED_space_image_show_mask(const SpaceImage *sima)
void ED_mask_center_from_pivot_ex(const bContext *C, ScrArea *area, float r_center[2], char mode, bool *r_has_select)
bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2], bool handles_as_control_point)
void ED_region_tag_redraw_editor_overlays(ARegion *region)
Definition area.cc:654
bool ED_uvedit_minmax_multi(const Scene *scene, blender::Span< Object * > objects_edit, float r_min[2], float r_max[2])
bool ED_uvedit_center_from_pivot_ex(const SpaceImage *sima, Scene *scene, ViewLayer *view_layer, float r_center[2], char mode, bool *r_has_select)
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
Definition IK_Math.h:117
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ TH_GIZMO_VIEW_ALIGN
@ TH_AXIS_Y
@ TH_AXIS_X
void UI_GetThemeColor4fv(int colorid, float col[4])
void UI_view2d_view_to_region_m4(const View2D *v2d, float matrix[4][4]) ATTR_NONNULL()
Definition view2d.cc:1808
void UI_view2d_view_to_region_fl(const View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL()
Definition view2d.cc:1739
eWM_GizmoFlagTweak
Gizmo tweak flag. Bit-flag passed to gizmo while tweaking.
@ WM_GIZMO_HIDDEN
@ WM_GIZMO_DRAW_OFFSET_SCALE
#define U
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
int64_t size() const
int64_t remove_if(Predicate &&predicate)
#define SELECT
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
#define G(x, y, z)
static bool gizmo2d_generic_poll(const bContext *C, wmGizmoGroupType *gzgt)
void ED_widgetgroup_gizmo2d_resize_callbacks_set(wmGizmoGroupType *gzgt)
void ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType *gzgt)
static void gizmo2d_xform_invoke_prepare(const bContext *C, wmGizmoGroup *gzgroup, wmGizmo *, const wmEvent *)
static float gizmo2d_calc_rotation(const bContext *C)
static void gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static bool gizmo2d_calc_transform_pivot(const bContext *C, float r_pivot[2])
static GizmoGroup_Rotate2D * gizmogroup2d_rotate_init(wmGizmoGroup *gzgroup)
static int gizmo2d_calc_transform_orientation(const bContext *C)
BLI_INLINE void gizmo2d_origin_to_region(ARegion *region, float *r_origin)
static void gizmo2d_resize_invoke_prepare(const bContext *C, wmGizmoGroup *, wmGizmo *gz, const wmEvent *)
static void gizmo2d_resize_setup(const bContext *, wmGizmoGroup *gzgroup)
static void gizmo2d_xform_setup(const bContext *, wmGizmoGroup *gzgroup)
static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void rotate_around_center_v2(float point[2], const float center[2], const float angle)
static GizmoGroup2D * gizmogroup2d_init(wmGizmoGroup *gzgroup)
static void gizmo2d_xform_no_cage_message_subscribe(const bContext *C, wmGizmoGroup *gzgroup, wmMsgBus *mbus)
static void gizmo2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi)
static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo2d_rotate_message_subscribe(const bContext *C, wmGizmoGroup *gzgroup, wmMsgBus *mbus)
static void gizmo2d_resize_message_subscribe(const bContext *C, wmGizmoGroup *gzgroup, wmMsgBus *mbus)
void ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set(wmGizmoGroupType *gzgt)
static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max)
static wmOperatorStatus gizmo2d_modal(bContext *C, wmGizmo *widget, const wmEvent *, eWM_GizmoFlagTweak)
static void gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo2d_xform_setup_no_cage(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo2d_pivot_point_message_subscribe(wmGizmoGroup *gzgroup, wmMsgBus *mbus, bScreen *screen, ScrArea *area, ARegion *region)
static void gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static bool seq_get_strip_pivot_median(const Scene *scene, float r_pivot[2])
static void gizmo2d_rotate_setup(const bContext *, wmGizmoGroup *gzgroup)
static GizmoGroup_Resize2D * gizmogroup2d_resize_init(wmGizmoGroup *gzgroup)
void ED_widgetgroup_gizmo2d_rotate_callbacks_set(wmGizmoGroupType *gzgt)
ListBase * channels_displayed_get(const Editing *ed)
Definition channels.cc:28
Bounds< float2 > image_transform_bounding_box_from_collection(Scene *scene, blender::Span< Strip * > strips, bool apply_rotation)
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:286
float2 image_transform_mirror_factor_get(const Strip *strip)
float2 image_transform_origin_offset_pixelspace_get(const Scene *scene, const Strip *strip)
VectorSet< Strip * > query_rendered_strips(const Scene *scene, ListBase *channels, ListBase *seqbase, const int timeline_frame, const int displayed_channel)
Definition iterator.cc:228
ListBase * active_seqbase_get(const Editing *ed)
Definition sequencer.cc:433
float2 image_preview_unit_to_px(const Scene *scene, const float2 co_src)
VecBase< float, 2 > float2
VecBase< float, 3 > float3
void RNA_boolean_set_array(PointerRNA *ptr, const char *name, const bool *values)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
void RNA_property_enum_set(PointerRNA *ptr, PropertyRNA *prop, int value)
void RNA_property_boolean_set(PointerRNA *ptr, PropertyRNA *prop, bool value)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
void RNA_property_boolean_set_array(PointerRNA *ptr, PropertyRNA *prop, const bool *values)
void * first
struct ToolSettings * toolsettings
struct RenderData r
ListBase spacedata
float cursor[2]
StripTransform * transform
StripData * data
struct SequencerToolSettings * sequencer_tool_settings
wmGizmoGroupFnSetupKeymap setup_keymap
wmGizmoGroupFnMsgBusSubscribe message_subscribe
wmGizmoGroupFnRefresh refresh
wmGizmoGroupFnInit setup
wmGizmoGroupFnInvokePrepare invoke_prepare
wmGizmoGroupFnPoll poll
wmGizmoGroupFnDrawPrepare draw_prepare
wmGizmoMap * parent_gzmap
float matrix_basis[4][4]
float matrix_offset[4][4]
PointerRNA * ptr
float matrix_space[4][4]
eWM_GizmoFlag flag
i
Definition text_draw.cc:230
#define GIZMO_AXIS_LINE_WIDTH
PointerRNA * ptr
Definition wm_files.cc:4238
void WM_gizmo_set_matrix_offset_location(wmGizmo *gz, const float offset[3])
Definition wm_gizmo.cc:302
wmGizmoOpElem * WM_gizmo_operator_get(wmGizmo *gz, int part_index)
Definition wm_gizmo.cc:195
void WM_gizmo_set_color_highlight(wmGizmo *gz, const float color_hi[4])
Definition wm_gizmo.cc:340
void WM_gizmo_set_line_width(wmGizmo *gz, const float line_width)
Definition wm_gizmo.cc:322
void WM_gizmo_set_fn_custom_modal(wmGizmo *gz, wmGizmoFnModal fn)
Definition wm_gizmo.cc:351
wmGizmo * WM_gizmo_new_ptr(const wmGizmoType *gzt, wmGizmoGroup *gzgroup, PointerRNA *properties)
Definition wm_gizmo.cc:85
void WM_gizmo_set_scale(wmGizmo *gz, const float scale)
Definition wm_gizmo.cc:317
void WM_gizmo_set_matrix_location(wmGizmo *gz, const float origin[3])
Definition wm_gizmo.cc:287
void WM_gizmo_set_matrix_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3])
Definition wm_gizmo.cc:277
PointerRNA * WM_gizmo_operator_set(wmGizmo *gz, int part_index, wmOperatorType *ot, IDProperty *properties)
Definition wm_gizmo.cc:203
void WM_gizmo_set_color(wmGizmo *gz, const float color[4])
Definition wm_gizmo.cc:331
wmKeyMap * WM_gizmogroup_setup_keymap_generic_maybe_drag(const wmGizmoGroupType *, wmKeyConfig *kc)
void WM_gizmo_do_msg_notify_tag_refresh(bContext *, wmMsgSubscribeKey *, wmMsgSubscribeValue *msg_val)
const wmGizmoType * WM_gizmotype_find(const StringRef idname, bool quiet)
void WM_msg_subscribe_rna(wmMsgBus *mbus, PointerRNA *ptr, const PropertyRNA *prop, const wmMsgSubscribeValue *msg_val_params, const char *id_repr)
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)