1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 */
16
17 /** \file
18 * \ingroup edtransform
19 *
20 * \name 2D Transform Gizmo
21 *
22 * Used for UV/Image Editor
23 */
24
25 #include "MEM_guardedalloc.h"
26
27 #include "BLI_math.h"
28
29 #include "DNA_object_types.h"
30 #include "DNA_screen_types.h"
31 #include "DNA_space_types.h"
32 #include "DNA_view3d_types.h"
33
34 #include "BKE_context.h"
35 #include "BKE_layer.h"
36
37 #include "RNA_access.h"
38
39 #include "UI_resources.h"
40 #include "UI_view2d.h"
41
42 #include "WM_api.h"
43 #include "WM_message.h"
44 #include "WM_types.h"
45
46 #include "ED_gizmo_library.h"
47 #include "ED_gizmo_utils.h"
48 #include "ED_image.h"
49 #include "ED_screen.h"
50 #include "ED_uvedit.h"
51
52 #include "transform.h" /* own include */
53
54 /* -------------------------------------------------------------------- */
55 /** \name Shared Callback's
56 */
57
gizmo2d_generic_poll(const bContext * C,wmGizmoGroupType * gzgt)58 static bool gizmo2d_generic_poll(const bContext *C, wmGizmoGroupType *gzgt)
59 {
60 if (!ED_gizmo_poll_or_unlink_delayed_from_tool(C, gzgt)) {
61 return false;
62 }
63
64 if ((U.gizmo_flag & USER_GIZMO_DRAW) == 0) {
65 return false;
66 }
67
68 ScrArea *area = CTX_wm_area(C);
69 switch (area->spacetype) {
70 case SPACE_IMAGE: {
71 SpaceImage *sima = area->spacedata.first;
72 Object *obedit = CTX_data_edit_object(C);
73 if (!ED_space_image_show_uvedit(sima, obedit)) {
74 return false;
75 }
76 }
77 }
78
79 return true;
80 }
81
gizmo2d_pivot_point_message_subscribe(struct wmGizmoGroup * gzgroup,struct wmMsgBus * mbus,bScreen * screen,ScrArea * area,ARegion * region)82 static void gizmo2d_pivot_point_message_subscribe(struct wmGizmoGroup *gzgroup,
83 struct wmMsgBus *mbus,
84 /* Additional args. */
85 bScreen *screen,
86 ScrArea *area,
87 ARegion *region)
88 {
89 wmMsgSubscribeValue msg_sub_value_gz_tag_refresh = {
90 .owner = region,
91 .user_data = gzgroup->parent_gzmap,
92 .notify = WM_gizmo_do_msg_notify_tag_refresh,
93 };
94
95 switch (area->spacetype) {
96 case SPACE_IMAGE: {
97 SpaceImage *sima = area->spacedata.first;
98 PointerRNA ptr;
99 RNA_pointer_create(&screen->id, &RNA_SpaceImageEditor, sima, &ptr);
100 {
101 extern PropertyRNA rna_SpaceImageEditor_pivot_point;
102 extern PropertyRNA rna_SpaceImageEditor_cursor_location;
103 const PropertyRNA *props[] = {
104 &rna_SpaceImageEditor_pivot_point,
105 (sima->around == V3D_AROUND_CURSOR) ? &rna_SpaceImageEditor_cursor_location : NULL,
106 };
107 for (int i = 0; i < ARRAY_SIZE(props); i++) {
108 if (props[i] == NULL) {
109 continue;
110 }
111 WM_msg_subscribe_rna(mbus, &ptr, props[i], &msg_sub_value_gz_tag_refresh, __func__);
112 }
113 }
114 break;
115 }
116 }
117 }
118
119 /** \} */
120
121 /* -------------------------------------------------------------------- */
122 /** \name Arrow / Cage Gizmo Group
123 *
124 * Defines public functions, not the gizmo itself:
125 *
126 * - #ED_widgetgroup_gizmo2d_xform_callbacks_set
127 * - #ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set
128 *
129 * \{ */
130
131 /* axes as index */
132 enum {
133 MAN2D_AXIS_TRANS_X = 0,
134 MAN2D_AXIS_TRANS_Y,
135
136 MAN2D_AXIS_LAST,
137 };
138
139 typedef struct GizmoGroup2D {
140 wmGizmo *translate_xy[3];
141 wmGizmo *cage;
142
143 /* Current origin in view space, used to update widget origin for possible view changes */
144 float origin[2];
145 float min[2];
146 float max[2];
147
148 bool no_cage;
149
150 } GizmoGroup2D;
151
152 /* **************** Utilities **************** */
153
gizmo2d_get_axis_color(const int axis_idx,float * r_col,float * r_col_hi)154 static void gizmo2d_get_axis_color(const int axis_idx, float *r_col, float *r_col_hi)
155 {
156 const float alpha = 0.6f;
157 const float alpha_hi = 1.0f;
158 int col_id;
159
160 switch (axis_idx) {
161 case MAN2D_AXIS_TRANS_X:
162 col_id = TH_AXIS_X;
163 break;
164 case MAN2D_AXIS_TRANS_Y:
165 col_id = TH_AXIS_Y;
166 break;
167 default:
168 BLI_assert(0);
169 col_id = TH_AXIS_Y;
170 break;
171 }
172
173 UI_GetThemeColor4fv(col_id, r_col);
174
175 copy_v4_v4(r_col_hi, r_col);
176 r_col[3] *= alpha;
177 r_col_hi[3] *= alpha_hi;
178 }
179
gizmogroup2d_init(wmGizmoGroup * gzgroup)180 static GizmoGroup2D *gizmogroup2d_init(wmGizmoGroup *gzgroup)
181 {
182 const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
183 const wmGizmoType *gzt_cage = WM_gizmotype_find("GIZMO_GT_cage_2d", true);
184 const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
185
186 GizmoGroup2D *ggd = MEM_callocN(sizeof(GizmoGroup2D), __func__);
187
188 ggd->translate_xy[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
189 ggd->translate_xy[1] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
190 ggd->translate_xy[2] = WM_gizmo_new_ptr(gzt_button, gzgroup, NULL);
191 ggd->cage = WM_gizmo_new_ptr(gzt_cage, gzgroup, NULL);
192
193 RNA_enum_set(ggd->cage->ptr,
194 "transform",
195 ED_GIZMO_CAGE2D_XFORM_FLAG_TRANSLATE | ED_GIZMO_CAGE2D_XFORM_FLAG_SCALE |
196 ED_GIZMO_CAGE2D_XFORM_FLAG_ROTATE);
197
198 return ggd;
199 }
200
201 /**
202 * Calculates origin in view space, use with #gizmo2d_origin_to_region.
203 */
gizmo2d_calc_bounds(const bContext * C,float * r_center,float * r_min,float * r_max)204 static bool gizmo2d_calc_bounds(const bContext *C, float *r_center, float *r_min, float *r_max)
205 {
206 float min_buf[2], max_buf[2];
207 if (r_min == NULL) {
208 r_min = min_buf;
209 }
210 if (r_max == NULL) {
211 r_max = max_buf;
212 }
213
214 ScrArea *area = CTX_wm_area(C);
215 bool changed = false;
216 if (area->spacetype == SPACE_IMAGE) {
217 Scene *scene = CTX_data_scene(C);
218 ViewLayer *view_layer = CTX_data_view_layer(C);
219 uint objects_len = 0;
220 Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs(
221 view_layer, NULL, &objects_len);
222 if (ED_uvedit_minmax_multi(scene, objects, objects_len, r_min, r_max)) {
223 changed = true;
224 }
225 MEM_freeN(objects);
226 }
227
228 if (changed == false) {
229 zero_v2(r_min);
230 zero_v2(r_max);
231 }
232
233 mid_v2_v2v2(r_center, r_min, r_max);
234 return changed;
235 }
236
gizmo2d_calc_center(const bContext * C,float r_center[2])237 static bool gizmo2d_calc_center(const bContext *C, float r_center[2])
238 {
239 ScrArea *area = CTX_wm_area(C);
240 bool has_select = false;
241 zero_v2(r_center);
242 if (area->spacetype == SPACE_IMAGE) {
243 SpaceImage *sima = area->spacedata.first;
244 Scene *scene = CTX_data_scene(C);
245 ViewLayer *view_layer = CTX_data_view_layer(C);
246 ED_uvedit_center_from_pivot_ex(sima, scene, view_layer, r_center, sima->around, &has_select);
247 }
248 return has_select;
249 }
250
251 /**
252 * Convert origin (or any other point) from view to region space.
253 */
gizmo2d_origin_to_region(ARegion * region,float * r_origin)254 BLI_INLINE void gizmo2d_origin_to_region(ARegion *region, float *r_origin)
255 {
256 UI_view2d_view_to_region_fl(®ion->v2d, r_origin[0], r_origin[1], &r_origin[0], &r_origin[1]);
257 }
258
259 /**
260 * Custom handler for gizmo widgets
261 */
gizmo2d_modal(bContext * C,wmGizmo * widget,const wmEvent * UNUSED (event),eWM_GizmoFlagTweak UNUSED (tweak_flag))262 static int gizmo2d_modal(bContext *C,
263 wmGizmo *widget,
264 const wmEvent *UNUSED(event),
265 eWM_GizmoFlagTweak UNUSED(tweak_flag))
266 {
267 ARegion *region = CTX_wm_region(C);
268 float origin[3];
269
270 gizmo2d_calc_center(C, origin);
271 gizmo2d_origin_to_region(region, origin);
272 WM_gizmo_set_matrix_location(widget, origin);
273
274 ED_region_tag_redraw_editor_overlays(region);
275
276 return OPERATOR_RUNNING_MODAL;
277 }
278
gizmo2d_xform_setup(const bContext * UNUSED (C),wmGizmoGroup * gzgroup)279 static void gizmo2d_xform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
280 {
281 wmOperatorType *ot_translate = WM_operatortype_find("TRANSFORM_OT_translate", true);
282 GizmoGroup2D *ggd = gizmogroup2d_init(gzgroup);
283 gzgroup->customdata = ggd;
284
285 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
286 wmGizmo *gz = ggd->translate_xy[i];
287
288 /* custom handler! */
289 WM_gizmo_set_fn_custom_modal(gz, gizmo2d_modal);
290
291 if (i < 2) {
292 float color[4], color_hi[4];
293 gizmo2d_get_axis_color(i, color, color_hi);
294
295 /* set up widget data */
296 RNA_float_set(gz->ptr, "length", 0.8f);
297 float axis[3] = {0.0f};
298 axis[i] = 1.0f;
299 WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis);
300
301 float offset[3] = {0, 0, 0};
302 offset[2] = 0.18f;
303 WM_gizmo_set_matrix_offset_location(gz, offset);
304 gz->flag |= WM_GIZMO_DRAW_OFFSET_SCALE;
305
306 WM_gizmo_set_line_width(gz, GIZMO_AXIS_LINE_WIDTH);
307 WM_gizmo_set_color(gz, color);
308 WM_gizmo_set_color_highlight(gz, color_hi);
309
310 WM_gizmo_set_scale(gz, 1.0f);
311 }
312 else {
313 float color[4], color_hi[4];
314 UI_GetThemeColor4fv(TH_GIZMO_VIEW_ALIGN, color);
315 copy_v4_v4(color_hi, color);
316 color[3] *= 0.6f;
317
318 PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
319 RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
320
321 RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
322 /* Make the center low alpha. */
323 WM_gizmo_set_line_width(gz, 2.0f);
324 RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
325 WM_gizmo_set_color(gz, color);
326 WM_gizmo_set_color_highlight(gz, color_hi);
327
328 WM_gizmo_set_scale(gz, 0.2f);
329 }
330
331 /* Assign operator. */
332 PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_translate, NULL);
333 if (i < 2) {
334 bool constraint[3] = {false};
335 constraint[i] = true;
336 if (RNA_struct_find_property(ptr, "constraint_axis")) {
337 RNA_boolean_set_array(ptr, "constraint_axis", constraint);
338 }
339 }
340
341 RNA_boolean_set(ptr, "release_confirm", 1);
342 }
343
344 {
345 wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
346 wmOperatorType *ot_rotate = WM_operatortype_find("TRANSFORM_OT_rotate", true);
347 PointerRNA *ptr;
348
349 /* assign operator */
350 ptr = WM_gizmo_operator_set(ggd->cage, 0, ot_translate, NULL);
351 RNA_boolean_set(ptr, "release_confirm", 1);
352
353 const bool constraint_x[3] = {1, 0, 0};
354 const bool constraint_y[3] = {0, 1, 0};
355
356 ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X, ot_resize, NULL);
357 PropertyRNA *prop_release_confirm = RNA_struct_find_property(ptr, "release_confirm");
358 PropertyRNA *prop_constraint_axis = RNA_struct_find_property(ptr, "constraint_axis");
359 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
360 RNA_property_boolean_set(ptr, prop_release_confirm, true);
361 ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X, ot_resize, NULL);
362 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_x);
363 RNA_property_boolean_set(ptr, prop_release_confirm, true);
364 ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y, ot_resize, NULL);
365 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
366 RNA_property_boolean_set(ptr, prop_release_confirm, true);
367 ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y, ot_resize, NULL);
368 RNA_property_boolean_set_array(ptr, prop_constraint_axis, constraint_y);
369 RNA_property_boolean_set(ptr, prop_release_confirm, true);
370
371 ptr = WM_gizmo_operator_set(
372 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y, ot_resize, NULL);
373 RNA_property_boolean_set(ptr, prop_release_confirm, true);
374 ptr = WM_gizmo_operator_set(
375 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y, ot_resize, NULL);
376 RNA_property_boolean_set(ptr, prop_release_confirm, true);
377 ptr = WM_gizmo_operator_set(
378 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y, ot_resize, NULL);
379 RNA_property_boolean_set(ptr, prop_release_confirm, true);
380 ptr = WM_gizmo_operator_set(
381 ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y, ot_resize, NULL);
382 RNA_property_boolean_set(ptr, prop_release_confirm, true);
383 ptr = WM_gizmo_operator_set(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE, ot_rotate, NULL);
384 RNA_property_boolean_set(ptr, prop_release_confirm, true);
385 }
386 }
387
gizmo2d_xform_setup_no_cage(const bContext * C,wmGizmoGroup * gzgroup)388 static void gizmo2d_xform_setup_no_cage(const bContext *C, wmGizmoGroup *gzgroup)
389 {
390 gizmo2d_xform_setup(C, gzgroup);
391 GizmoGroup2D *ggd = gzgroup->customdata;
392 ggd->no_cage = true;
393 }
394
gizmo2d_xform_refresh(const bContext * C,wmGizmoGroup * gzgroup)395 static void gizmo2d_xform_refresh(const bContext *C, wmGizmoGroup *gzgroup)
396 {
397 GizmoGroup2D *ggd = gzgroup->customdata;
398 float origin[3];
399 bool has_select;
400 if (ggd->no_cage) {
401 has_select = gizmo2d_calc_center(C, origin);
402 }
403 else {
404 has_select = gizmo2d_calc_bounds(C, origin, ggd->min, ggd->max);
405 }
406 copy_v2_v2(ggd->origin, origin);
407 bool show_cage = !ggd->no_cage && !equals_v2v2(ggd->min, ggd->max);
408
409 if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
410 Scene *scene = CTX_data_scene(C);
411 if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
412 gzgroup->use_fallback_keymap = true;
413 }
414 else {
415 gzgroup->use_fallback_keymap = false;
416 }
417 }
418
419 if (has_select == false) {
420 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
421 ggd->translate_xy[i]->flag |= WM_GIZMO_HIDDEN;
422 }
423 ggd->cage->flag |= WM_GIZMO_HIDDEN;
424 }
425 else {
426 if (show_cage) {
427 ggd->cage->flag &= ~WM_GIZMO_HIDDEN;
428 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
429 wmGizmo *gz = ggd->translate_xy[i];
430 gz->flag |= WM_GIZMO_HIDDEN;
431 }
432 }
433 else {
434 ggd->cage->flag |= WM_GIZMO_HIDDEN;
435 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
436 wmGizmo *gz = ggd->translate_xy[i];
437 gz->flag &= ~WM_GIZMO_HIDDEN;
438 }
439 }
440
441 if (show_cage) {
442 wmGizmoOpElem *gzop;
443 float mid[2];
444 const float *min = ggd->min;
445 const float *max = ggd->max;
446 mid_v2_v2v2(mid, min, max);
447
448 gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X);
449 PropertyRNA *prop_center_override = RNA_struct_find_property(&gzop->ptr, "center_override");
450 RNA_property_float_set_array(
451 &gzop->ptr, prop_center_override, (float[3]){max[0], mid[1], 0.0f});
452 gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X);
453 RNA_property_float_set_array(
454 &gzop->ptr, prop_center_override, (float[3]){min[0], mid[1], 0.0f});
455 gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_Y);
456 RNA_property_float_set_array(
457 &gzop->ptr, prop_center_override, (float[3]){mid[0], max[1], 0.0f});
458 gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_Y);
459 RNA_property_float_set_array(
460 &gzop->ptr, prop_center_override, (float[3]){mid[0], min[1], 0.0f});
461
462 gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MIN_Y);
463 RNA_property_float_set_array(
464 &gzop->ptr, prop_center_override, (float[3]){max[0], max[1], 0.0f});
465 gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MIN_X_MAX_Y);
466 RNA_property_float_set_array(
467 &gzop->ptr, prop_center_override, (float[3]){max[0], min[1], 0.0f});
468 gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MIN_Y);
469 RNA_property_float_set_array(
470 &gzop->ptr, prop_center_override, (float[3]){min[0], max[1], 0.0f});
471 gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_SCALE_MAX_X_MAX_Y);
472 RNA_property_float_set_array(
473 &gzop->ptr, prop_center_override, (float[3]){min[0], min[1], 0.0f});
474
475 gzop = WM_gizmo_operator_get(ggd->cage, ED_GIZMO_CAGE2D_PART_ROTATE);
476 RNA_property_float_set_array(
477 &gzop->ptr, prop_center_override, (float[3]){mid[0], mid[1], 0.0f});
478 }
479 }
480 }
481
gizmo2d_xform_draw_prepare(const bContext * C,wmGizmoGroup * gzgroup)482 static void gizmo2d_xform_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
483 {
484 ARegion *region = CTX_wm_region(C);
485 GizmoGroup2D *ggd = gzgroup->customdata;
486 float origin[3] = {UNPACK2(ggd->origin), 0.0f};
487 const float origin_aa[3] = {UNPACK2(ggd->origin), 0.0f};
488
489 gizmo2d_origin_to_region(region, origin);
490
491 for (int i = 0; i < ARRAY_SIZE(ggd->translate_xy); i++) {
492 wmGizmo *gz = ggd->translate_xy[i];
493 WM_gizmo_set_matrix_location(gz, origin);
494 }
495
496 UI_view2d_view_to_region_m4(®ion->v2d, ggd->cage->matrix_space);
497 WM_gizmo_set_matrix_offset_location(ggd->cage, origin_aa);
498 ggd->cage->matrix_offset[0][0] = (ggd->max[0] - ggd->min[0]);
499 ggd->cage->matrix_offset[1][1] = (ggd->max[1] - ggd->min[1]);
500 }
501
gizmo2d_xform_no_cage_message_subscribe(const struct bContext * C,struct wmGizmoGroup * gzgroup,struct wmMsgBus * mbus)502 static void gizmo2d_xform_no_cage_message_subscribe(const struct bContext *C,
503 struct wmGizmoGroup *gzgroup,
504 struct wmMsgBus *mbus)
505 {
506 bScreen *screen = CTX_wm_screen(C);
507 ScrArea *area = CTX_wm_area(C);
508 ARegion *region = CTX_wm_region(C);
509 gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
510 }
511
ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType * gzgt)512 void ED_widgetgroup_gizmo2d_xform_callbacks_set(wmGizmoGroupType *gzgt)
513 {
514 gzgt->poll = gizmo2d_generic_poll;
515 gzgt->setup = gizmo2d_xform_setup;
516 gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
517 gzgt->refresh = gizmo2d_xform_refresh;
518 gzgt->draw_prepare = gizmo2d_xform_draw_prepare;
519 }
520
ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set(wmGizmoGroupType * gzgt)521 void ED_widgetgroup_gizmo2d_xform_no_cage_callbacks_set(wmGizmoGroupType *gzgt)
522 {
523 ED_widgetgroup_gizmo2d_xform_callbacks_set(gzgt);
524 gzgt->setup = gizmo2d_xform_setup_no_cage;
525 gzgt->message_subscribe = gizmo2d_xform_no_cage_message_subscribe;
526 }
527
528 /** \} */
529
530 /* -------------------------------------------------------------------- */
531 /** \name Scale Handles
532 *
533 * Defines public functions, not the gizmo itself:
534 *
535 * - #ED_widgetgroup_gizmo2d_resize_callbacks_set
536 *
537 * \{ */
538
539 typedef struct GizmoGroup_Resize2D {
540 wmGizmo *gizmo_xy[3];
541 float origin[2];
542 } GizmoGroup_Resize2D;
543
gizmogroup2d_resize_init(wmGizmoGroup * gzgroup)544 static GizmoGroup_Resize2D *gizmogroup2d_resize_init(wmGizmoGroup *gzgroup)
545 {
546 const wmGizmoType *gzt_arrow = WM_gizmotype_find("GIZMO_GT_arrow_3d", true);
547 const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
548
549 GizmoGroup_Resize2D *ggd = MEM_callocN(sizeof(GizmoGroup_Resize2D), __func__);
550
551 ggd->gizmo_xy[0] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
552 ggd->gizmo_xy[1] = WM_gizmo_new_ptr(gzt_arrow, gzgroup, NULL);
553 ggd->gizmo_xy[2] = WM_gizmo_new_ptr(gzt_button, gzgroup, NULL);
554
555 return ggd;
556 }
557
gizmo2d_resize_refresh(const bContext * C,wmGizmoGroup * gzgroup)558 static void gizmo2d_resize_refresh(const bContext *C, wmGizmoGroup *gzgroup)
559 {
560 GizmoGroup_Resize2D *ggd = gzgroup->customdata;
561 float origin[3];
562 const bool has_select = gizmo2d_calc_center(C, origin);
563
564 if (has_select == false) {
565 for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
566 ggd->gizmo_xy[i]->flag |= WM_GIZMO_HIDDEN;
567 }
568 }
569 else {
570 for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
571 ggd->gizmo_xy[i]->flag &= ~WM_GIZMO_HIDDEN;
572 }
573 copy_v2_v2(ggd->origin, origin);
574 }
575 }
576
gizmo2d_resize_draw_prepare(const bContext * C,wmGizmoGroup * gzgroup)577 static void gizmo2d_resize_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
578 {
579 ARegion *region = CTX_wm_region(C);
580 GizmoGroup_Resize2D *ggd = gzgroup->customdata;
581 float origin[3] = {UNPACK2(ggd->origin), 0.0f};
582
583 if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
584 Scene *scene = CTX_data_scene(C);
585 if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
586 gzgroup->use_fallback_keymap = true;
587 }
588 else {
589 gzgroup->use_fallback_keymap = false;
590 }
591 }
592
593 gizmo2d_origin_to_region(region, origin);
594
595 for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
596 wmGizmo *gz = ggd->gizmo_xy[i];
597 WM_gizmo_set_matrix_location(gz, origin);
598 }
599 }
600
gizmo2d_resize_setup(const bContext * UNUSED (C),wmGizmoGroup * gzgroup)601 static void gizmo2d_resize_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
602 {
603
604 wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_resize", true);
605 GizmoGroup_Resize2D *ggd = gizmogroup2d_resize_init(gzgroup);
606 gzgroup->customdata = ggd;
607
608 for (int i = 0; i < ARRAY_SIZE(ggd->gizmo_xy); i++) {
609 wmGizmo *gz = ggd->gizmo_xy[i];
610
611 /* custom handler! */
612 WM_gizmo_set_fn_custom_modal(gz, gizmo2d_modal);
613
614 if (i < 2) {
615 float color[4], color_hi[4];
616 gizmo2d_get_axis_color(i, color, color_hi);
617
618 /* set up widget data */
619 RNA_float_set(gz->ptr, "length", 1.0f);
620 float axis[3] = {0.0f};
621 axis[(i + 1) % 2] = 1.0f;
622 WM_gizmo_set_matrix_rotation_from_z_axis(gz, axis);
623
624 RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_ARROW_STYLE_BOX);
625
626 WM_gizmo_set_line_width(gz, GIZMO_AXIS_LINE_WIDTH);
627 WM_gizmo_set_color(gz, color);
628 WM_gizmo_set_color_highlight(gz, color_hi);
629
630 WM_gizmo_set_scale(gz, 1.0f);
631 }
632 else {
633 float color[4], color_hi[4];
634 UI_GetThemeColor4fv(TH_GIZMO_VIEW_ALIGN, color);
635 copy_v4_v4(color_hi, color);
636 color[3] *= 0.6f;
637
638 PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
639 RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
640
641 RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
642 /* Make the center low alpha. */
643 WM_gizmo_set_line_width(gz, 2.0f);
644 RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
645 WM_gizmo_set_color(gz, color);
646 WM_gizmo_set_color_highlight(gz, color_hi);
647
648 WM_gizmo_set_scale(gz, 1.2f);
649 }
650
651 /* Assign operator. */
652 PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_resize, NULL);
653 if (i < 2) {
654 bool constraint[3] = {0};
655 constraint[(i + 1) % 2] = 1;
656 if (RNA_struct_find_property(ptr, "constraint_axis")) {
657 RNA_boolean_set_array(ptr, "constraint_axis", constraint);
658 }
659 }
660 RNA_boolean_set(ptr, "release_confirm", true);
661 }
662 }
663
gizmo2d_resize_message_subscribe(const struct bContext * C,struct wmGizmoGroup * gzgroup,struct wmMsgBus * mbus)664 static void gizmo2d_resize_message_subscribe(const struct bContext *C,
665 struct wmGizmoGroup *gzgroup,
666 struct wmMsgBus *mbus)
667 {
668 bScreen *screen = CTX_wm_screen(C);
669 ScrArea *area = CTX_wm_area(C);
670 ARegion *region = CTX_wm_region(C);
671 gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
672 }
673
ED_widgetgroup_gizmo2d_resize_callbacks_set(wmGizmoGroupType * gzgt)674 void ED_widgetgroup_gizmo2d_resize_callbacks_set(wmGizmoGroupType *gzgt)
675 {
676 gzgt->poll = gizmo2d_generic_poll;
677 gzgt->setup = gizmo2d_resize_setup;
678 gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
679 gzgt->refresh = gizmo2d_resize_refresh;
680 gzgt->draw_prepare = gizmo2d_resize_draw_prepare;
681 gzgt->message_subscribe = gizmo2d_resize_message_subscribe;
682 }
683
684 /** \} */
685
686 /* -------------------------------------------------------------------- */
687 /** \name Rotate Handles
688 *
689 * Defines public functions, not the gizmo itself:
690 *
691 * - #ED_widgetgroup_gizmo2d_rotate_setup
692 *
693 * \{ */
694
695 typedef struct GizmoGroup_Rotate2D {
696 wmGizmo *gizmo;
697 float origin[2];
698 } GizmoGroup_Rotate2D;
699
gizmogroup2d_rotate_init(wmGizmoGroup * gzgroup)700 static GizmoGroup_Rotate2D *gizmogroup2d_rotate_init(wmGizmoGroup *gzgroup)
701 {
702 const wmGizmoType *gzt_button = WM_gizmotype_find("GIZMO_GT_button_2d", true);
703
704 GizmoGroup_Rotate2D *ggd = MEM_callocN(sizeof(GizmoGroup_Rotate2D), __func__);
705
706 ggd->gizmo = WM_gizmo_new_ptr(gzt_button, gzgroup, NULL);
707
708 return ggd;
709 }
710
gizmo2d_rotate_refresh(const bContext * C,wmGizmoGroup * gzgroup)711 static void gizmo2d_rotate_refresh(const bContext *C, wmGizmoGroup *gzgroup)
712 {
713 GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
714 float origin[3];
715 const bool has_select = gizmo2d_calc_center(C, origin);
716
717 if (has_select == false) {
718 ggd->gizmo->flag |= WM_GIZMO_HIDDEN;
719 }
720 else {
721 ggd->gizmo->flag &= ~WM_GIZMO_HIDDEN;
722 copy_v2_v2(ggd->origin, origin);
723 }
724 }
725
gizmo2d_rotate_draw_prepare(const bContext * C,wmGizmoGroup * gzgroup)726 static void gizmo2d_rotate_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup)
727 {
728 ARegion *region = CTX_wm_region(C);
729 GizmoGroup_Rotate2D *ggd = gzgroup->customdata;
730 float origin[3] = {UNPACK2(ggd->origin), 0.0f};
731
732 if (gzgroup->type->flag & WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP) {
733 Scene *scene = CTX_data_scene(C);
734 if (scene->toolsettings->workspace_tool_type == SCE_WORKSPACE_TOOL_FALLBACK) {
735 gzgroup->use_fallback_keymap = true;
736 }
737 else {
738 gzgroup->use_fallback_keymap = false;
739 }
740 }
741
742 gizmo2d_origin_to_region(region, origin);
743
744 wmGizmo *gz = ggd->gizmo;
745 WM_gizmo_set_matrix_location(gz, origin);
746 }
747
gizmo2d_rotate_setup(const bContext * UNUSED (C),wmGizmoGroup * gzgroup)748 static void gizmo2d_rotate_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup)
749 {
750
751 wmOperatorType *ot_resize = WM_operatortype_find("TRANSFORM_OT_rotate", true);
752 GizmoGroup_Rotate2D *ggd = gizmogroup2d_rotate_init(gzgroup);
753 gzgroup->customdata = ggd;
754
755 /* Other setup functions iterate over axis. */
756 {
757 wmGizmo *gz = ggd->gizmo;
758
759 /* custom handler! */
760 WM_gizmo_set_fn_custom_modal(gz, gizmo2d_modal);
761 WM_gizmo_set_scale(gz, 1.2f);
762
763 {
764 float color[4];
765 UI_GetThemeColor4fv(TH_GIZMO_VIEW_ALIGN, color);
766
767 PropertyRNA *prop = RNA_struct_find_property(gz->ptr, "icon");
768 RNA_property_enum_set(gz->ptr, prop, ICON_NONE);
769
770 RNA_enum_set(gz->ptr, "draw_options", ED_GIZMO_BUTTON_SHOW_BACKDROP);
771 /* Make the center low alpha. */
772 WM_gizmo_set_line_width(gz, 2.0f);
773 RNA_float_set(gz->ptr, "backdrop_fill_alpha", 0.0);
774 WM_gizmo_set_color(gz, color);
775 WM_gizmo_set_color_highlight(gz, color);
776 }
777
778 /* Assign operator. */
779 PointerRNA *ptr = WM_gizmo_operator_set(gz, 0, ot_resize, NULL);
780 RNA_boolean_set(ptr, "release_confirm", true);
781 }
782 }
783
gizmo2d_rotate_message_subscribe(const struct bContext * C,struct wmGizmoGroup * gzgroup,struct wmMsgBus * mbus)784 static void gizmo2d_rotate_message_subscribe(const struct bContext *C,
785 struct wmGizmoGroup *gzgroup,
786 struct wmMsgBus *mbus)
787 {
788 bScreen *screen = CTX_wm_screen(C);
789 ScrArea *area = CTX_wm_area(C);
790 ARegion *region = CTX_wm_region(C);
791 gizmo2d_pivot_point_message_subscribe(gzgroup, mbus, screen, area, region);
792 }
793
ED_widgetgroup_gizmo2d_rotate_callbacks_set(wmGizmoGroupType * gzgt)794 void ED_widgetgroup_gizmo2d_rotate_callbacks_set(wmGizmoGroupType *gzgt)
795 {
796 gzgt->poll = gizmo2d_generic_poll;
797 gzgt->setup = gizmo2d_rotate_setup;
798 gzgt->setup_keymap = WM_gizmogroup_setup_keymap_generic_maybe_drag;
799 gzgt->refresh = gizmo2d_rotate_refresh;
800 gzgt->draw_prepare = gizmo2d_rotate_draw_prepare;
801 gzgt->message_subscribe = gizmo2d_rotate_message_subscribe;
802 }
803
804 /** \} */
805