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