Blender V4.3
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
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_screen.hh"
43#include "ED_uvedit.hh"
44
45#include "SEQ_channels.hh"
46#include "SEQ_iterator.hh"
47#include "SEQ_sequencer.hh"
48#include "SEQ_transform.hh"
49
50#include "transform.hh"
51#include "transform_gizmo.hh"
52
53using blender::Vector;
54
55/* -------------------------------------------------------------------- */
60{
62 return false;
63 }
64
65 if ((U.gizmo_flag & USER_GIZMO_DRAW) == 0) {
66 return false;
67 }
68
69 if (G.moving) {
70 return false;
71 }
72
73 ScrArea *area = CTX_wm_area(C);
74 if (area == nullptr) {
75 return false;
76 }
77
78 /* NOTE: below this is assumed to be a tool gizmo.
79 * If there are cases that need to check other flags - this function could be split. */
80 switch (area->spacetype) {
81 case SPACE_IMAGE: {
82 const SpaceImage *sima = static_cast<const SpaceImage *>(area->spacedata.first);
83 Object *obedit = CTX_data_edit_object(C);
84 if (!ED_space_image_show_uvedit(sima, obedit)) {
85 return false;
86 }
87 break;
88 }
89 case SPACE_SEQ: {
90 const SpaceSeq *sseq = static_cast<const SpaceSeq *>(area->spacedata.first);
92 return false;
93 }
94 if (sseq->mainb != SEQ_DRAW_IMG_IMBUF) {
95 return false;
96 }
97 Scene *scene = CTX_data_scene(C);
98 Editing *ed = SEQ_editing_get(scene);
99 if (ed == nullptr) {
100 return false;
101 }
102 break;
103 }
104 }
105
106 return true;
107}
108
110 wmMsgBus *mbus, /* Additional args. */
111 bScreen *screen,
112 ScrArea *area,
113 ARegion *region)
114{
115 wmMsgSubscribeValue msg_sub_value_gz_tag_refresh{};
116 msg_sub_value_gz_tag_refresh.owner = region;
117 msg_sub_value_gz_tag_refresh.user_data = gzgroup->parent_gzmap;
118 msg_sub_value_gz_tag_refresh.notify = WM_gizmo_do_msg_notify_tag_refresh;
119
120 switch (area->spacetype) {
121 case SPACE_IMAGE: {
122 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
123 PointerRNA ptr = RNA_pointer_create(&screen->id, &RNA_SpaceImageEditor, sima);
124 {
125 const PropertyRNA *props[] = {
126 &rna_SpaceImageEditor_pivot_point,
127 (sima->around == V3D_AROUND_CURSOR) ? &rna_SpaceImageEditor_cursor_location : nullptr,
128 };
129 for (int i = 0; i < ARRAY_SIZE(props); i++) {
130 if (props[i] == nullptr) {
131 continue;
132 }
133 WM_msg_subscribe_rna(mbus, &ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
134 }
135 }
136 break;
137 }
138 }
139}
140
143/* -------------------------------------------------------------------- */
153/* Axes as index. */
154enum {
157
159};
160
164
165 /* Current origin in view space, used to update widget origin for possible view changes. */
166 float origin[2];
167 float min[2];
168 float max[2];
169 float rotation;
170
172};
173
174/* **************** Utilities **************** */
175
176static void gizmo2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi)
177{
178 const float alpha = 0.6f;
179 const float alpha_hi = 1.0f;
180 int col_id;
181
182 switch (axis_idx) {
184 col_id = TH_AXIS_X;
185 break;
187 col_id = TH_AXIS_Y;
188 break;
189 default:
190 BLI_assert(0);
191 col_id = TH_AXIS_Y;
192 break;
193 }
194
195 UI_GetThemeColor4fv(col_id, r_col);
196
197 copy_v4_v4(r_col_hi, r_col);
198 r_col[3] *= alpha;
199 r_col_hi[3] *= alpha_hi;
200}
201
203{
204 const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
205 const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_2d", true);
206 const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
207
208 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(MEM_callocN(sizeof(GizmoGroup2D), __func__));
209
210 ggd->translate_xy[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
211 ggd->translate_xy[1] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
212 ggd->translate_xy[2] = WM_gizmo_new_ptr(gzt_button, gzgroup, nullptr);
213 ggd->cage = WM_gizmo_new_ptr(gzt_cage, gzgroup, nullptr);
214
215 RNA_enum_set(ggd->cage->ptr,
216 "transform",
219
220 return ggd;
221}
222
226static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max)
227{
228 float min_buf[2], max_buf[2];
229 if (r_min == nullptr) {
230 r_min = min_buf;
231 }
232 if (r_max == nullptr) {
233 r_max = max_buf;
234 }
235
236 ScrArea *area = CTX_wm_area(C);
237 bool has_select = false;
238 if (area->spacetype == SPACE_IMAGE) {
239 Scene *scene = CTX_data_scene(C);
240 ViewLayer *view_layer = CTX_data_view_layer(C);
242 scene, view_layer, nullptr);
243 if (ED_uvedit_minmax_multi(scene, objects, r_min, r_max)) {
244 has_select = true;
245 }
246 }
247 else if (area->spacetype == SPACE_SEQ) {
248 Scene *scene = CTX_data_scene(C);
249 Editing *ed = SEQ_editing_get(scene);
250 ListBase *seqbase = SEQ_active_seqbase_get(ed);
251 ListBase *channels = SEQ_channels_displayed_get(ed);
253 scene, channels, seqbase, scene->r.cfra, 0);
254 strips.remove_if([&](Sequence *seq) { return (seq->flag & SELECT) == 0; });
255 int selected_strips = strips.size();
256 if (selected_strips > 0) {
257 has_select = true;
259 scene, strips, selected_strips != 1, r_min, r_max);
260 }
261 if (selected_strips > 1) {
262 /* Don't draw the cage as transforming multiple strips isn't currently very useful as it
263 * doesn't behave as one would expect.
264 *
265 * This is because our current transform system doesn't support shearing which would make the
266 * scaling transforms of the bounding box behave weirdly.
267 * In addition to this, the rotation of the bounding box can not currently be hooked up
268 * properly to read the result from the transform system (when transforming multiple strips).
269 */
270 const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
271 if (pivot_point == V3D_AROUND_CURSOR) {
272 SpaceSeq *sseq = static_cast<SpaceSeq *>(area->spacedata.first);
273 SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_center);
274 }
275 else {
276 mid_v2_v2v2(r_center, r_min, r_max);
277 }
278 zero_v2(r_min);
279 zero_v2(r_max);
280 return has_select;
281 }
282 }
283
284 if (has_select == false) {
285 zero_v2(r_min);
286 zero_v2(r_max);
287 }
288
289 mid_v2_v2v2(r_center, r_min, r_max);
290 return has_select;
291}
292
294{
295 ScrArea *area = CTX_wm_area(C);
296 if (area->spacetype != SPACE_SEQ) {
297 return V3D_ORIENT_GLOBAL;
298 }
299
300 Scene *scene = CTX_data_scene(C);
301 Editing *ed = SEQ_editing_get(scene);
302 ListBase *seqbase = SEQ_active_seqbase_get(ed);
303 ListBase *channels = SEQ_channels_displayed_get(ed);
305 scene, channels, seqbase, scene->r.cfra, 0);
306 strips.remove_if([&](Sequence *seq) { return (seq->flag & SELECT) == 0; });
307
308 bool use_local_orient = strips.size() == 1;
309
310 if (use_local_orient) {
311 return V3D_ORIENT_LOCAL;
312 }
313 return V3D_ORIENT_GLOBAL;
314}
315
316static float gizmo2d_calc_rotation(const bContext *C)
317{
318 ScrArea *area = CTX_wm_area(C);
319 if (area->spacetype != SPACE_SEQ) {
320 return 0.0f;
321 }
322
323 Scene *scene = CTX_data_scene(C);
324 Editing *ed = SEQ_editing_get(scene);
325 ListBase *seqbase = SEQ_active_seqbase_get(ed);
326 ListBase *channels = SEQ_channels_displayed_get(ed);
328 scene, channels, seqbase, scene->r.cfra, 0);
329 strips.remove_if([&](Sequence *seq) { return (seq->flag & SELECT) == 0; });
330
331 if (strips.size() == 1) {
332 /* Only return the strip rotation if only one is selected. */
333 for (Sequence *seq : strips) {
334 StripTransform *transform = seq->strip->transform;
335 float mirror[2];
337 return transform->rotation * mirror[0] * mirror[1];
338 }
339 }
340
341 return 0.0f;
342}
343
344static bool seq_get_strip_pivot_median(const Scene *scene, float r_pivot[2])
345{
346 zero_v2(r_pivot);
347
348 Editing *ed = SEQ_editing_get(scene);
349 ListBase *seqbase = SEQ_active_seqbase_get(ed);
350 ListBase *channels = SEQ_channels_displayed_get(ed);
352 scene, channels, seqbase, scene->r.cfra, 0);
353 strips.remove_if([&](Sequence *seq) { return (seq->flag & SELECT) == 0; });
354 bool has_select = !strips.is_empty();
355
356 if (has_select) {
357 for (Sequence *seq : strips) {
358 float origin[2];
360 add_v2_v2(r_pivot, origin);
361 }
362 mul_v2_fl(r_pivot, 1.0f / strips.size());
363 }
364
365 return has_select;
366}
367
368static bool gizmo2d_calc_transform_pivot(const bContext *C, float r_pivot[2])
369{
370 ScrArea *area = CTX_wm_area(C);
371 Scene *scene = CTX_data_scene(C);
372 bool has_select = false;
373
374 if (area->spacetype == SPACE_IMAGE) {
375 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
376 ViewLayer *view_layer = CTX_data_view_layer(C);
377 ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_pivot, sima->around, &has_select);
378 }
379 else if (area->spacetype == SPACE_SEQ) {
380 SpaceSeq *sseq = static_cast<SpaceSeq *>(area->spacedata.first);
381 const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
382
383 if (pivot_point == V3D_AROUND_CURSOR) {
384 SEQ_image_preview_unit_to_px(scene, sseq->cursor, r_pivot);
385
386 Editing *ed = SEQ_editing_get(scene);
387 ListBase *seqbase = SEQ_active_seqbase_get(ed);
388 ListBase *channels = SEQ_channels_displayed_get(ed);
390 scene, channels, seqbase, scene->r.cfra, 0);
391 strips.remove_if([&](Sequence *seq) { return (seq->flag & SELECT) == 0; });
392 has_select = !strips.is_empty();
393 }
394 else if (pivot_point == V3D_AROUND_CENTER_BOUNDS) {
395 has_select = gizmo2d_calc_bounds(C, r_pivot, nullptr, nullptr);
396 }
397 else {
398 has_select = seq_get_strip_pivot_median(scene, r_pivot);
399 }
400 }
401 else {
402 BLI_assert_msg(0, "Unhandled space type!");
403 }
404 return has_select;
405}
406
410BLI_INLINE void gizmo2d_origin_to_region(ARegion *region, float *r_origin)
411{
412 UI_view2d_view_to_region_fl(&region->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]);
413}
414
419 wmGizmo *widget,
420 const wmEvent * /*event*/,
421 eWM_GizmoFlagTweak /*tweak_flag*/)
422{
423 ARegion *region = CTX_wm_region(C);
424 float origin[3];
425
427 gizmo2d_origin_to_region(region, origin);
428 WM_gizmo_set_matrix_location(widget, origin);
429
431
433}
434
435static void gizmo2d_xform_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
436{
437 wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
438 GizmoGroup2D *ggd = gizmogroup2d_init(gzgroup);
439 gzgroup->customdata = ggd;
440
441 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
442 wmGizmo *gz = ggd->translate_xy[i];
443
444 /* Custom handler! */
446
447 if (i < 2) {
448 float color[4], color_hi[4];
449 gizmo2d_get_axis_color(i, color, color_hi);
450
451 /* Set up widget data. */
452 RNA_float_set(gz->ptr, "length", 0.8f);
453 float axis[3] = {0.0f};
454 axis[i] = 1.0f;
456
457 float offset[3] = {0, 0, 0};
458 offset[2] = 0.18f;
461
463 WM_gizmo_set_color(gz, color);
464 WM_gizmo_set_color_highlight(gz, color_hi);
465
466 WM_gizmo_set_scale(gz, 1.0f);
467 }
468 else {
469 float color[4], color_hi[4];
471 copy_v4_v4(color_hi, color);
472 color[3] *= 0.6f;
473
474 PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
475 RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
476
477 RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
478 /* Make the center low alpha. */
479 WM_gizmo_set_line_width(gz, 2.0f);
480 RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
481 WM_gizmo_set_color(gz, color);
482 WM_gizmo_set_color_highlight(gz, color_hi);
483
484 WM_gizmo_set_scale(gz, 0.2f);
485 }
486
487 /* Assign operator. */
488 PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_translate, nullptr);
489 if (i < 2) {
490 bool constraint[3] = {false};
491 constraint[i] = true;
492 if (RNA_struct_find_property(ptr, "constraint_axis")) {
493 RNA_boolean_set_array(ptr, "constraint_axis", constraint);
494 }
495 }
496
497 RNA_boolean_set(ptr, "release_confirm", true);
498 }
499
500 {
501 wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
502 wmOperatorType *ot_rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true);
504
505 /* Assign operator. */
506 ptr = WM_gizmo_operator_set(ggd->cage, 0, ot_translate, nullptr);
507 RNA_boolean_set(ptr, "release_confirm", true);
508
509 const bool constraint_x[3] = {true, false, false};
510 const bool constraint_y[3] = {false, true, false};
511
513 PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
514 PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
515 RNA_property_boolean_set(ptr, prop_release_confirm, true);
516 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
518 RNA_property_boolean_set(ptr, prop_release_confirm, true);
519 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
521 RNA_property_boolean_set(ptr, prop_release_confirm, true);
522 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
524 RNA_property_boolean_set(ptr, prop_release_confirm, true);
525 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
526
528 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, nullptr);
529 RNA_property_boolean_set(ptr, prop_release_confirm, true);
531 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y, ot_resize, nullptr);
532 RNA_property_boolean_set(ptr, prop_release_confirm, true);
534 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y, ot_resize, nullptr);
535 RNA_property_boolean_set(ptr, prop_release_confirm, true);
537 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y, ot_resize, nullptr);
538 RNA_property_boolean_set(ptr, prop_release_confirm, true);
539 ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE, ot_rotate, nullptr);
540 RNA_property_boolean_set(ptr, prop_release_confirm, true);
541 }
542}
543
544static void rotate_around_center_v2(float point[2], const float center[2], const float angle)
545{
546 float tmp[2];
547
548 sub_v2_v2v2(tmp, point, center);
549 rotate_v2_v2fl(point, tmp, angle);
550 add_v2_v2(point, center);
551}
552
553static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
554{
555 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(gzgroup->customdata);
556 bool has_select;
557 if (ggd->no_cage) {
558 has_select = gizmo2d_calc_transform_pivot(C, ggd->origin);
559 }
560 else {
561 has_select = gizmo2d_calc_bounds(C, ggd->origin, ggd->min, ggd->max);
563 }
564
565 bool show_cage = !ggd->no_cage && !equals_v2v2(ggd->min, ggd->max);
566
567 if (has_select == false) {
568 /* Nothing selected. Disable gizmo drawing and return. */
569 ggd->cage->flag |= WM_GIZMO_HIDDEN;
570 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
572 }
573 return;
574 }
575
576 if (!show_cage) {
577 /* Disable cage gizmo drawing and return. */
578 ggd->cage->flag |= WM_GIZMO_HIDDEN;
579 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
580 ggd->translate_xy[i]->flag &= ~WM_GIZMO_HIDDEN;
581 }
582 return;
583 }
584
585 /* We will show the cage gizmo! Setup all necessary data. */
586 ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
587 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
589 }
590}
591
592static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
593{
594 ARegion *region = CTX_wm_region(C);
595 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(gzgroup->customdata);
596 float origin[3] = {UNPACK2(ggd->origin), 0.0f};
597
598 gizmo2d_origin_to_region(region, origin);
599
600 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
601 wmGizmo *gz = ggd->translate_xy[i];
603 }
604
605 UI_view2d_view_to_region_m4(&region->v2d, ggd->cage->matrix_space);
606 /* Define the bounding box of the gizmo in the offset transform matrix. */
608 const float min_gizmo_pixel_size = 0.001f; /* Draw Gizmo larger than this many pixels. */
609 const float min_scale_axis_x = min_gizmo_pixel_size / ggd->cage->matrix_space[0][0];
610 const float min_scale_axis_y = min_gizmo_pixel_size / ggd->cage->matrix_space[1][1];
611 ggd->cage->matrix_offset[0][0] = max_ff(min_scale_axis_x, ggd->max[0] - ggd->min[0]);
612 ggd->cage->matrix_offset[1][1] = max_ff(min_scale_axis_y, ggd->max[1] - ggd->min[1]);
613
614 ScrArea *area = CTX_wm_area(C);
615
616 if (area->spacetype == SPACE_SEQ) {
617 Scene *scene = CTX_data_scene(C);
618 seq_get_strip_pivot_median(scene, origin);
619
620 float matrix_rotate[4][4];
621 unit_m4(matrix_rotate);
622 copy_v3_v3(matrix_rotate[3], origin);
623 rotate_m4(matrix_rotate, 'Z', ggd->rotation);
625 mul_m4_m4m4(ggd->cage->matrix_basis, matrix_rotate, ggd->cage->matrix_basis);
626
627 float mid[2];
628 sub_v2_v2v2(mid, origin, ggd->origin);
629 mul_v2_fl(mid, -1.0f);
630 copy_v2_v2(ggd->cage->matrix_offset[3], mid);
631 }
632 else {
633 const float origin_aa[3] = {UNPACK2(ggd->origin), 0.0f};
635 }
636}
637
639 wmGizmoGroup *gzgroup,
640 wmGizmo * /*gz*/,
641 const wmEvent * /*event*/)
642{
643 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(gzgroup->customdata);
644 wmGizmoOpElem *gzop;
645 const float *mid = ggd->origin;
646 const float *min = ggd->min;
647 const float *max = ggd->max;
648
649 /* Define the different transform center points that will be used when grabbing the corners or
650 * rotating with the gizmo.
651 *
652 * The coordinates are referred to as their cardinal directions:
653 * N
654 * o
655 *NW | NE
656 * x-----------x
657 * | |
658 *W| C |E
659 * | |
660 * x-----------x
661 *SW S SE
662 */
663 float n[3] = {mid[0], max[1], 0.0f};
664 float w[3] = {min[0], mid[1], 0.0f};
665 float e[3] = {max[0], mid[1], 0.0f};
666 float s[3] = {mid[0], min[1], 0.0f};
667
668 float nw[3] = {min[0], max[1], 0.0f};
669 float ne[3] = {max[0], max[1], 0.0f};
670 float sw[3] = {min[0], min[1], 0.0f};
671 float se[3] = {max[0], min[1], 0.0f};
672
673 float c[3] = {mid[0], mid[1], 0.0f};
674
675 float orient_matrix[3][3];
676 unit_m3(orient_matrix);
677
678 ScrArea *area = CTX_wm_area(C);
679
680 if (ggd->rotation != 0.0f && area->spacetype == SPACE_SEQ) {
681 float origin[3];
682 Scene *scene = CTX_data_scene(C);
683 seq_get_strip_pivot_median(scene, origin);
684 /* We need to rotate the cardinal points so they align with the rotated bounding box. */
685
686 rotate_around_center_v2(n, origin, ggd->rotation);
687 rotate_around_center_v2(w, origin, ggd->rotation);
688 rotate_around_center_v2(e, origin, ggd->rotation);
689 rotate_around_center_v2(s, origin, ggd->rotation);
690
691 rotate_around_center_v2(nw, origin, ggd->rotation);
692 rotate_around_center_v2(ne, origin, ggd->rotation);
693 rotate_around_center_v2(sw, origin, ggd->rotation);
694 rotate_around_center_v2(se, origin, ggd->rotation);
695
696 rotate_around_center_v2(c, origin, ggd->rotation);
697
698 axis_angle_to_mat3_single(orient_matrix, 'Z', ggd->rotation);
699 }
700
701 int orient_type = gizmo2d_calc_transform_orientation(C);
702
704 PropertyRNA *prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
705 PropertyRNA *prop_mouse_dir = RNA_struct_find_property(&gzop->ptr, "mouse_dir_constraint");
706 RNA_property_float_set_array(&gzop->ptr, prop_center_override, e);
707 RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[0]);
708 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
710 RNA_property_float_set_array(&gzop->ptr, prop_center_override, w);
711 RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[0]);
712 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
714 RNA_property_float_set_array(&gzop->ptr, prop_center_override, n);
715 RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[1]);
716 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
718 RNA_property_float_set_array(&gzop->ptr, prop_center_override, s);
719 RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[1]);
720 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
721
723 RNA_property_float_set_array(&gzop->ptr, prop_center_override, ne);
725 RNA_property_float_set_array(&gzop->ptr, prop_center_override, se);
727 RNA_property_float_set_array(&gzop->ptr, prop_center_override, nw);
729 RNA_property_float_set_array(&gzop->ptr, prop_center_override, sw);
730
732 RNA_property_float_set_array(&gzop->ptr, prop_center_override, c);
733}
734
744
745static void gizmo2d_xform_setup_no_cage(const bContext *C, wmGizmoGroup *gzgroup)
746{
747 gizmo2d_xform_setup(C, gzgroup);
748 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(gzgroup->customdata);
749 ggd->no_cage = true;
750}
751
753 wmGizmoGroup *gzgroup,
754 wmMsgBus *mbus)
755{
756 bScreen *screen = CTX_wm_screen(C);
757 ScrArea *area = CTX_wm_area(C);
758 ARegion *region = CTX_wm_region(C);
759 gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
760}
761
768
771/* -------------------------------------------------------------------- */
785
787{
788 const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
789 const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
790
791 GizmoGroup_Resize2D *ggd = static_cast<GizmoGroup_Resize2D *>(
792 MEM_callocN(sizeof(GizmoGroup_Resize2D), __func__));
793
794 ggd->gizmo_xy[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
795 ggd->gizmo_xy[1] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, nullptr);
796 ggd->gizmo_xy[2] = WM_gizmo_new_ptr(gzt_button, gzgroup, nullptr);
797
798 return ggd;
799}
800
801static void gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
802{
803 GizmoGroup_Resize2D *ggd = static_cast<GizmoGroup_Resize2D *>(gzgroup->customdata);
804 float origin[3];
805 const bool has_select = gizmo2d_calc_transform_pivot(C, origin);
806
807 if (has_select == false) {
808 for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
809 ggd->gizmo_xy[i]->flag |= WM_GIZMO_HIDDEN;
810 }
811 }
812 else {
813 for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
814 ggd->gizmo_xy[i]->flag &= ~WM_GIZMO_HIDDEN;
815 }
816 copy_v2_v2(ggd->origin, origin);
818 }
819}
820
821static void gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
822{
823 ARegion *region = CTX_wm_region(C);
824 GizmoGroup_Resize2D *ggd = static_cast<GizmoGroup_Resize2D *>(gzgroup->customdata);
825 float origin[3] = {UNPACK2(ggd->origin), 0.0f};
826
827 gizmo2d_origin_to_region(region, origin);
828
829 for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
830 wmGizmo *gz = ggd->gizmo_xy[i];
832
833 if (i < 2) {
834 float axis[3] = {0.0f}, rotated_axis[3];
835 axis[i] = 1.0f;
836 rotate_v3_v3v3fl(rotated_axis, axis, blender::float3{0, 0, 1}, ggd->rotation);
838 }
839 }
840}
841
842static void gizmo2d_resize_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
843{
844
845 wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
847 gzgroup->customdata = ggd;
848
849 for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
850 wmGizmo *gz = ggd->gizmo_xy[i];
851
852 /* Custom handler! */
854
855 if (i < 2) {
856 float color[4], color_hi[4];
857 gizmo2d_get_axis_color(i, color, color_hi);
858
859 /* Set up widget data. */
860 RNA_float_set(gz->ptr, "length", 1.0f);
861 RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
862
864 WM_gizmo_set_color(gz, color);
865 WM_gizmo_set_color_highlight(gz, color_hi);
866
867 WM_gizmo_set_scale(gz, 1.0f);
868 }
869 else {
870 float color[4], color_hi[4];
872 copy_v4_v4(color_hi, color);
873 color[3] *= 0.6f;
874
875 PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
876 RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
877
878 RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
879 /* Make the center low alpha. */
880 WM_gizmo_set_line_width(gz, 2.0f);
881 RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
882 WM_gizmo_set_color(gz, color);
883 WM_gizmo_set_color_highlight(gz, color_hi);
884
885 WM_gizmo_set_scale(gz, 1.2f);
886 }
887
888 /* Assign operator. */
889 PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_resize, nullptr);
890 if (i < 2) {
891 bool constraint[3] = {false};
892 constraint[i] = true;
893 if (RNA_struct_find_property(ptr, "constraint_axis")) {
894 RNA_boolean_set_array(ptr, "constraint_axis", constraint);
895 }
896 }
897 RNA_boolean_set(ptr, "release_confirm", true);
898 }
899}
900
902 wmGizmoGroup * /*gzgroup*/,
903 wmGizmo *gz,
904 const wmEvent * /*event*/)
905{
906 wmGizmoOpElem *gzop;
907 int orient_type = gizmo2d_calc_transform_orientation(C);
908
909 gzop = WM_gizmo_operator_get(gz, 0);
910 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
911}
912
914 wmGizmoGroup *gzgroup,
915 wmMsgBus *mbus)
916{
917 bScreen *screen = CTX_wm_screen(C);
918 ScrArea *area = CTX_wm_area(C);
919 ARegion *region = CTX_wm_region(C);
920 gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
921}
922
933
936/* -------------------------------------------------------------------- */
949
951{
952 const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
953
954 GizmoGroup_Rotate2D *ggd = static_cast<GizmoGroup_Rotate2D *>(
955 MEM_callocN(sizeof(GizmoGroup_Rotate2D), __func__));
956
957 ggd->gizmo = WM_gizmo_new_ptr(gzt_button, gzgroup, nullptr);
958
959 return ggd;
960}
961
962static void gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
963{
964 GizmoGroup_Rotate2D *ggd = static_cast<GizmoGroup_Rotate2D *>(gzgroup->customdata);
965 float origin[3];
966 const bool has_select = gizmo2d_calc_transform_pivot(C, origin);
967
968 if (has_select == false) {
969 ggd->gizmo->flag |= WM_GIZMO_HIDDEN;
970 }
971 else {
972 ggd->gizmo->flag &= ~WM_GIZMO_HIDDEN;
973 copy_v2_v2(ggd->origin, origin);
974 }
975}
976
977static void gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
978{
979 ARegion *region = CTX_wm_region(C);
980 GizmoGroup_Rotate2D *ggd = static_cast<GizmoGroup_Rotate2D *>(gzgroup->customdata);
981 float origin[3] = {UNPACK2(ggd->origin), 0.0f};
982
983 gizmo2d_origin_to_region(region, origin);
984
985 wmGizmo *gz = ggd->gizmo;
987}
988
989static void gizmo2d_rotate_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
990{
991
992 wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_rotate", true);
994 gzgroup->customdata = ggd;
995
996 /* Other setup functions iterate over axis. */
997 {
998 wmGizmo *gz = ggd->gizmo;
999
1000 /* Custom handler! */
1002 WM_gizmo_set_scale(gz, 1.2f);
1003
1004 {
1005 float color[4];
1007
1008 PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
1009 RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
1010
1011 RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
1012 /* Make the center low alpha. */
1013 WM_gizmo_set_line_width(gz, 2.0f);
1014 RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
1015 WM_gizmo_set_color(gz, color);
1017 }
1018
1019 /* Assign operator. */
1020 PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_resize, nullptr);
1021 RNA_boolean_set(ptr, "release_confirm", true);
1022 }
1023}
1024
1026 wmGizmoGroup *gzgroup,
1027 wmMsgBus *mbus)
1028{
1029 bScreen *screen = CTX_wm_screen(C);
1030 ScrArea *area = CTX_wm_area(C);
1031 ARegion *region = CTX_wm_region(C);
1032 gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
1033}
1034
1044
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:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#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 unit_m4(float m[4][4])
Definition rct.c:1127
void rotate_m4(float mat[4][4], char axis, float angle)
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
@ 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_ARROW_STYLE_BOX
@ 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
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)
void ED_region_tag_redraw_editor_overlays(ARegion *region)
Definition area.cc:669
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(SpaceImage *sima, Scene *scene, ViewLayer *view_layer, float r_center[2], char mode, bool *r_has_select)
Read Guarded memory(de)allocation.
@ 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:1803
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:1734
eWM_GizmoFlagTweak
Gizmo tweak flag. Bit-flag passed to gizmo while tweaking.
@ WM_GIZMO_HIDDEN
@ WM_GIZMO_DRAW_OFFSET_SCALE
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
ListBase * SEQ_channels_displayed_get(Editing *ed)
Definition channels.cc:23
int64_t size() const
int64_t remove_if(Predicate &&predicate)
#define SELECT
VectorSet< Sequence * > SEQ_query_rendered_strips(const Scene *scene, ListBase *channels, ListBase *seqbase, const int timeline_frame, const int displayed_channel)
Definition iterator.cc:184
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define G(x, y, z)
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(ID *id, StructRNA *type, void *data)
void RNA_property_boolean_set_array(PointerRNA *ptr, PropertyRNA *prop, const bool *values)
ListBase * SEQ_active_seqbase_get(const Editing *ed)
Definition sequencer.cc:416
Editing * SEQ_editing_get(const Scene *scene)
Definition sequencer.cc:262
#define min(a, b)
Definition sort.c:32
void SEQ_image_preview_unit_to_px(const Scene *scene, const float co_src[2], float co_dst[2])
void SEQ_image_transform_bounding_box_from_collection(Scene *scene, blender::Span< Sequence * > strips, bool apply_rotation, float r_min[2], float r_max[2])
void SEQ_image_transform_origin_offset_pixelspace_get(const Scene *scene, const Sequence *seq, float r_origin[2])
void SEQ_image_transform_mirror_factor_get(const Sequence *seq, float r_mirror[2])
wmGizmo * translate_xy[3]
float cursor[2]
StripTransform * transform
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
#define GIZMO_AXIS_LINE_WIDTH
static void gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
static int gizmo2d_modal(bContext *C, wmGizmo *widget, const wmEvent *, eWM_GizmoFlagTweak)
static void gizmo2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi)
void ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set(wmGizmoGroupType *gzgt)
void ED_widgetgroup_gizmo2d_rotate_callbacks_set(wmGizmoGroupType *gzgt)
static int gizmo2d_calc_transform_orientation(const bContext *C)
static bool gizmo2d_generic_poll(const bContext *C, wmGizmoGroupType *gzgt)
static GizmoGroup_Rotate2D * gizmogroup2d_rotate_init(wmGizmoGroup *gzgroup)
BLI_INLINE void gizmo2d_origin_to_region(ARegion *region, float *r_origin)
static void gizmo2d_resize_message_subscribe(const bContext *C, wmGizmoGroup *gzgroup, wmMsgBus *mbus)
static void gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
static void gizmo2d_xform_invoke_prepare(const bContext *C, wmGizmoGroup *gzgroup, wmGizmo *, const wmEvent *)
void ED_widgetgroup_gizmo2d_resize_callbacks_set(wmGizmoGroupType *gzgt)
static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
static void rotate_around_center_v2(float point[2], const float center[2], const float angle)
void ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType *gzgt)
static void gizmo2d_rotate_setup(const bContext *, wmGizmoGroup *gzgroup)
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_Resize2D * gizmogroup2d_resize_init(wmGizmoGroup *gzgroup)
static void gizmo2d_resize_invoke_prepare(const bContext *C, wmGizmoGroup *, wmGizmo *gz, const wmEvent *)
static void gizmo2d_rotate_message_subscribe(const bContext *C, wmGizmoGroup *gzgroup, wmMsgBus *mbus)
static void gizmo2d_xform_setup_no_cage(const bContext *C, wmGizmoGroup *gzgroup)
@ MAN2D_AXIS_LAST
@ MAN2D_AXIS_TRANS_X
@ MAN2D_AXIS_TRANS_Y
static void gizmo2d_pivot_point_message_subscribe(wmGizmoGroup *gzgroup, wmMsgBus *mbus, bScreen *screen, ScrArea *area, ARegion *region)
static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
static GizmoGroup2D * gizmogroup2d_init(wmGizmoGroup *gzgroup)
static void gizmo2d_xform_setup(const bContext *, wmGizmoGroup *gzgroup)
static void gizmo2d_resize_setup(const bContext *, wmGizmoGroup *gzgroup)
static float gizmo2d_calc_rotation(const bContext *C)
static bool seq_get_strip_pivot_median(const Scene *scene, float r_pivot[2])
static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max)
static void gizmo2d_xform_no_cage_message_subscribe(const bContext *C, wmGizmoGroup *gzgroup, wmMsgBus *mbus)
PointerRNA * ptr
Definition wm_files.cc:4126
void WM_gizmo_set_matrix_offset_location(wmGizmo *gz, const float offset[3])
Definition wm_gizmo.cc:298
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:336
void WM_gizmo_set_line_width(wmGizmo *gz, const float line_width)
Definition wm_gizmo.cc:318
void WM_gizmo_set_fn_custom_modal(wmGizmo *gz, wmGizmoFnModal fn)
Definition wm_gizmo.cc:347
wmGizmo * WM_gizmo_new_ptr(const wmGizmoType *gzt, wmGizmoGroup *gzgroup, PointerRNA *properties)
Definition wm_gizmo.cc:81
void WM_gizmo_set_scale(wmGizmo *gz, const float scale)
Definition wm_gizmo.cc:313
void WM_gizmo_set_matrix_location(wmGizmo *gz, const float origin[3])
Definition wm_gizmo.cc:283
void WM_gizmo_set_matrix_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3])
Definition wm_gizmo.cc:273
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:327
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 char *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)