Blender V4.5
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_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
53namespace blender::ed::transform {
54
55/* -------------------------------------------------------------------- */
58
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_discrete(&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
142
143/* -------------------------------------------------------------------- */
152
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
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 RNA_enum_set(ggd->cage->ptr,
220 "draw_options",
223
224 return ggd;
225}
226
230static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max)
231{
232 float min_buf[2], max_buf[2];
233 if (r_min == nullptr) {
234 r_min = min_buf;
235 }
236 if (r_max == nullptr) {
237 r_max = max_buf;
238 }
239
240 ScrArea *area = CTX_wm_area(C);
241 bool has_select = false;
242 if (area->spacetype == SPACE_IMAGE) {
243 Scene *scene = CTX_data_scene(C);
244 ViewLayer *view_layer = CTX_data_view_layer(C);
246 scene, view_layer, nullptr);
247 if (ED_uvedit_minmax_multi(scene, objects, r_min, r_max)) {
248 has_select = true;
249 }
250 }
251 else if (area->spacetype == SPACE_SEQ) {
252 Scene *scene = CTX_data_scene(C);
253 Editing *ed = seq::editing_get(scene);
256 VectorSet strips = seq::query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
257 strips.remove_if([&](Strip *strip) { return (strip->flag & SELECT) == 0; });
258 int selected_strips = strips.size();
259 if (selected_strips > 0) {
260 has_select = true;
262 scene, strips, selected_strips != 1);
263 copy_v2_v2(r_min, box.min);
264 copy_v2_v2(r_max, box.max);
265 }
266 if (selected_strips > 1) {
267 /* Don't draw the cage as transforming multiple strips isn't currently very useful as it
268 * doesn't behave as one would expect.
269 *
270 * This is because our current transform system doesn't support shearing which would make the
271 * scaling transforms of the bounding box behave weirdly.
272 * In addition to this, the rotation of the bounding box can not currently be hooked up
273 * properly to read the result from the transform system (when transforming multiple strips).
274 */
275 const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
276 if (pivot_point == V3D_AROUND_CURSOR) {
277 SpaceSeq *sseq = static_cast<SpaceSeq *>(area->spacedata.first);
278 const float2 cursor_pixel = seq::image_preview_unit_to_px(scene, sseq->cursor);
279 copy_v2_v2(r_center, cursor_pixel);
280 }
281 else {
282 mid_v2_v2v2(r_center, r_min, r_max);
283 }
284 zero_v2(r_min);
285 zero_v2(r_max);
286 return has_select;
287 }
288 }
289
290 if (has_select == false) {
291 zero_v2(r_min);
292 zero_v2(r_max);
293 }
294
295 mid_v2_v2v2(r_center, r_min, r_max);
296 return has_select;
297}
298
300{
301 ScrArea *area = CTX_wm_area(C);
302 if (area->spacetype != SPACE_SEQ) {
303 return V3D_ORIENT_GLOBAL;
304 }
305
306 Scene *scene = CTX_data_scene(C);
307 Editing *ed = seq::editing_get(scene);
310 VectorSet strips = seq::query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
311 strips.remove_if([&](Strip *strip) { return (strip->flag & SELECT) == 0; });
312
313 bool use_local_orient = strips.size() == 1;
314
315 if (use_local_orient) {
316 return V3D_ORIENT_LOCAL;
317 }
318 return V3D_ORIENT_GLOBAL;
319}
320
321static float gizmo2d_calc_rotation(const bContext *C)
322{
323 ScrArea *area = CTX_wm_area(C);
324 if (area->spacetype != SPACE_SEQ) {
325 return 0.0f;
326 }
327
328 Scene *scene = CTX_data_scene(C);
329 Editing *ed = seq::editing_get(scene);
332 VectorSet strips = seq::query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
333 strips.remove_if([&](Strip *strip) { return (strip->flag & SELECT) == 0; });
334
335 if (strips.size() == 1) {
336 /* Only return the strip rotation if only one is selected. */
337 for (Strip *strip : strips) {
340 return transform->rotation * mirror[0] * mirror[1];
341 }
342 }
343
344 return 0.0f;
345}
346
347static bool seq_get_strip_pivot_median(const Scene *scene, float r_pivot[2])
348{
349 zero_v2(r_pivot);
350
351 Editing *ed = seq::editing_get(scene);
354 VectorSet strips = seq::query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
355 strips.remove_if([&](Strip *strip) { return (strip->flag & SELECT) == 0; });
356 bool has_select = !strips.is_empty();
357
358 if (has_select) {
359 for (Strip *strip : strips) {
361 add_v2_v2(r_pivot, origin);
362 }
363 mul_v2_fl(r_pivot, 1.0f / strips.size());
364 }
365
366 return has_select;
367}
368
369static bool gizmo2d_calc_transform_pivot(const bContext *C, float r_pivot[2])
370{
371 ScrArea *area = CTX_wm_area(C);
372 Scene *scene = CTX_data_scene(C);
373 bool has_select = false;
374
375 if (area->spacetype == SPACE_IMAGE) {
376 SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first);
377 ViewLayer *view_layer = CTX_data_view_layer(C);
378 ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_pivot, sima->around, &has_select);
379 }
380 else if (area->spacetype == SPACE_SEQ) {
381 SpaceSeq *sseq = static_cast<SpaceSeq *>(area->spacedata.first);
382 const int pivot_point = scene->toolsettings->sequencer_tool_settings->pivot_point;
383
384 if (pivot_point == V3D_AROUND_CURSOR) {
385 const float2 cursor_pixel = seq::image_preview_unit_to_px(scene, sseq->cursor);
386 copy_v2_v2(r_pivot, cursor_pixel);
387
388 Editing *ed = seq::editing_get(scene);
391 VectorSet strips = seq::query_rendered_strips(scene, channels, seqbase, scene->r.cfra, 0);
392 strips.remove_if([&](Strip *strip) { return (strip->flag & SELECT) == 0; });
393 has_select = !strips.is_empty();
394 }
395 else if (pivot_point == V3D_AROUND_CENTER_BOUNDS) {
396 has_select = gizmo2d_calc_bounds(C, r_pivot, nullptr, nullptr);
397 }
398 else {
399 has_select = seq_get_strip_pivot_median(scene, r_pivot);
400 }
401 }
402 else {
403 BLI_assert_msg(0, "Unhandled space type!");
404 }
405 return has_select;
406}
407
411BLI_INLINE void gizmo2d_origin_to_region(ARegion *region, float *r_origin)
412{
413 UI_view2d_view_to_region_fl(&region->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]);
414}
415
420 wmGizmo *widget,
421 const wmEvent * /*event*/,
422 eWM_GizmoFlagTweak /*tweak_flag*/)
423{
424 ARegion *region = CTX_wm_region(C);
425 float origin[3];
426
428 gizmo2d_origin_to_region(region, origin);
429 WM_gizmo_set_matrix_location(widget, origin);
430
432
434}
435
436static void gizmo2d_xform_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
437{
438 wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
439 GizmoGroup2D *ggd = gizmogroup2d_init(gzgroup);
440 gzgroup->customdata = ggd;
441
442 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
443 wmGizmo *gz = ggd->translate_xy[i];
444
445 /* Custom handler! */
447
448 if (i < 2) {
449 float color[4], color_hi[4];
450 gizmo2d_get_axis_color(i, color, color_hi);
451
452 /* Set up widget data. */
453 RNA_float_set(gz->ptr, "length", 0.8f);
454 float axis[3] = {0.0f};
455 axis[i] = 1.0f;
457
458 float offset[3] = {0, 0, 0};
459 offset[2] = 0.18f;
462
465 WM_gizmo_set_color_highlight(gz, color_hi);
466
467 WM_gizmo_set_scale(gz, 1.0f);
468 }
469 else {
470 float color[4], color_hi[4];
472 copy_v4_v4(color_hi, color);
473 color[3] *= 0.6f;
474
475 PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
476 RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
477
478 RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
479 /* Make the center low alpha. */
480 WM_gizmo_set_line_width(gz, 2.0f);
481 RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
483 WM_gizmo_set_color_highlight(gz, color_hi);
484
485 WM_gizmo_set_scale(gz, 0.2f);
486 }
487
488 /* Assign operator. */
489 PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_translate, nullptr);
490 if (i < 2) {
491 bool constraint[3] = {false};
492 constraint[i] = true;
493 if (RNA_struct_find_property(ptr, "constraint_axis")) {
494 RNA_boolean_set_array(ptr, "constraint_axis", constraint);
495 }
496 }
497
498 RNA_boolean_set(ptr, "release_confirm", true);
499 }
500
501 {
502 wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
503 wmOperatorType *ot_rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true);
505
506 /* Assign operator. */
507 ptr = WM_gizmo_operator_set(ggd->cage, 0, ot_translate, nullptr);
508 RNA_boolean_set(ptr, "release_confirm", true);
509
510 const bool constraint_x[3] = {true, false, false};
511 const bool constraint_y[3] = {false, true, false};
512
514 PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
515 PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
516 RNA_property_boolean_set(ptr, prop_release_confirm, true);
517 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
519 RNA_property_boolean_set(ptr, prop_release_confirm, true);
520 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
522 RNA_property_boolean_set(ptr, prop_release_confirm, true);
523 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
525 RNA_property_boolean_set(ptr, prop_release_confirm, true);
526 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
527
529 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, nullptr);
530 RNA_property_boolean_set(ptr, prop_release_confirm, true);
532 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y, ot_resize, nullptr);
533 RNA_property_boolean_set(ptr, prop_release_confirm, true);
535 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y, ot_resize, nullptr);
536 RNA_property_boolean_set(ptr, prop_release_confirm, true);
538 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y, ot_resize, nullptr);
539 RNA_property_boolean_set(ptr, prop_release_confirm, true);
540 ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE, ot_rotate, nullptr);
541 RNA_property_boolean_set(ptr, prop_release_confirm, true);
542 }
543}
544
545static void rotate_around_center_v2(float point[2], const float center[2], const float angle)
546{
547 float tmp[2];
548
549 sub_v2_v2v2(tmp, point, center);
550 rotate_v2_v2fl(point, tmp, angle);
551 add_v2_v2(point, center);
552}
553
554static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
555{
556 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(gzgroup->customdata);
557 bool has_select;
558 if (ggd->no_cage) {
559 has_select = gizmo2d_calc_transform_pivot(C, ggd->origin);
560 }
561 else {
562 has_select = gizmo2d_calc_bounds(C, ggd->origin, ggd->min, ggd->max);
564 }
565
566 bool show_cage = !ggd->no_cage && !equals_v2v2(ggd->min, ggd->max);
567
568 if (has_select == false) {
569 /* Nothing selected. Disable gizmo drawing and return. */
570 ggd->cage->flag |= WM_GIZMO_HIDDEN;
571 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
573 }
574 return;
575 }
576
577 if (!show_cage) {
578 /* Disable cage gizmo drawing and return. */
579 ggd->cage->flag |= WM_GIZMO_HIDDEN;
580 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
582 }
583 return;
584 }
585
586 /* We will show the cage gizmo! Setup all necessary data. */
587 ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
588 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
590 }
591}
592
594{
595 ARegion *region = CTX_wm_region(C);
596 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(gzgroup->customdata);
597 float origin[3] = {UNPACK2(ggd->origin), 0.0f};
598
599 gizmo2d_origin_to_region(region, origin);
600
601 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
602 wmGizmo *gz = ggd->translate_xy[i];
604 }
605
607 /* Define the bounding box of the gizmo in the offset transform matrix. */
609 const float min_gizmo_pixel_size = 0.001f; /* Draw Gizmo larger than this many pixels. */
610 const float min_scale_axis_x = min_gizmo_pixel_size / ggd->cage->matrix_space[0][0];
611 const float min_scale_axis_y = min_gizmo_pixel_size / ggd->cage->matrix_space[1][1];
612 ggd->cage->matrix_offset[0][0] = max_ff(min_scale_axis_x, ggd->max[0] - ggd->min[0]);
613 ggd->cage->matrix_offset[1][1] = max_ff(min_scale_axis_y, ggd->max[1] - ggd->min[1]);
614
615 ScrArea *area = CTX_wm_area(C);
616
617 if (area->spacetype == SPACE_SEQ) {
618 Scene *scene = CTX_data_scene(C);
619 seq_get_strip_pivot_median(scene, origin);
620
621 float matrix_rotate[4][4];
622 unit_m4(matrix_rotate);
623 copy_v3_v3(matrix_rotate[3], origin);
624 rotate_m4(matrix_rotate, 'Z', ggd->rotation);
626 mul_m4_m4m4(ggd->cage->matrix_basis, matrix_rotate, ggd->cage->matrix_basis);
627
628 float mid[2];
629 sub_v2_v2v2(mid, origin, ggd->origin);
630 mul_v2_fl(mid, -1.0f);
631 copy_v2_v2(ggd->cage->matrix_offset[3], mid);
632 }
633 else {
634 const float origin_aa[3] = {UNPACK2(ggd->origin), 0.0f};
636 }
637}
638
640 wmGizmoGroup *gzgroup,
641 wmGizmo * /*gz*/,
642 const wmEvent * /*event*/)
643{
644 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(gzgroup->customdata);
645 wmGizmoOpElem *gzop;
646 const float *mid = ggd->origin;
647 const float *min = ggd->min;
648 const float *max = ggd->max;
649
650 /* Define the different transform center points that will be used when grabbing the corners or
651 * rotating with the gizmo.
652 *
653 * The coordinates are referred to as their cardinal directions:
654 * N
655 * o
656 *NW | NE
657 * x-----------x
658 * | |
659 *W| C |E
660 * | |
661 * x-----------x
662 *SW S SE
663 */
664 float n[3] = {mid[0], max[1], 0.0f};
665 float w[3] = {min[0], mid[1], 0.0f};
666 float e[3] = {max[0], mid[1], 0.0f};
667 float s[3] = {mid[0], min[1], 0.0f};
668
669 float nw[3] = {min[0], max[1], 0.0f};
670 float ne[3] = {max[0], max[1], 0.0f};
671 float sw[3] = {min[0], min[1], 0.0f};
672 float se[3] = {max[0], min[1], 0.0f};
673
674 float c[3] = {mid[0], mid[1], 0.0f};
675
676 float orient_matrix[3][3];
677 unit_m3(orient_matrix);
678
679 ScrArea *area = CTX_wm_area(C);
680
681 if (ggd->rotation != 0.0f && area->spacetype == SPACE_SEQ) {
682 float origin[3];
683 Scene *scene = CTX_data_scene(C);
684 seq_get_strip_pivot_median(scene, origin);
685 /* We need to rotate the cardinal points so they align with the rotated bounding box. */
686
687 rotate_around_center_v2(n, origin, ggd->rotation);
688 rotate_around_center_v2(w, origin, ggd->rotation);
689 rotate_around_center_v2(e, origin, ggd->rotation);
690 rotate_around_center_v2(s, origin, ggd->rotation);
691
692 rotate_around_center_v2(nw, origin, ggd->rotation);
693 rotate_around_center_v2(ne, origin, ggd->rotation);
694 rotate_around_center_v2(sw, origin, ggd->rotation);
695 rotate_around_center_v2(se, origin, ggd->rotation);
696
697 rotate_around_center_v2(c, origin, ggd->rotation);
698
699 axis_angle_to_mat3_single(orient_matrix, 'Z', ggd->rotation);
700 }
701
702 int orient_type = gizmo2d_calc_transform_orientation(C);
703
705 PropertyRNA *prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
706 PropertyRNA *prop_mouse_dir = RNA_struct_find_property(&gzop->ptr, "mouse_dir_constraint");
707 RNA_property_float_set_array(&gzop->ptr, prop_center_override, e);
708 RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[0]);
709 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
711 RNA_property_float_set_array(&gzop->ptr, prop_center_override, w);
712 RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[0]);
713 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
715 RNA_property_float_set_array(&gzop->ptr, prop_center_override, n);
716 RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[1]);
717 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
719 RNA_property_float_set_array(&gzop->ptr, prop_center_override, s);
720 RNA_property_float_set_array(&gzop->ptr, prop_mouse_dir, orient_matrix[1]);
721 RNA_enum_set(&gzop->ptr, "orient_type", orient_type);
722
724 RNA_property_float_set_array(&gzop->ptr, prop_center_override, ne);
726 RNA_property_float_set_array(&gzop->ptr, prop_center_override, se);
728 RNA_property_float_set_array(&gzop->ptr, prop_center_override, nw);
730 RNA_property_float_set_array(&gzop->ptr, prop_center_override, sw);
731
733 RNA_property_float_set_array(&gzop->ptr, prop_center_override, c);
734}
735
745
747{
748 gizmo2d_xform_setup(C, gzgroup);
749 GizmoGroup2D *ggd = static_cast<GizmoGroup2D *>(gzgroup->customdata);
750 ggd->no_cage = true;
751}
752
754 wmGizmoGroup *gzgroup,
755 wmMsgBus *mbus)
756{
757 bScreen *screen = CTX_wm_screen(C);
758 ScrArea *area = CTX_wm_area(C);
759 ARegion *region = CTX_wm_region(C);
760 gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
761}
762
769
771
772/* -------------------------------------------------------------------- */
780
786
788{
789 const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
790 const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
791
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++) {
815 }
816 copy_v2_v2(ggd->origin, origin);
818 }
819}
820
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, 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
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);
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
935
936/* -------------------------------------------------------------------- */
944
949
951{
952 const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
953
955
956 ggd->gizmo = WM_gizmo_new_ptr(gzt_button, gzgroup, nullptr);
957
958 return ggd;
959}
960
961static void gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
962{
963 GizmoGroup_Rotate2D *ggd = static_cast<GizmoGroup_Rotate2D *>(gzgroup->customdata);
964 float origin[3];
965 const bool has_select = gizmo2d_calc_transform_pivot(C, origin);
966
967 if (has_select == false) {
968 ggd->gizmo->flag |= WM_GIZMO_HIDDEN;
969 }
970 else {
971 ggd->gizmo->flag &= ~WM_GIZMO_HIDDEN;
972 copy_v2_v2(ggd->origin, origin);
973 }
974}
975
977{
978 ARegion *region = CTX_wm_region(C);
979 GizmoGroup_Rotate2D *ggd = static_cast<GizmoGroup_Rotate2D *>(gzgroup->customdata);
980 float origin[3] = {UNPACK2(ggd->origin), 0.0f};
981
982 gizmo2d_origin_to_region(region, origin);
983
984 wmGizmo *gz = ggd->gizmo;
986}
987
988static void gizmo2d_rotate_setup(const bContext * /*C*/, wmGizmoGroup *gzgroup)
989{
990
991 wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_rotate", true);
993 gzgroup->customdata = ggd;
994
995 /* Other setup functions iterate over axis. */
996 {
997 wmGizmo *gz = ggd->gizmo;
998
999 /* Custom handler! */
1001 WM_gizmo_set_scale(gz, 1.2f);
1002
1003 {
1004 float color[4];
1006
1007 PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
1008 RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
1009
1010 RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
1011 /* Make the center low alpha. */
1012 WM_gizmo_set_line_width(gz, 2.0f);
1013 RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
1016 }
1017
1018 /* Assign operator. */
1019 PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_resize, nullptr);
1020 RNA_boolean_set(ptr, "release_confirm", true);
1021 }
1022}
1023
1025 wmGizmoGroup *gzgroup,
1026 wmMsgBus *mbus)
1027{
1028 bScreen *screen = CTX_wm_screen(C);
1029 ScrArea *area = CTX_wm_area(C);
1030 ARegion *region = CTX_wm_region(C);
1031 gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
1032}
1033
1043
1045
1046} // 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
@ 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_XFORM_FLAG_SCALE
@ ED_GIZMO_CAGE_XFORM_FLAG_TRANSLATE
@ ED_GIZMO_CAGE_XFORM_FLAG_ROTATE
@ 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_ARROW_STYLE_BOX
@ ED_GIZMO_CAGE_DRAW_FLAG_CORNER_HANDLES
@ ED_GIZMO_CAGE_DRAW_FLAG_XFORM_CENTER_HANDLE
@ ED_GIZMO_BUTTON_SHOW_BACKDROP
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:675
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)
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:1807
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:1738
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:272
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:205
ListBase * active_seqbase_get(const Editing *ed)
Definition sequencer.cc:420
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:4226
void WM_gizmo_set_matrix_offset_location(wmGizmo *gz, const float offset[3])
Definition wm_gizmo.cc:301
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:339
void WM_gizmo_set_line_width(wmGizmo *gz, const float line_width)
Definition wm_gizmo.cc:321
void WM_gizmo_set_fn_custom_modal(wmGizmo *gz, wmGizmoFnModal fn)
Definition wm_gizmo.cc:350
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:316
void WM_gizmo_set_matrix_location(wmGizmo *gz, const float origin[3])
Definition wm_gizmo.cc:286
void WM_gizmo_set_matrix_rotation_from_z_axis(wmGizmo *gz, const float z_axis[3])
Definition wm_gizmo.cc:276
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:330
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)