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 
21 #include "MEM_guardedalloc.h"
22 
23 #include "DNA_object_types.h"
24 #include "DNA_scene_types.h"
25 
26 #include "BLI_math.h"
27 #include "BLI_utildefines.h"
28 
29 #include "BLT_translation.h"
30 
31 #include "BKE_context.h"
32 #include "BKE_editmesh.h"
33 #include "BKE_global.h"
34 #include "BKE_report.h"
35 #include "BKE_scene.h"
36 
37 #include "RNA_access.h"
38 #include "RNA_define.h"
39 #include "RNA_enum_types.h"
40 
41 #include "WM_api.h"
42 #include "WM_message.h"
43 #include "WM_toolsystem.h"
44 #include "WM_types.h"
45 
46 #include "UI_interface.h"
47 #include "UI_resources.h"
48 
49 #include "ED_screen.h"
50 /* for USE_LOOPSLIDE_HACK only */
51 #include "ED_mesh.h"
52 
53 #include "transform.h"
54 #include "transform_convert.h"
55 
56 typedef struct TransformModeItem {
57   const char *idname;
58   int mode;
59   void (*opfunc)(wmOperatorType *);
60 } TransformModeItem;
61 
62 static const float VecOne[3] = {1, 1, 1};
63 
64 static const char OP_TRANSLATION[] = "TRANSFORM_OT_translate";
65 static const char OP_ROTATION[] = "TRANSFORM_OT_rotate";
66 static const char OP_TOSPHERE[] = "TRANSFORM_OT_tosphere";
67 static const char OP_RESIZE[] = "TRANSFORM_OT_resize";
68 static const char OP_SKIN_RESIZE[] = "TRANSFORM_OT_skin_resize";
69 static const char OP_SHEAR[] = "TRANSFORM_OT_shear";
70 static const char OP_BEND[] = "TRANSFORM_OT_bend";
71 static const char OP_SHRINK_FATTEN[] = "TRANSFORM_OT_shrink_fatten";
72 static const char OP_PUSH_PULL[] = "TRANSFORM_OT_push_pull";
73 static const char OP_TILT[] = "TRANSFORM_OT_tilt";
74 static const char OP_TRACKBALL[] = "TRANSFORM_OT_trackball";
75 static const char OP_MIRROR[] = "TRANSFORM_OT_mirror";
76 static const char OP_BONE_SIZE[] = "TRANSFORM_OT_bbone_resize";
77 static const char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide";
78 static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide";
79 static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease";
80 static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight";
81 static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide";
82 static const char OP_NORMAL_ROTATION[] = "TRANSFORM_OT_rotate_normal";
83 
84 static void TRANSFORM_OT_translate(struct wmOperatorType *ot);
85 static void TRANSFORM_OT_rotate(struct wmOperatorType *ot);
86 static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot);
87 static void TRANSFORM_OT_resize(struct wmOperatorType *ot);
88 static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot);
89 static void TRANSFORM_OT_shear(struct wmOperatorType *ot);
90 static void TRANSFORM_OT_bend(struct wmOperatorType *ot);
91 static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot);
92 static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot);
93 static void TRANSFORM_OT_tilt(struct wmOperatorType *ot);
94 static void TRANSFORM_OT_trackball(struct wmOperatorType *ot);
95 static void TRANSFORM_OT_mirror(struct wmOperatorType *ot);
96 static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot);
97 static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot);
98 static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot);
99 static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot);
100 static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot);
101 static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot);
102 static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot);
103 
104 static TransformModeItem transform_modes[] = {
105     {OP_TRANSLATION, TFM_TRANSLATION, TRANSFORM_OT_translate},
106     {OP_ROTATION, TFM_ROTATION, TRANSFORM_OT_rotate},
107     {OP_TOSPHERE, TFM_TOSPHERE, TRANSFORM_OT_tosphere},
108     {OP_RESIZE, TFM_RESIZE, TRANSFORM_OT_resize},
109     {OP_SKIN_RESIZE, TFM_SKIN_RESIZE, TRANSFORM_OT_skin_resize},
110     {OP_SHEAR, TFM_SHEAR, TRANSFORM_OT_shear},
111     {OP_BEND, TFM_BEND, TRANSFORM_OT_bend},
112     {OP_SHRINK_FATTEN, TFM_SHRINKFATTEN, TRANSFORM_OT_shrink_fatten},
113     {OP_PUSH_PULL, TFM_PUSHPULL, TRANSFORM_OT_push_pull},
114     {OP_TILT, TFM_TILT, TRANSFORM_OT_tilt},
115     {OP_TRACKBALL, TFM_TRACKBALL, TRANSFORM_OT_trackball},
116     {OP_MIRROR, TFM_MIRROR, TRANSFORM_OT_mirror},
117     {OP_BONE_SIZE, TFM_BONESIZE, TRANSFORM_OT_bbone_resize},
118     {OP_EDGE_SLIDE, TFM_EDGE_SLIDE, TRANSFORM_OT_edge_slide},
119     {OP_VERT_SLIDE, TFM_VERT_SLIDE, TRANSFORM_OT_vert_slide},
120     {OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease},
121     {OP_EDGE_BWEIGHT, TFM_BWEIGHT, TRANSFORM_OT_edge_bevelweight},
122     {OP_SEQ_SLIDE, TFM_SEQ_SLIDE, TRANSFORM_OT_seq_slide},
123     {OP_NORMAL_ROTATION, TFM_NORMAL_ROTATION, TRANSFORM_OT_rotate_normal},
124     {NULL, 0},
125 };
126 
127 const EnumPropertyItem rna_enum_transform_mode_types[] = {
128     {TFM_INIT, "INIT", 0, "Init", ""},
129     {TFM_DUMMY, "DUMMY", 0, "Dummy", ""},
130     {TFM_TRANSLATION, "TRANSLATION", 0, "Translation", ""},
131     {TFM_ROTATION, "ROTATION", 0, "Rotation", ""},
132     {TFM_RESIZE, "RESIZE", 0, "Resize", ""},
133     {TFM_SKIN_RESIZE, "SKIN_RESIZE", 0, "Skin Resize", ""},
134     {TFM_TOSPHERE, "TOSPHERE", 0, "Tosphere", ""},
135     {TFM_SHEAR, "SHEAR", 0, "Shear", ""},
136     {TFM_BEND, "BEND", 0, "Bend", ""},
137     {TFM_SHRINKFATTEN, "SHRINKFATTEN", 0, "Shrinkfatten", ""},
138     {TFM_TILT, "TILT", 0, "Tilt", ""},
139     {TFM_TRACKBALL, "TRACKBALL", 0, "Trackball", ""},
140     {TFM_PUSHPULL, "PUSHPULL", 0, "Pushpull", ""},
141     {TFM_CREASE, "CREASE", 0, "Crease", ""},
142     {TFM_MIRROR, "MIRROR", 0, "Mirror", ""},
143     {TFM_BONESIZE, "BONE_SIZE", 0, "Bonesize", ""},
144     {TFM_BONE_ENVELOPE, "BONE_ENVELOPE", 0, "Bone Envelope", ""},
145     {TFM_BONE_ENVELOPE_DIST, "BONE_ENVELOPE_DIST", 0, "Bone Envelope Distance", ""},
146     {TFM_CURVE_SHRINKFATTEN, "CURVE_SHRINKFATTEN", 0, "Curve Shrinkfatten", ""},
147     {TFM_MASK_SHRINKFATTEN, "MASK_SHRINKFATTEN", 0, "Mask Shrinkfatten", ""},
148     {TFM_GPENCIL_SHRINKFATTEN, "GPENCIL_SHRINKFATTEN", 0, "GPencil Shrinkfatten", ""},
149     {TFM_BONE_ROLL, "BONE_ROLL", 0, "Bone Roll", ""},
150     {TFM_TIME_TRANSLATE, "TIME_TRANSLATE", 0, "Time Translate", ""},
151     {TFM_TIME_SLIDE, "TIME_SLIDE", 0, "Time Slide", ""},
152     {TFM_TIME_SCALE, "TIME_SCALE", 0, "Time Scale", ""},
153     {TFM_TIME_EXTEND, "TIME_EXTEND", 0, "Time Extend", ""},
154     {TFM_BAKE_TIME, "BAKE_TIME", 0, "Bake Time", ""},
155     {TFM_BWEIGHT, "BWEIGHT", 0, "Bweight", ""},
156     {TFM_ALIGN, "ALIGN", 0, "Align", ""},
157     {TFM_EDGE_SLIDE, "EDGESLIDE", 0, "Edge Slide", ""},
158     {TFM_SEQ_SLIDE, "SEQSLIDE", 0, "Sequence Slide", ""},
159     {TFM_GPENCIL_OPACITY, "GPENCIL_OPACITY", 0, "GPencil Opacity", ""},
160     {0, NULL, 0, NULL, NULL},
161 };
162 
select_orientation_exec(bContext * C,wmOperator * op)163 static int select_orientation_exec(bContext *C, wmOperator *op)
164 {
165   Scene *scene = CTX_data_scene(C);
166   View3D *v3d = CTX_wm_view3d(C);
167 
168   int orientation = RNA_enum_get(op->ptr, "orientation");
169 
170   BKE_scene_orientation_slot_set_index(&scene->orientation_slots[SCE_ORIENT_DEFAULT], orientation);
171 
172   WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL);
173   WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
174 
175   struct wmMsgBus *mbus = CTX_wm_message_bus(C);
176   WM_msg_publish_rna_prop(mbus, &scene->id, scene, TransformOrientationSlot, type);
177 
178   return OPERATOR_FINISHED;
179 }
180 
select_orientation_invoke(bContext * C,wmOperator * UNUSED (op),const wmEvent * UNUSED (event))181 static int select_orientation_invoke(bContext *C,
182                                      wmOperator *UNUSED(op),
183                                      const wmEvent *UNUSED(event))
184 {
185   uiPopupMenu *pup;
186   uiLayout *layout;
187 
188   pup = UI_popup_menu_begin(C, IFACE_("Orientation"), ICON_NONE);
189   layout = UI_popup_menu_layout(pup);
190   uiItemsEnumO(layout, "TRANSFORM_OT_select_orientation", "orientation");
191   UI_popup_menu_end(C, pup);
192 
193   return OPERATOR_INTERFACE;
194 }
195 
TRANSFORM_OT_select_orientation(struct wmOperatorType * ot)196 static void TRANSFORM_OT_select_orientation(struct wmOperatorType *ot)
197 {
198   PropertyRNA *prop;
199 
200   /* identifiers */
201   ot->name = "Select Orientation";
202   ot->description = "Select transformation orientation";
203   ot->idname = "TRANSFORM_OT_select_orientation";
204   ot->flag = OPTYPE_UNDO;
205 
206   /* api callbacks */
207   ot->invoke = select_orientation_invoke;
208   ot->exec = select_orientation_exec;
209   ot->poll = ED_operator_view3d_active;
210 
211   prop = RNA_def_property(ot->srna, "orientation", PROP_ENUM, PROP_NONE);
212   RNA_def_property_ui_text(prop, "Orientation", "Transformation orientation");
213   RNA_def_enum_funcs(prop, rna_TransformOrientation_itemf);
214 }
215 
delete_orientation_exec(bContext * C,wmOperator * UNUSED (op))216 static int delete_orientation_exec(bContext *C, wmOperator *UNUSED(op))
217 {
218   Scene *scene = CTX_data_scene(C);
219   BIF_removeTransformOrientationIndex(C,
220                                       scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom);
221 
222   WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
223 
224   struct wmMsgBus *mbus = CTX_wm_message_bus(C);
225   WM_msg_publish_rna_prop(mbus, &scene->id, scene, Scene, transform_orientation_slots);
226 
227   return OPERATOR_FINISHED;
228 }
229 
delete_orientation_invoke(bContext * C,wmOperator * op,const wmEvent * UNUSED (event))230 static int delete_orientation_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
231 {
232   return delete_orientation_exec(C, op);
233 }
234 
delete_orientation_poll(bContext * C)235 static bool delete_orientation_poll(bContext *C)
236 {
237   if (ED_operator_areaactive(C) == 0) {
238     return 0;
239   }
240 
241   Scene *scene = CTX_data_scene(C);
242   return ((scene->orientation_slots[SCE_ORIENT_DEFAULT].type >= V3D_ORIENT_CUSTOM) &&
243           (scene->orientation_slots[SCE_ORIENT_DEFAULT].index_custom != -1));
244 }
245 
TRANSFORM_OT_delete_orientation(struct wmOperatorType * ot)246 static void TRANSFORM_OT_delete_orientation(struct wmOperatorType *ot)
247 {
248   /* identifiers */
249   ot->name = "Delete Orientation";
250   ot->description = "Delete transformation orientation";
251   ot->idname = "TRANSFORM_OT_delete_orientation";
252   ot->flag = OPTYPE_UNDO;
253 
254   /* api callbacks */
255   ot->invoke = delete_orientation_invoke;
256   ot->exec = delete_orientation_exec;
257   ot->poll = delete_orientation_poll;
258 }
259 
create_orientation_exec(bContext * C,wmOperator * op)260 static int create_orientation_exec(bContext *C, wmOperator *op)
261 {
262   char name[MAX_NAME];
263   const bool use = RNA_boolean_get(op->ptr, "use");
264   const bool overwrite = RNA_boolean_get(op->ptr, "overwrite");
265   const bool use_view = RNA_boolean_get(op->ptr, "use_view");
266   View3D *v3d = CTX_wm_view3d(C);
267   Scene *scene = CTX_data_scene(C);
268 
269   RNA_string_get(op->ptr, "name", name);
270 
271   if (use && !v3d) {
272     BKE_report(op->reports,
273                RPT_ERROR,
274                "Create Orientation's 'use' parameter only valid in a 3DView context");
275     return OPERATOR_CANCELLED;
276   }
277 
278   if (!BIF_createTransformOrientation(C, op->reports, name, use_view, use, overwrite)) {
279     BKE_report(op->reports, RPT_ERROR, "Unable to create orientation");
280     return OPERATOR_CANCELLED;
281   }
282 
283   if (use) {
284     struct wmMsgBus *mbus = CTX_wm_message_bus(C);
285     WM_msg_publish_rna_prop(mbus, &scene->id, scene, Scene, transform_orientation_slots);
286     WM_event_add_notifier(C, NC_SCENE | NA_EDITED, scene);
287   }
288 
289   WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, v3d);
290 
291   return OPERATOR_FINISHED;
292 }
293 
TRANSFORM_OT_create_orientation(struct wmOperatorType * ot)294 static void TRANSFORM_OT_create_orientation(struct wmOperatorType *ot)
295 {
296   /* identifiers */
297   ot->name = "Create Orientation";
298   ot->description = "Create transformation orientation from selection";
299   ot->idname = "TRANSFORM_OT_create_orientation";
300   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
301 
302   /* api callbacks */
303   ot->exec = create_orientation_exec;
304   ot->poll = ED_operator_areaactive;
305 
306   RNA_def_string(ot->srna, "name", NULL, MAX_NAME, "Name", "Name of the new custom orientation");
307   RNA_def_boolean(
308       ot->srna,
309       "use_view",
310       false,
311       "Use View",
312       "Use the current view instead of the active object to create the new orientation");
313 
314   WM_operatortype_props_advanced_begin(ot);
315 
316   RNA_def_boolean(
317       ot->srna, "use", false, "Use After Creation", "Select orientation after its creation");
318   RNA_def_boolean(ot->srna,
319                   "overwrite",
320                   false,
321                   "Overwrite Previous",
322                   "Overwrite previously created orientation with same name");
323 }
324 
325 #ifdef USE_LOOPSLIDE_HACK
326 /**
327  * Special hack for MESH_OT_loopcut_slide so we get back to the selection mode
328  */
transformops_loopsel_hack(bContext * C,wmOperator * op)329 static void transformops_loopsel_hack(bContext *C, wmOperator *op)
330 {
331   if (op->type->idname == OP_EDGE_SLIDE) {
332     if (op->opm && op->opm->opm && op->opm->opm->prev) {
333       wmOperator *op_prev = op->opm->opm->prev;
334       Scene *scene = CTX_data_scene(C);
335       bool mesh_select_mode[3];
336       PropertyRNA *prop = RNA_struct_find_property(op_prev->ptr, "mesh_select_mode_init");
337 
338       if (prop && RNA_property_is_set(op_prev->ptr, prop)) {
339         ToolSettings *ts = scene->toolsettings;
340         short selectmode_orig;
341 
342         RNA_property_boolean_get_array(op_prev->ptr, prop, mesh_select_mode);
343         selectmode_orig = ((mesh_select_mode[0] ? SCE_SELECT_VERTEX : 0) |
344                            (mesh_select_mode[1] ? SCE_SELECT_EDGE : 0) |
345                            (mesh_select_mode[2] ? SCE_SELECT_FACE : 0));
346 
347         /* still switch if we were originally in face select mode */
348         if ((ts->selectmode != selectmode_orig) && (selectmode_orig != SCE_SELECT_FACE)) {
349           Object *obedit = CTX_data_edit_object(C);
350           BMEditMesh *em = BKE_editmesh_from_object(obedit);
351           em->selectmode = ts->selectmode = selectmode_orig;
352           EDBM_selectmode_set(em);
353         }
354       }
355     }
356   }
357 }
358 #else
359 /* prevent removal by cleanup */
360 #  error "loopslide hack removed!"
361 #endif /* USE_LOOPSLIDE_HACK */
362 
transformops_exit(bContext * C,wmOperator * op)363 static void transformops_exit(bContext *C, wmOperator *op)
364 {
365 #ifdef USE_LOOPSLIDE_HACK
366   transformops_loopsel_hack(C, op);
367 #endif
368 
369   saveTransform(C, op->customdata, op);
370   MEM_freeN(op->customdata);
371   op->customdata = NULL;
372   G.moving = 0;
373 }
374 
transformops_data(bContext * C,wmOperator * op,const wmEvent * event)375 static int transformops_data(bContext *C, wmOperator *op, const wmEvent *event)
376 {
377   int retval = 1;
378   if (op->customdata == NULL) {
379     TransInfo *t = MEM_callocN(sizeof(TransInfo), "TransInfo data2");
380     TransformModeItem *tmode;
381     int mode = -1;
382 
383     for (tmode = transform_modes; tmode->idname; tmode++) {
384       if (op->type->idname == tmode->idname) {
385         mode = tmode->mode;
386         break;
387       }
388     }
389 
390     if (mode == -1) {
391       mode = RNA_enum_get(op->ptr, "mode");
392     }
393 
394     retval = initTransform(C, t, op, event, mode);
395 
396     /* store data */
397     if (retval) {
398       G.moving = special_transform_moving(t);
399       op->customdata = t;
400     }
401     else {
402       MEM_freeN(t);
403     }
404   }
405 
406   return retval; /* return 0 on error */
407 }
408 
transform_modal(bContext * C,wmOperator * op,const wmEvent * event)409 static int transform_modal(bContext *C, wmOperator *op, const wmEvent *event)
410 {
411   int exit_code;
412 
413   TransInfo *t = op->customdata;
414   const enum TfmMode mode_prev = t->mode;
415 
416 #if defined(WITH_INPUT_NDOF) && 0
417   /* Stable 2D mouse coords map to different 3D coords while the 3D mouse is active
418    * in other words, 2D deltas are no longer good enough!
419    * disable until individual 'transformers' behave better. */
420 
421   if (event->type == NDOF_MOTION) {
422     return OPERATOR_PASS_THROUGH;
423   }
424 #endif
425 
426   /* XXX insert keys are called here, and require context */
427   t->context = C;
428   exit_code = transformEvent(t, event);
429   t->context = NULL;
430 
431   /* XXX, workaround: active needs to be calculated before transforming,
432    * since we're not reading from 'td->center' in this case. see: T40241 */
433   if (t->tsnap.target == SCE_SNAP_TARGET_ACTIVE) {
434     /* In camera view, tsnap callback is not set
435      * (see initSnappingMode() in transfrom_snap.c, and T40348). */
436     if (t->tsnap.targetSnap && ((t->tsnap.status & TARGET_INIT) == 0)) {
437       t->tsnap.targetSnap(t);
438     }
439   }
440 
441   transformApply(C, t);
442 
443   exit_code |= transformEnd(C, t);
444 
445   if ((exit_code & OPERATOR_RUNNING_MODAL) == 0) {
446     transformops_exit(C, op);
447     exit_code &= ~OPERATOR_PASS_THROUGH; /* preventively remove passthrough */
448   }
449   else {
450     if (mode_prev != t->mode) {
451       /* WARNING: this is not normal to switch operator types
452        * normally it would not be supported but transform happens
453        * to share callbacks between different operators. */
454       wmOperatorType *ot_new = NULL;
455       TransformModeItem *item = transform_modes;
456       while (item->idname) {
457         if (item->mode == t->mode) {
458           ot_new = WM_operatortype_find(item->idname, false);
459           break;
460         }
461         item++;
462       }
463 
464       BLI_assert(ot_new != NULL);
465       if (ot_new) {
466         WM_operator_type_set(op, ot_new);
467       }
468       /* end suspicious code */
469     }
470   }
471 
472   return exit_code;
473 }
474 
transform_cancel(bContext * C,wmOperator * op)475 static void transform_cancel(bContext *C, wmOperator *op)
476 {
477   TransInfo *t = op->customdata;
478 
479   t->state = TRANS_CANCEL;
480   transformEnd(C, t);
481   transformops_exit(C, op);
482 }
483 
transform_exec(bContext * C,wmOperator * op)484 static int transform_exec(bContext *C, wmOperator *op)
485 {
486   TransInfo *t;
487 
488   if (!transformops_data(C, op, NULL)) {
489     G.moving = 0;
490     return OPERATOR_CANCELLED;
491   }
492 
493   t = op->customdata;
494 
495   t->options |= CTX_AUTOCONFIRM;
496 
497   transformApply(C, t);
498 
499   transformEnd(C, t);
500 
501   transformops_exit(C, op);
502 
503   WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL);
504 
505   return OPERATOR_FINISHED;
506 }
507 
transform_invoke(bContext * C,wmOperator * op,const wmEvent * event)508 static int transform_invoke(bContext *C, wmOperator *op, const wmEvent *event)
509 {
510   if (!transformops_data(C, op, event)) {
511     G.moving = 0;
512     return OPERATOR_CANCELLED;
513   }
514 
515   /* When modal, allow 'value' to set initial offset. */
516   if ((event == NULL) && RNA_struct_property_is_set(op->ptr, "value")) {
517     return transform_exec(C, op);
518   }
519 
520   /* add temp handler */
521   WM_event_add_modal_handler(C, op);
522 
523   op->flag |= OP_IS_MODAL_GRAB_CURSOR; /* XXX maybe we want this with the gizmo only? */
524 
525   /* Use when modal input has some transformation to begin with. */
526   TransInfo *t = op->customdata;
527   if (UNLIKELY(!is_zero_v4(t->values_modal_offset))) {
528     transformApply(C, t);
529   }
530 
531   return OPERATOR_RUNNING_MODAL;
532 }
533 
transform_poll_property(const bContext * UNUSED (C),wmOperator * op,const PropertyRNA * prop)534 static bool transform_poll_property(const bContext *UNUSED(C),
535                                     wmOperator *op,
536                                     const PropertyRNA *prop)
537 {
538   const char *prop_id = RNA_property_identifier(prop);
539 
540   /* Orientation/Constraints. */
541   {
542     /* Hide orientation axis if no constraints are set, since it wont be used. */
543     PropertyRNA *prop_con = RNA_struct_find_property(op->ptr, "orient_type");
544     if (prop_con != NULL && (prop_con != prop)) {
545       if (STRPREFIX(prop_id, "constraint")) {
546 
547         /* Special case: show constraint axis if we don't have values,
548          * needed for mirror operator. */
549         if (STREQ(prop_id, "constraint_axis") &&
550             (RNA_struct_find_property(op->ptr, "value") == NULL)) {
551           return true;
552         }
553 
554         return false;
555       }
556     }
557   }
558 
559   /* Proportional Editing. */
560   {
561     PropertyRNA *prop_pet = RNA_struct_find_property(op->ptr, "use_proportional_edit");
562     if (prop_pet && (prop_pet != prop) && (RNA_property_boolean_get(op->ptr, prop_pet) == false)) {
563       if (STRPREFIX(prop_id, "proportional") || STRPREFIX(prop_id, "use_proportional")) {
564         return false;
565       }
566     }
567   }
568 
569   return true;
570 }
571 
Transform_Properties(struct wmOperatorType * ot,int flags)572 void Transform_Properties(struct wmOperatorType *ot, int flags)
573 {
574   PropertyRNA *prop;
575 
576   if (flags & P_ORIENT_AXIS) {
577     prop = RNA_def_property(ot->srna, "orient_axis", PROP_ENUM, PROP_NONE);
578     RNA_def_property_ui_text(prop, "Axis", "");
579     RNA_def_property_enum_default(prop, 2);
580     RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
581     RNA_def_property_flag(prop, PROP_SKIP_SAVE);
582   }
583   if (flags & P_ORIENT_AXIS_ORTHO) {
584     prop = RNA_def_property(ot->srna, "orient_axis_ortho", PROP_ENUM, PROP_NONE);
585     RNA_def_property_ui_text(prop, "Axis Ortho", "");
586     RNA_def_property_enum_default(prop, 0);
587     RNA_def_property_enum_items(prop, rna_enum_axis_xyz_items);
588     RNA_def_property_flag(prop, PROP_SKIP_SAVE);
589   }
590 
591   if (flags & P_ORIENT_MATRIX) {
592     prop = RNA_def_property(ot->srna, "orient_type", PROP_ENUM, PROP_NONE);
593     RNA_def_property_ui_text(prop, "Orientation", "Transformation orientation");
594     RNA_def_enum_funcs(prop, rna_TransformOrientation_itemf);
595 
596     /* Set by 'orient_type' or gizmo which acts on non-standard orientation. */
597     prop = RNA_def_float_matrix(
598         ot->srna, "orient_matrix", 3, 3, NULL, 0.0f, 0.0f, "Matrix", "", 0.0f, 0.0f);
599     RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
600 
601     /* Only use 'orient_matrix' when 'orient_matrix_type == orient_type',
602      * this allows us to reuse the orientation set by a gizmo for eg, without disabling the ability
603      * to switch over to other orientations. */
604     prop = RNA_def_property(ot->srna, "orient_matrix_type", PROP_ENUM, PROP_NONE);
605     RNA_def_property_ui_text(prop, "Matrix Orientation", "");
606     RNA_def_enum_funcs(prop, rna_TransformOrientation_itemf);
607     RNA_def_property_flag(prop, PROP_HIDDEN);
608   }
609 
610   if (flags & P_CONSTRAINT) {
611     RNA_def_boolean_vector(ot->srna, "constraint_axis", 3, NULL, "Constraint Axis", "");
612   }
613 
614   if (flags & P_MIRROR) {
615     prop = RNA_def_boolean(ot->srna, "mirror", 0, "Mirror Editing", "");
616     if (flags & P_MIRROR_DUMMY) {
617       /* only used so macros can disable this option */
618       RNA_def_property_flag(prop, PROP_HIDDEN);
619     }
620   }
621 
622   if (flags & P_PROPORTIONAL) {
623     RNA_def_boolean(ot->srna, "use_proportional_edit", 0, "Proportional Editing", "");
624     prop = RNA_def_enum(ot->srna,
625                         "proportional_edit_falloff",
626                         rna_enum_proportional_falloff_items,
627                         0,
628                         "Proportional Falloff",
629                         "Falloff type for proportional editing mode");
630     /* Abusing id_curve :/ */
631     RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE);
632     RNA_def_float(ot->srna,
633                   "proportional_size",
634                   1,
635                   T_PROP_SIZE_MIN,
636                   T_PROP_SIZE_MAX,
637                   "Proportional Size",
638                   "",
639                   0.001f,
640                   100.0f);
641 
642     RNA_def_boolean(ot->srna, "use_proportional_connected", 0, "Connected", "");
643     RNA_def_boolean(ot->srna, "use_proportional_projected", 0, "Projected (2D)", "");
644   }
645 
646   if (flags & P_SNAP) {
647     prop = RNA_def_boolean(ot->srna, "snap", 0, "Use Snapping Options", "");
648     RNA_def_property_flag(prop, PROP_HIDDEN);
649 
650     if (flags & P_GEO_SNAP) {
651       prop = RNA_def_enum(ot->srna, "snap_target", rna_enum_snap_target_items, 0, "Target", "");
652       RNA_def_property_flag(prop, PROP_HIDDEN);
653       prop = RNA_def_float_vector(
654           ot->srna, "snap_point", 3, NULL, -FLT_MAX, FLT_MAX, "Point", "", -FLT_MAX, FLT_MAX);
655       RNA_def_property_flag(prop, PROP_HIDDEN);
656 
657       if (flags & P_ALIGN_SNAP) {
658         prop = RNA_def_boolean(ot->srna, "snap_align", 0, "Align with Point Normal", "");
659         RNA_def_property_flag(prop, PROP_HIDDEN);
660         prop = RNA_def_float_vector(
661             ot->srna, "snap_normal", 3, NULL, -FLT_MAX, FLT_MAX, "Normal", "", -FLT_MAX, FLT_MAX);
662         RNA_def_property_flag(prop, PROP_HIDDEN);
663       }
664     }
665   }
666 
667   if (flags & P_GPENCIL_EDIT) {
668     prop = RNA_def_boolean(ot->srna,
669                            "gpencil_strokes",
670                            0,
671                            "Edit Grease Pencil",
672                            "Edit selected Grease Pencil strokes");
673     RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
674   }
675 
676   if (flags & P_CURSOR_EDIT) {
677     prop = RNA_def_boolean(ot->srna, "cursor_transform", 0, "Transform Cursor", "");
678     RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
679   }
680 
681   if ((flags & P_OPTIONS) && !(flags & P_NO_TEXSPACE)) {
682     prop = RNA_def_boolean(
683         ot->srna, "texture_space", 0, "Edit Texture Space", "Edit Object data texture space");
684     RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
685     prop = RNA_def_boolean(
686         ot->srna, "remove_on_cancel", 0, "Remove on Cancel", "Remove elements on cancel");
687     RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
688   }
689 
690   if (flags & P_CORRECT_UV) {
691     RNA_def_boolean(
692         ot->srna, "correct_uv", true, "Correct UVs", "Correct UV coordinates when transforming");
693   }
694 
695   if (flags & P_CENTER) {
696     /* For gizmos that define their own center. */
697     prop = RNA_def_property(ot->srna, "center_override", PROP_FLOAT, PROP_XYZ);
698     RNA_def_property_array(prop, 3);
699     RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
700     RNA_def_property_ui_text(prop, "Center Override", "Force using this center value (when set)");
701   }
702 
703   if ((flags & P_NO_DEFAULTS) == 0) {
704     prop = RNA_def_boolean(ot->srna,
705                            "release_confirm",
706                            0,
707                            "Confirm on Release",
708                            "Always confirm operation when releasing button");
709     RNA_def_property_flag(prop, PROP_HIDDEN);
710 
711     prop = RNA_def_boolean(ot->srna, "use_accurate", 0, "Accurate", "Use accurate transformation");
712     RNA_def_property_flag(prop, PROP_HIDDEN);
713   }
714 
715   if (flags & P_POST_TRANSFORM) {
716     prop = RNA_def_boolean(ot->srna,
717                            "use_automerge_and_split",
718                            0,
719                            "Auto Merge & Split",
720                            "Forces the use of Auto Merge & Split");
721     RNA_def_property_flag(prop, PROP_HIDDEN);
722   }
723 }
724 
TRANSFORM_OT_translate(struct wmOperatorType * ot)725 static void TRANSFORM_OT_translate(struct wmOperatorType *ot)
726 {
727   /* identifiers */
728   ot->name = "Move";
729   ot->description = "Move selected items";
730   ot->idname = OP_TRANSLATION;
731   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
732 
733   /* api callbacks */
734   ot->invoke = transform_invoke;
735   ot->exec = transform_exec;
736   ot->modal = transform_modal;
737   ot->cancel = transform_cancel;
738   ot->poll = ED_operator_screenactive;
739   ot->poll_property = transform_poll_property;
740 
741   RNA_def_float_translation(
742       ot->srna, "value", 3, NULL, -FLT_MAX, FLT_MAX, "Move", "", -FLT_MAX, FLT_MAX);
743 
744   WM_operatortype_props_advanced_begin(ot);
745 
746   Transform_Properties(ot,
747                        P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP |
748                            P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_POST_TRANSFORM);
749 }
750 
TRANSFORM_OT_resize(struct wmOperatorType * ot)751 static void TRANSFORM_OT_resize(struct wmOperatorType *ot)
752 {
753   /* identifiers */
754   ot->name = "Resize";
755   ot->description = "Scale (resize) selected items";
756   ot->idname = OP_RESIZE;
757   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
758 
759   /* api callbacks */
760   ot->invoke = transform_invoke;
761   ot->exec = transform_exec;
762   ot->modal = transform_modal;
763   ot->cancel = transform_cancel;
764   ot->poll = ED_operator_screenactive;
765   ot->poll_property = transform_poll_property;
766 
767   RNA_def_float_vector(
768       ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Scale", "", -FLT_MAX, FLT_MAX);
769 
770   WM_operatortype_props_advanced_begin(ot);
771 
772   Transform_Properties(ot,
773                        P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP |
774                            P_OPTIONS | P_GPENCIL_EDIT | P_CENTER);
775 }
776 
TRANSFORM_OT_skin_resize(struct wmOperatorType * ot)777 static void TRANSFORM_OT_skin_resize(struct wmOperatorType *ot)
778 {
779   /* identifiers */
780   ot->name = "Skin Resize";
781   ot->description = "Scale selected vertices' skin radii";
782   ot->idname = OP_SKIN_RESIZE;
783   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
784 
785   /* api callbacks */
786   ot->invoke = transform_invoke;
787   ot->exec = transform_exec;
788   ot->modal = transform_modal;
789   ot->cancel = transform_cancel;
790   ot->poll = ED_operator_editmesh;
791   ot->poll_property = transform_poll_property;
792 
793   RNA_def_float_vector(
794       ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Scale", "", -FLT_MAX, FLT_MAX);
795 
796   WM_operatortype_props_advanced_begin(ot);
797 
798   Transform_Properties(ot,
799                        P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_GEO_SNAP |
800                            P_OPTIONS | P_NO_TEXSPACE);
801 }
802 
TRANSFORM_OT_trackball(struct wmOperatorType * ot)803 static void TRANSFORM_OT_trackball(struct wmOperatorType *ot)
804 {
805   /* identifiers */
806   ot->name = "Trackball";
807   ot->description = "Trackball style rotation of selected items";
808   ot->idname = OP_TRACKBALL;
809   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
810 
811   /* api callbacks */
812   ot->invoke = transform_invoke;
813   ot->exec = transform_exec;
814   ot->modal = transform_modal;
815   ot->cancel = transform_cancel;
816   ot->poll = ED_operator_screenactive;
817   ot->poll_property = transform_poll_property;
818 
819   /* Maybe we could use float_vector_xyz here too? */
820   RNA_def_float_rotation(
821       ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -FLT_MAX, FLT_MAX);
822 
823   WM_operatortype_props_advanced_begin(ot);
824 
825   Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
826 }
827 
TRANSFORM_OT_rotate(struct wmOperatorType * ot)828 static void TRANSFORM_OT_rotate(struct wmOperatorType *ot)
829 {
830   /* identifiers */
831   ot->name = "Rotate";
832   ot->description = "Rotate selected items";
833   ot->idname = OP_ROTATION;
834   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
835 
836   /* api callbacks */
837   ot->invoke = transform_invoke;
838   ot->exec = transform_exec;
839   ot->modal = transform_modal;
840   ot->cancel = transform_cancel;
841   ot->poll = ED_operator_screenactive;
842   ot->poll_property = transform_poll_property;
843 
844   RNA_def_float_rotation(
845       ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
846 
847   WM_operatortype_props_advanced_begin(ot);
848 
849   Transform_Properties(ot,
850                        P_ORIENT_AXIS | P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR |
851                            P_GEO_SNAP | P_GPENCIL_EDIT | P_CENTER);
852 }
853 
TRANSFORM_OT_tilt(struct wmOperatorType * ot)854 static void TRANSFORM_OT_tilt(struct wmOperatorType *ot)
855 {
856   /* identifiers */
857   ot->name = "Tilt";
858   /* optional -
859    * "Tilt selected vertices"
860    * "Specify an extra axis rotation for selected vertices of 3D curve" */
861   ot->description = "Tilt selected control vertices of 3D curve";
862   ot->idname = OP_TILT;
863   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
864 
865   /* api callbacks */
866   ot->invoke = transform_invoke;
867   ot->exec = transform_exec;
868   ot->modal = transform_modal;
869   ot->cancel = transform_cancel;
870   ot->poll = ED_operator_editcurve_3d;
871   ot->poll_property = transform_poll_property;
872 
873   RNA_def_float_rotation(
874       ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
875 
876   WM_operatortype_props_advanced_begin(ot);
877 
878   Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
879 }
880 
TRANSFORM_OT_bend(struct wmOperatorType * ot)881 static void TRANSFORM_OT_bend(struct wmOperatorType *ot)
882 {
883   /* identifiers */
884   ot->name = "Bend";
885   ot->description = "Bend selected items between the 3D cursor and the mouse";
886   ot->idname = OP_BEND;
887   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
888 
889   /* api callbacks */
890   ot->invoke = transform_invoke;
891   // ot->exec = transform_exec; /* unsupported */
892   ot->modal = transform_modal;
893   ot->cancel = transform_cancel;
894   ot->poll = ED_operator_region_view3d_active;
895   ot->poll_property = transform_poll_property;
896 
897   RNA_def_float_rotation(
898       ot->srna, "value", 1, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
899 
900   WM_operatortype_props_advanced_begin(ot);
901 
902   Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
903 }
904 
transform_shear_poll(bContext * C)905 static bool transform_shear_poll(bContext *C)
906 {
907   if (!ED_operator_screenactive(C)) {
908     return false;
909   }
910 
911   ScrArea *area = CTX_wm_area(C);
912   return area && !ELEM(area->spacetype, SPACE_ACTION);
913 }
914 
TRANSFORM_OT_shear(struct wmOperatorType * ot)915 static void TRANSFORM_OT_shear(struct wmOperatorType *ot)
916 {
917   /* identifiers */
918   ot->name = "Shear";
919   ot->description = "Shear selected items along the horizontal screen axis";
920   ot->idname = OP_SHEAR;
921   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
922 
923   /* api callbacks */
924   ot->invoke = transform_invoke;
925   ot->exec = transform_exec;
926   ot->modal = transform_modal;
927   ot->cancel = transform_cancel;
928   ot->poll = transform_shear_poll;
929   ot->poll_property = transform_poll_property;
930 
931   RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
932 
933   WM_operatortype_props_advanced_begin(ot);
934 
935   Transform_Properties(ot,
936                        P_ORIENT_AXIS | P_ORIENT_AXIS_ORTHO | P_ORIENT_MATRIX | P_PROPORTIONAL |
937                            P_MIRROR | P_SNAP | P_GPENCIL_EDIT);
938 }
939 
TRANSFORM_OT_push_pull(struct wmOperatorType * ot)940 static void TRANSFORM_OT_push_pull(struct wmOperatorType *ot)
941 {
942   /* identifiers */
943   ot->name = "Push/Pull";
944   ot->description = "Push/Pull selected items";
945   ot->idname = OP_PUSH_PULL;
946   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
947 
948   /* api callbacks */
949   ot->invoke = transform_invoke;
950   ot->exec = transform_exec;
951   ot->modal = transform_modal;
952   ot->cancel = transform_cancel;
953   ot->poll = ED_operator_screenactive;
954   ot->poll_property = transform_poll_property;
955 
956   RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Distance", "", -FLT_MAX, FLT_MAX);
957 
958   WM_operatortype_props_advanced_begin(ot);
959 
960   Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_CENTER);
961 }
962 
TRANSFORM_OT_shrink_fatten(struct wmOperatorType * ot)963 static void TRANSFORM_OT_shrink_fatten(struct wmOperatorType *ot)
964 {
965   /* identifiers */
966   ot->name = "Shrink/Fatten";
967   ot->description = "Shrink/fatten selected vertices along normals";
968   ot->idname = OP_SHRINK_FATTEN;
969   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
970 
971   /* api callbacks */
972   ot->invoke = transform_invoke;
973   ot->exec = transform_exec;
974   ot->modal = transform_modal;
975   ot->cancel = transform_cancel;
976   ot->poll = ED_operator_editmesh;
977   ot->poll_property = transform_poll_property;
978 
979   RNA_def_float_distance(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
980 
981   RNA_def_boolean(ot->srna,
982                   "use_even_offset",
983                   false,
984                   "Offset Even",
985                   "Scale the offset to give more even thickness");
986 
987   WM_operatortype_props_advanced_begin(ot);
988 
989   Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP);
990 }
991 
TRANSFORM_OT_tosphere(struct wmOperatorType * ot)992 static void TRANSFORM_OT_tosphere(struct wmOperatorType *ot)
993 {
994   /* identifiers */
995   ot->name = "To Sphere";
996   ot->description = "Move selected items outward in a spherical shape around geometric center";
997   ot->idname = OP_TOSPHERE;
998   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
999 
1000   /* api callbacks */
1001   ot->invoke = transform_invoke;
1002   ot->exec = transform_exec;
1003   ot->modal = transform_modal;
1004   ot->cancel = transform_cancel;
1005   ot->poll = ED_operator_screenactive;
1006   ot->poll_property = transform_poll_property;
1007 
1008   RNA_def_float_factor(ot->srna, "value", 0, 0, 1, "Factor", "", 0, 1);
1009 
1010   WM_operatortype_props_advanced_begin(ot);
1011 
1012   Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR | P_SNAP | P_GPENCIL_EDIT | P_CENTER);
1013 }
1014 
TRANSFORM_OT_mirror(struct wmOperatorType * ot)1015 static void TRANSFORM_OT_mirror(struct wmOperatorType *ot)
1016 {
1017   /* identifiers */
1018   ot->name = "Mirror";
1019   ot->description = "Mirror selected items around one or more axes";
1020   ot->idname = OP_MIRROR;
1021   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1022 
1023   /* api callbacks */
1024   ot->invoke = transform_invoke;
1025   ot->exec = transform_exec;
1026   ot->modal = transform_modal;
1027   ot->cancel = transform_cancel;
1028   ot->poll = ED_operator_screenactive;
1029   ot->poll_property = transform_poll_property;
1030 
1031   Transform_Properties(
1032       ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_GPENCIL_EDIT | P_CENTER);
1033 }
1034 
TRANSFORM_OT_bbone_resize(struct wmOperatorType * ot)1035 static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot)
1036 {
1037   /* identifiers */
1038   ot->name = "Scale B-Bone";
1039   ot->description = "Scale selected bendy bones display size";
1040   ot->idname = OP_BONE_SIZE;
1041   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1042 
1043   /* api callbacks */
1044   ot->invoke = transform_invoke;
1045   ot->exec = transform_exec;
1046   ot->modal = transform_modal;
1047   ot->cancel = transform_cancel;
1048   ot->poll = ED_operator_object_active;
1049   ot->poll_property = transform_poll_property;
1050 
1051   RNA_def_float_translation(
1052       ot->srna, "value", 3, VecOne, -FLT_MAX, FLT_MAX, "Display Size", "", -FLT_MAX, FLT_MAX);
1053 
1054   WM_operatortype_props_advanced_begin(ot);
1055 
1056   Transform_Properties(ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_MIRROR);
1057 }
1058 
TRANSFORM_OT_edge_slide(struct wmOperatorType * ot)1059 static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot)
1060 {
1061   PropertyRNA *prop;
1062 
1063   /* identifiers */
1064   ot->name = "Edge Slide";
1065   ot->description = "Slide an edge loop along a mesh";
1066   ot->idname = OP_EDGE_SLIDE;
1067   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1068 
1069   /* api callbacks */
1070   ot->invoke = transform_invoke;
1071   ot->exec = transform_exec;
1072   ot->modal = transform_modal;
1073   ot->cancel = transform_cancel;
1074   ot->poll = ED_operator_editmesh_region_view3d;
1075   ot->poll_property = transform_poll_property;
1076 
1077   RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
1078 
1079   prop = RNA_def_boolean(ot->srna, "single_side", false, "Single Side", "");
1080   RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
1081   RNA_def_boolean(ot->srna,
1082                   "use_even",
1083                   false,
1084                   "Even",
1085                   "Make the edge loop match the shape of the adjacent edge loop");
1086 
1087   WM_operatortype_props_advanced_begin(ot);
1088 
1089   RNA_def_boolean(ot->srna,
1090                   "flipped",
1091                   false,
1092                   "Flipped",
1093                   "When Even mode is active, flips between the two adjacent edge loops");
1094   RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp", "Clamp within the edge extents");
1095 
1096   Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV);
1097 }
1098 
TRANSFORM_OT_vert_slide(struct wmOperatorType * ot)1099 static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot)
1100 {
1101   /* identifiers */
1102   ot->name = "Vertex Slide";
1103   ot->description = "Slide a vertex along a mesh";
1104   ot->idname = OP_VERT_SLIDE;
1105   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1106 
1107   /* api callbacks */
1108   ot->invoke = transform_invoke;
1109   ot->exec = transform_exec;
1110   ot->modal = transform_modal;
1111   ot->cancel = transform_cancel;
1112   ot->poll = ED_operator_editmesh_region_view3d;
1113   ot->poll_property = transform_poll_property;
1114 
1115   RNA_def_float_factor(ot->srna, "value", 0, -10.0f, 10.0f, "Factor", "", -1.0f, 1.0f);
1116   RNA_def_boolean(ot->srna,
1117                   "use_even",
1118                   false,
1119                   "Even",
1120                   "Make the edge loop match the shape of the adjacent edge loop");
1121 
1122   WM_operatortype_props_advanced_begin(ot);
1123 
1124   RNA_def_boolean(ot->srna,
1125                   "flipped",
1126                   false,
1127                   "Flipped",
1128                   "When Even mode is active, flips between the two adjacent edge loops");
1129   RNA_def_boolean(ot->srna, "use_clamp", true, "Clamp", "Clamp within the edge extents");
1130 
1131   Transform_Properties(ot, P_MIRROR | P_SNAP | P_CORRECT_UV);
1132 }
1133 
TRANSFORM_OT_edge_crease(struct wmOperatorType * ot)1134 static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot)
1135 {
1136   /* identifiers */
1137   ot->name = "Edge Crease";
1138   ot->description = "Change the crease of edges";
1139   ot->idname = OP_EDGE_CREASE;
1140   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1141 
1142   /* api callbacks */
1143   ot->invoke = transform_invoke;
1144   ot->exec = transform_exec;
1145   ot->modal = transform_modal;
1146   ot->cancel = transform_cancel;
1147   ot->poll = ED_operator_editmesh;
1148   ot->poll_property = transform_poll_property;
1149 
1150   RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
1151 
1152   WM_operatortype_props_advanced_begin(ot);
1153 
1154   Transform_Properties(ot, P_SNAP);
1155 }
1156 
TRANSFORM_OT_edge_bevelweight(struct wmOperatorType * ot)1157 static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot)
1158 {
1159   /* identifiers */
1160   ot->name = "Edge Bevel Weight";
1161   ot->description = "Change the bevel weight of edges";
1162   ot->idname = OP_EDGE_BWEIGHT;
1163   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1164 
1165   /* api callbacks */
1166   ot->invoke = transform_invoke;
1167   ot->exec = transform_exec;
1168   ot->modal = transform_modal;
1169   ot->cancel = transform_cancel;
1170   ot->poll = ED_operator_editmesh;
1171 
1172   RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f);
1173 
1174   WM_operatortype_props_advanced_begin(ot);
1175 
1176   Transform_Properties(ot, P_SNAP);
1177 }
1178 
TRANSFORM_OT_seq_slide(struct wmOperatorType * ot)1179 static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot)
1180 {
1181   /* identifiers */
1182   ot->name = "Sequence Slide";
1183   ot->description = "Slide a sequence strip in time";
1184   ot->idname = OP_SEQ_SLIDE;
1185   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1186 
1187   /* api callbacks */
1188   ot->invoke = transform_invoke;
1189   ot->exec = transform_exec;
1190   ot->modal = transform_modal;
1191   ot->cancel = transform_cancel;
1192   ot->poll = ED_operator_sequencer_active;
1193 
1194   /* properties */
1195   PropertyRNA *prop;
1196 
1197   prop = RNA_def_float_vector(
1198       ot->srna, "value", 2, NULL, -FLT_MAX, FLT_MAX, "Offset", "", -FLT_MAX, FLT_MAX);
1199   RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, 0);
1200 
1201   WM_operatortype_props_advanced_begin(ot);
1202 
1203   Transform_Properties(ot, P_SNAP);
1204 }
1205 
TRANSFORM_OT_rotate_normal(struct wmOperatorType * ot)1206 static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot)
1207 {
1208   /* identifiers */
1209   ot->name = "Rotate Normals";
1210   ot->description = "Rotate split normal of selected items";
1211   ot->idname = OP_NORMAL_ROTATION;
1212   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1213 
1214   /* api callbacks */
1215   ot->invoke = transform_invoke;
1216   ot->exec = transform_exec;
1217   ot->modal = transform_modal;
1218   ot->cancel = transform_cancel;
1219   ot->poll = ED_operator_editmesh;
1220 
1221   RNA_def_float_rotation(
1222       ot->srna, "value", 0, NULL, -FLT_MAX, FLT_MAX, "Angle", "", -M_PI * 2, M_PI * 2);
1223 
1224   Transform_Properties(ot, P_ORIENT_AXIS | P_ORIENT_MATRIX | P_CONSTRAINT | P_MIRROR);
1225 }
1226 
TRANSFORM_OT_transform(struct wmOperatorType * ot)1227 static void TRANSFORM_OT_transform(struct wmOperatorType *ot)
1228 {
1229   PropertyRNA *prop;
1230 
1231   /* identifiers */
1232   ot->name = "Transform";
1233   ot->description = "Transform selected items by mode type";
1234   ot->idname = "TRANSFORM_OT_transform";
1235   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING;
1236 
1237   /* api callbacks */
1238   ot->invoke = transform_invoke;
1239   ot->exec = transform_exec;
1240   ot->modal = transform_modal;
1241   ot->cancel = transform_cancel;
1242   ot->poll = ED_operator_screenactive;
1243   ot->poll_property = transform_poll_property;
1244 
1245   prop = RNA_def_enum(
1246       ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
1247   RNA_def_property_flag(prop, PROP_HIDDEN);
1248 
1249   RNA_def_float_vector(
1250       ot->srna, "value", 4, NULL, -FLT_MAX, FLT_MAX, "Values", "", -FLT_MAX, FLT_MAX);
1251 
1252   WM_operatortype_props_advanced_begin(ot);
1253 
1254   Transform_Properties(ot,
1255                        P_ORIENT_AXIS | P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR |
1256                            P_ALIGN_SNAP | P_GPENCIL_EDIT | P_CENTER);
1257 }
1258 
transform_from_gizmo_invoke(bContext * C,wmOperator * UNUSED (op),const wmEvent * UNUSED (event))1259 static int transform_from_gizmo_invoke(bContext *C,
1260                                        wmOperator *UNUSED(op),
1261                                        const wmEvent *UNUSED(event))
1262 {
1263   bToolRef *tref = WM_toolsystem_ref_from_context(C);
1264   if (tref) {
1265     ARegion *region = CTX_wm_region(C);
1266     wmGizmoMap *gzmap = region->gizmo_map;
1267     wmGizmoGroup *gzgroup = gzmap ? WM_gizmomap_group_find(gzmap, "VIEW3D_GGT_xform_gizmo") : NULL;
1268     if (gzgroup != NULL) {
1269       PointerRNA gzg_ptr;
1270       WM_toolsystem_ref_properties_ensure_from_gizmo_group(tref, gzgroup->type, &gzg_ptr);
1271       const int drag_action = RNA_enum_get(&gzg_ptr, "drag_action");
1272       const char *op_id = NULL;
1273       switch (drag_action) {
1274         case V3D_GIZMO_SHOW_OBJECT_TRANSLATE:
1275           op_id = "TRANSFORM_OT_translate";
1276           break;
1277         case V3D_GIZMO_SHOW_OBJECT_ROTATE:
1278           op_id = "TRANSFORM_OT_rotate";
1279           break;
1280         case V3D_GIZMO_SHOW_OBJECT_SCALE:
1281           op_id = "TRANSFORM_OT_resize";
1282           break;
1283         default:
1284           break;
1285       }
1286       if (op_id) {
1287         wmOperatorType *ot = WM_operatortype_find(op_id, true);
1288         PointerRNA op_ptr;
1289         WM_operator_properties_create_ptr(&op_ptr, ot);
1290         RNA_boolean_set(&op_ptr, "release_confirm", true);
1291         WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_ptr);
1292         WM_operator_properties_free(&op_ptr);
1293         return OPERATOR_FINISHED;
1294       }
1295     }
1296   }
1297   return OPERATOR_PASS_THROUGH;
1298 }
1299 
1300 /* Use with 'TRANSFORM_GGT_gizmo'. */
TRANSFORM_OT_from_gizmo(struct wmOperatorType * ot)1301 static void TRANSFORM_OT_from_gizmo(struct wmOperatorType *ot)
1302 {
1303   /* identifiers */
1304   ot->name = "Transform from Gizmo";
1305   ot->description = "Transform selected items by mode type";
1306   ot->idname = "TRANSFORM_OT_from_gizmo";
1307   ot->flag = 0;
1308 
1309   /* api callbacks */
1310   ot->invoke = transform_from_gizmo_invoke;
1311 }
1312 
transform_operatortypes(void)1313 void transform_operatortypes(void)
1314 {
1315   TransformModeItem *tmode;
1316 
1317   for (tmode = transform_modes; tmode->idname; tmode++) {
1318     WM_operatortype_append(tmode->opfunc);
1319   }
1320 
1321   WM_operatortype_append(TRANSFORM_OT_transform);
1322 
1323   WM_operatortype_append(TRANSFORM_OT_select_orientation);
1324   WM_operatortype_append(TRANSFORM_OT_create_orientation);
1325   WM_operatortype_append(TRANSFORM_OT_delete_orientation);
1326 
1327   WM_operatortype_append(TRANSFORM_OT_from_gizmo);
1328 }
1329 
ED_keymap_transform(wmKeyConfig * keyconf)1330 void ED_keymap_transform(wmKeyConfig *keyconf)
1331 {
1332   wmKeyMap *modalmap = transform_modal_keymap(keyconf);
1333 
1334   TransformModeItem *tmode;
1335 
1336   for (tmode = transform_modes; tmode->idname; tmode++) {
1337     WM_modalkeymap_assign(modalmap, tmode->idname);
1338   }
1339   WM_modalkeymap_assign(modalmap, "TRANSFORM_OT_transform");
1340 }
1341