Orientation for 3D cursor
[blender.git] / source / blender / editors / mesh / editmesh_bisect.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2013 by Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Campbell Barton
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/mesh/editmesh_bisect.c
27  *  \ingroup edmesh
28  */
29
30 #include "MEM_guardedalloc.h"
31
32 #include "DNA_object_types.h"
33
34 #include "BLI_math.h"
35
36 #include "BLT_translation.h"
37
38 #include "BKE_global.h"
39 #include "BKE_context.h"
40 #include "BKE_editmesh.h"
41 #include "BKE_report.h"
42
43 #include "RNA_define.h"
44 #include "RNA_access.h"
45
46 #include "WM_api.h"
47 #include "WM_types.h"
48
49 #include "ED_mesh.h"
50 #include "ED_screen.h"
51 #include "ED_view3d.h"
52
53 #include "UI_resources.h"
54
55 #include "mesh_intern.h"  /* own include */
56
57 #define USE_MANIPULATOR
58
59 #ifdef USE_MANIPULATOR
60 #include "ED_manipulator_library.h"
61 #include "ED_undo.h"
62 #endif
63
64 static int mesh_bisect_exec(bContext *C, wmOperator *op);
65
66 /* -------------------------------------------------------------------- */
67 /* Model Helpers */
68
69 typedef struct {
70         /* modal only */
71         BMBackup mesh_backup;
72         bool is_first;
73         short twflag;
74 } BisectData;
75
76 static bool mesh_bisect_interactive_calc(
77         bContext *C, wmOperator *op,
78         BMEditMesh *em,
79         float plane_co[3], float plane_no[3])
80 {
81         wmGesture *gesture = op->customdata;
82         BisectData *opdata;
83
84         View3D *v3d = CTX_wm_view3d(C);
85         ARegion *ar = CTX_wm_region(C);
86         RegionView3D *rv3d = ar->regiondata;
87
88         int x_start = RNA_int_get(op->ptr, "xstart");
89         int y_start = RNA_int_get(op->ptr, "ystart");
90         int x_end = RNA_int_get(op->ptr, "xend");
91         int y_end = RNA_int_get(op->ptr, "yend");
92
93         /* reference location (some point in front of the view) for finding a point on a plane */
94         const float *co_ref = rv3d->ofs;
95         float co_a_ss[2] = {x_start, y_start}, co_b_ss[2] = {x_end, y_end}, co_delta_ss[2];
96         float co_a[3], co_b[3];
97         const float zfac = ED_view3d_calc_zfac(rv3d, co_ref, NULL);
98
99         opdata = gesture->userdata;
100
101         /* view vector */
102         ED_view3d_win_to_vector(ar, co_a_ss, co_a);
103
104         /* view delta */
105         sub_v2_v2v2(co_delta_ss, co_a_ss, co_b_ss);
106         ED_view3d_win_to_delta(ar, co_delta_ss, co_b, zfac);
107
108         /* cross both to get a normal */
109         cross_v3_v3v3(plane_no, co_a, co_b);
110         normalize_v3(plane_no);  /* not needed but nicer for user */
111
112         /* point on plane, can use either start or endpoint */
113         ED_view3d_win_to_3d(v3d, ar, co_ref, co_a_ss, plane_co);
114
115         if (opdata->is_first == false)
116                 EDBM_redo_state_restore(opdata->mesh_backup, em, false);
117
118         opdata->is_first = false;
119
120         return true;
121 }
122
123 static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
124 {
125         Object *obedit = CTX_data_edit_object(C);
126         BMEditMesh *em = BKE_editmesh_from_object(obedit);
127         int ret;
128
129         if (em->bm->totedgesel == 0) {
130                 BKE_report(op->reports, RPT_ERROR, "Selected edges/faces required");
131                 return OPERATOR_CANCELLED;
132         }
133
134         /* if the properties are set or there is no rv3d,
135          * skip model and exec immediately */
136
137         if ((CTX_wm_region_view3d(C) == NULL) ||
138             (RNA_struct_property_is_set(op->ptr, "plane_co") &&
139              RNA_struct_property_is_set(op->ptr, "plane_no")))
140         {
141                 return mesh_bisect_exec(C, op);
142         }
143
144         ret = WM_gesture_straightline_invoke(C, op, event);
145         if (ret & OPERATOR_RUNNING_MODAL) {
146                 View3D *v3d = CTX_wm_view3d(C);
147
148                 wmGesture *gesture = op->customdata;
149                 BisectData *opdata;
150
151
152                 opdata = MEM_mallocN(sizeof(BisectData), "inset_operator_data");
153                 opdata->mesh_backup = EDBM_redo_state_store(em);
154                 opdata->is_first = true;
155                 gesture->userdata = opdata;
156
157                 /* misc other vars */
158                 G.moving = G_TRANSFORM_EDIT;
159                 opdata->twflag = v3d->twflag;
160                 v3d->twflag = 0;
161
162                 /* initialize modal callout */
163                 ED_area_headerprint(CTX_wm_area(C), IFACE_("LMB: Click and drag to draw cut line"));
164         }
165         return ret;
166 }
167
168 static void edbm_bisect_exit(bContext *C, BisectData *opdata)
169 {
170         View3D *v3d = CTX_wm_view3d(C);
171         EDBM_redo_state_free(&opdata->mesh_backup, NULL, false);
172         v3d->twflag = opdata->twflag;
173         G.moving = 0;
174 }
175
176 static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event)
177 {
178         wmGesture *gesture = op->customdata;
179         BisectData *opdata = gesture->userdata;
180         BisectData opdata_back = *opdata;  /* annoyance, WM_gesture_straightline_modal, frees */
181         int ret;
182
183         ret = WM_gesture_straightline_modal(C, op, event);
184
185         /* update or clear modal callout */
186         if (event->type == EVT_MODAL_MAP) {
187                 if (event->val == GESTURE_MODAL_BEGIN) {
188                         ED_area_headerprint(CTX_wm_area(C), IFACE_("LMB: Release to confirm cut line"));
189                 }
190                 else {
191                         ED_area_headerprint(CTX_wm_area(C), NULL);
192                 }
193         }
194
195         if (ret & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
196                 edbm_bisect_exit(C, &opdata_back);
197
198 #ifdef USE_MANIPULATOR
199                 /* Setup manipulators */
200                 {
201                         View3D *v3d = CTX_wm_view3d(C);
202                         if (v3d && (v3d->twflag & V3D_MANIPULATOR_DRAW)) {
203                                 WM_manipulator_group_type_ensure("MESH_WGT_bisect");
204                         }
205                 }
206 #endif
207         }
208
209         return ret;
210 }
211
212 /* End Model Helpers */
213 /* -------------------------------------------------------------------- */
214
215
216
217 static int mesh_bisect_exec(bContext *C, wmOperator *op)
218 {
219         Scene *scene = CTX_data_scene(C);
220
221         /* both can be NULL, fallbacks values are used */
222         View3D *v3d = CTX_wm_view3d(C);
223         RegionView3D *rv3d = ED_view3d_context_rv3d(C);
224
225         Object *obedit = CTX_data_edit_object(C);
226         BMEditMesh *em = BKE_editmesh_from_object(obedit);
227         BMesh *bm;
228         BMOperator bmop;
229         float plane_co[3];
230         float plane_no[3];
231         float imat[4][4];
232
233         const float thresh = RNA_float_get(op->ptr, "threshold");
234         const bool use_fill = RNA_boolean_get(op->ptr, "use_fill");
235         const bool clear_inner = RNA_boolean_get(op->ptr, "clear_inner");
236         const bool clear_outer = RNA_boolean_get(op->ptr, "clear_outer");
237
238         PropertyRNA *prop_plane_co;
239         PropertyRNA *prop_plane_no;
240
241         prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co");
242         if (RNA_property_is_set(op->ptr, prop_plane_co)) {
243                 RNA_property_float_get_array(op->ptr, prop_plane_co, plane_co);
244         }
245         else {
246                 copy_v3_v3(plane_co, ED_view3d_cursor3d_get(scene, v3d)->location);
247                 RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co);
248         }
249
250         prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no");
251         if (RNA_property_is_set(op->ptr, prop_plane_no)) {
252                 RNA_property_float_get_array(op->ptr, prop_plane_no, plane_no);
253         }
254         else {
255                 if (rv3d) {
256                         copy_v3_v3(plane_no, rv3d->viewinv[1]);
257                 }
258                 else {
259                         /* fallback... */
260                         plane_no[0] = plane_no[1] = 0.0f; plane_no[2] = 1.0f;
261                 }
262                 RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no);
263         }
264
265
266
267         /* -------------------------------------------------------------------- */
268         /* Modal support */
269         /* Note: keep this isolated, exec can work wihout this */
270         if ((op->customdata != NULL) &&
271             mesh_bisect_interactive_calc(C, op, em, plane_co, plane_no))
272         {
273                 /* write back to the props */
274                 RNA_property_float_set_array(op->ptr, prop_plane_no, plane_no);
275                 RNA_property_float_set_array(op->ptr, prop_plane_co, plane_co);
276         }
277         /* End Modal */
278         /* -------------------------------------------------------------------- */
279
280
281
282         bm = em->bm;
283
284         invert_m4_m4(imat, obedit->obmat);
285         mul_m4_v3(imat, plane_co);
286         mul_transposed_mat3_m4_v3(obedit->obmat, plane_no);
287
288         EDBM_op_init(em, &bmop, op,
289                      "bisect_plane geom=%hvef plane_co=%v plane_no=%v dist=%f clear_inner=%b clear_outer=%b",
290                      BM_ELEM_SELECT, plane_co, plane_no, thresh, clear_inner, clear_outer);
291         BMO_op_exec(bm, &bmop);
292
293         EDBM_flag_disable_all(em, BM_ELEM_SELECT);
294
295         if (use_fill) {
296                 float normal_fill[3];
297                 BMOperator bmop_fill;
298                 BMOperator bmop_attr;
299
300                 normalize_v3_v3(normal_fill, plane_no);
301                 if (clear_outer == true && clear_inner == false) {
302                         negate_v3(normal_fill);
303                 }
304
305                 /* Fill */
306                 BMO_op_initf(
307                         bm, &bmop_fill, 0,
308                         "triangle_fill edges=%S normal=%v use_dissolve=%b",
309                         &bmop, "geom_cut.out", normal_fill, true);
310                 BMO_op_exec(bm, &bmop_fill);
311
312                 /* Copy Attributes */
313                 BMO_op_initf(bm, &bmop_attr, 0,
314                              "face_attribute_fill faces=%S use_normals=%b use_data=%b",
315                              &bmop_fill, "geom.out", false, true);
316                 BMO_op_exec(bm, &bmop_attr);
317
318                 BMO_slot_buffer_hflag_enable(bm, bmop_fill.slots_out, "geom.out", BM_FACE, BM_ELEM_SELECT, true);
319
320                 BMO_op_finish(bm, &bmop_attr);
321                 BMO_op_finish(bm, &bmop_fill);
322         }
323
324         BMO_slot_buffer_hflag_enable(bm, bmop.slots_out, "geom_cut.out", BM_VERT | BM_EDGE, BM_ELEM_SELECT, true);
325
326         if (!EDBM_op_finish(em, &bmop, op, true)) {
327                 return OPERATOR_CANCELLED;
328         }
329         else {
330                 EDBM_update_generic(em, true, true);
331                 EDBM_selectmode_flush(em);
332                 return OPERATOR_FINISHED;
333         }
334 }
335
336 #ifdef USE_MANIPULATOR
337 static void MESH_WGT_bisect(struct wmManipulatorGroupType *wgt);
338 #endif
339
340 void MESH_OT_bisect(struct wmOperatorType *ot)
341 {
342         PropertyRNA *prop;
343
344         /* identifiers */
345         ot->name = "Bisect";
346         ot->description = "Cut geometry along a plane (click-drag to define plane)";
347         ot->idname = "MESH_OT_bisect";
348
349         /* api callbacks */
350         ot->exec = mesh_bisect_exec;
351         ot->invoke = mesh_bisect_invoke;
352         ot->modal = mesh_bisect_modal;
353         ot->cancel = WM_gesture_straightline_cancel;
354         ot->poll = ED_operator_editmesh;
355
356         /* flags */
357         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
358
359
360         prop = RNA_def_float_vector(ot->srna, "plane_co", 3, NULL, -1e12f, 1e12f,
361                                     "Plane Point", "A point on the plane", -1e4f, 1e4f);
362         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
363         prop = RNA_def_float_vector(ot->srna, "plane_no", 3, NULL, -1.0f, 1.0f,
364                                     "Plane Normal", "The direction the plane points", -1.0f, 1.0f);
365         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
366
367         RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill in the cut");
368         RNA_def_boolean(ot->srna, "clear_inner", false, "Clear Inner", "Remove geometry behind the plane");
369         RNA_def_boolean(ot->srna, "clear_outer", false, "Clear Outer", "Remove geometry in front of the plane");
370
371         RNA_def_float(ot->srna, "threshold", 0.0001, 0.0, 10.0, "Axis Threshold", "", 0.00001, 0.1);
372
373         WM_operator_properties_gesture_straightline(ot, CURSOR_EDIT);
374
375 #ifdef USE_MANIPULATOR
376         WM_manipulatorgrouptype_append(MESH_WGT_bisect);
377 #endif
378 }
379
380
381 #ifdef USE_MANIPULATOR
382
383 /* -------------------------------------------------------------------- */
384
385 /** \name Bisect Manipulator
386  * \{ */
387
388 typedef struct ManipulatorGroup {
389         /* Arrow to change plane depth. */
390         struct wmManipulator *translate_z;
391         /* Translate XYZ */
392         struct wmManipulator *translate_c;
393         /* For grabbing the manipulator and moving freely. */
394         struct wmManipulator *rotate_c;
395
396         /* We could store more vars here! */
397         struct {
398                 bContext *context;
399                 wmOperator *op;
400                 PropertyRNA *prop_plane_co;
401                 PropertyRNA *prop_plane_no;
402
403                 float rotate_axis[3];
404                 float rotate_up[3];
405         } data;
406 } ManipulatorGroup;
407
408 /**
409  * XXX. calling redo from property updates is not great.
410  * This is needed because changing the RNA doesn't cause a redo
411  * and we're not using operator UI which does just this.
412  */
413 static void manipulator_bisect_exec(ManipulatorGroup *man)
414 {
415         wmOperator *op = man->data.op;
416         if (op == WM_operator_last_redo((bContext *)man->data.context)) {
417                 ED_undo_operator_repeat((bContext *)man->data.context, op);
418         }
419 }
420
421 static void manipulator_mesh_bisect_update_from_op(ManipulatorGroup *man)
422 {
423         wmOperator *op = man->data.op;
424
425         float plane_co[3], plane_no[3];
426
427         RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co);
428         RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no);
429
430         WM_manipulator_set_matrix_location(man->translate_z, plane_co);
431         WM_manipulator_set_matrix_location(man->rotate_c, plane_co);
432         /* translate_c location comes from the property. */
433
434         WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_z, plane_no);
435
436         WM_manipulator_set_scale(man->translate_c, 0.2);
437
438         RegionView3D *rv3d = ED_view3d_context_rv3d(man->data.context);
439         if (rv3d) {
440                 normalize_v3_v3(man->data.rotate_axis, rv3d->viewinv[2]);
441                 normalize_v3_v3(man->data.rotate_up, rv3d->viewinv[1]);
442
443                 /* ensure its orthogonal */
444                 project_plane_normalized_v3_v3v3(man->data.rotate_up, man->data.rotate_up, man->data.rotate_axis);
445                 normalize_v3(man->data.rotate_up);
446
447                 WM_manipulator_set_matrix_rotation_from_z_axis(man->translate_c, plane_no);
448
449                 float plane_no_cross[3];
450                 cross_v3_v3v3(plane_no_cross, plane_no, man->data.rotate_axis);
451
452                 WM_manipulator_set_matrix_offset_rotation_from_yz_axis(man->rotate_c, plane_no_cross, man->data.rotate_axis);
453                 RNA_enum_set(man->rotate_c->ptr, "draw_options",
454                              ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_MIRROR |
455                              ED_MANIPULATOR_DIAL_DRAW_FLAG_ANGLE_START_Y);
456         }
457 }
458
459 /* depth callbacks */
460 static void manipulator_bisect_prop_depth_get(
461         const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
462         void *value_p)
463 {
464         ManipulatorGroup *man = mpr->parent_mgroup->customdata;
465         wmOperator *op = man->data.op;
466         float *value = value_p;
467
468         BLI_assert(mpr_prop->type->array_length == 1);
469         UNUSED_VARS_NDEBUG(mpr_prop);
470
471         float plane_co[3], plane_no[3];
472         RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co);
473         RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no);
474
475         value[0] = dot_v3v3(plane_no, plane_co) - dot_v3v3(plane_no, mpr->matrix_basis[3]);
476 }
477
478 static void manipulator_bisect_prop_depth_set(
479         const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
480         const void *value_p)
481 {
482         ManipulatorGroup *man = mpr->parent_mgroup->customdata;
483         wmOperator *op = man->data.op;
484         const float *value = value_p;
485
486         BLI_assert(mpr_prop->type->array_length == 1);
487         UNUSED_VARS_NDEBUG(mpr_prop);
488
489         float plane_co[3], plane[4];
490         RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, plane_co);
491         RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane);
492         normalize_v3(plane);
493
494         plane[3] = -value[0] - dot_v3v3(plane, mpr->matrix_basis[3]);
495
496         /* Keep our location, may be offset simply to be inside the viewport. */
497         closest_to_plane_normalized_v3(plane_co, plane, plane_co);
498
499         RNA_property_float_set_array(op->ptr, man->data.prop_plane_co, plane_co);
500
501         manipulator_bisect_exec(man);
502 }
503
504 /* translate callbacks */
505 static void manipulator_bisect_prop_translate_get(
506         const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
507         void *value_p)
508 {
509         ManipulatorGroup *man = mpr->parent_mgroup->customdata;
510         wmOperator *op = man->data.op;
511
512         BLI_assert(mpr_prop->type->array_length == 3);
513         UNUSED_VARS_NDEBUG(mpr_prop);
514
515         RNA_property_float_get_array(op->ptr, man->data.prop_plane_co, value_p);
516 }
517
518 static void manipulator_bisect_prop_translate_set(
519         const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
520         const void *value_p)
521 {
522         ManipulatorGroup *man = mpr->parent_mgroup->customdata;
523         wmOperator *op = man->data.op;
524
525         BLI_assert(mpr_prop->type->array_length == 3);
526         UNUSED_VARS_NDEBUG(mpr_prop);
527
528         RNA_property_float_set_array(op->ptr, man->data.prop_plane_co, value_p);
529
530         manipulator_bisect_exec(man);
531 }
532
533 /* angle callbacks */
534 static void manipulator_bisect_prop_angle_get(
535         const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
536         void *value_p)
537 {
538         ManipulatorGroup *man = mpr->parent_mgroup->customdata;
539         wmOperator *op = man->data.op;
540         float *value = value_p;
541
542         BLI_assert(mpr_prop->type->array_length == 1);
543         UNUSED_VARS_NDEBUG(mpr_prop);
544
545         float plane_no[4];
546         RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no);
547         normalize_v3(plane_no);
548
549         float plane_no_proj[3];
550         project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, man->data.rotate_axis);
551
552         if (!is_zero_v3(plane_no_proj)) {
553                 const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->data.rotate_axis);
554                 value[0] = angle;
555         }
556         else {
557                 value[0] = 0.0f;
558         }
559 }
560
561 static void manipulator_bisect_prop_angle_set(
562         const wmManipulator *mpr, wmManipulatorProperty *mpr_prop,
563         const void *value_p)
564 {
565         ManipulatorGroup *man = mpr->parent_mgroup->customdata;
566         wmOperator *op = man->data.op;
567         const float *value = value_p;
568
569         BLI_assert(mpr_prop->type->array_length == 1);
570         UNUSED_VARS_NDEBUG(mpr_prop);
571
572         float plane_no[4];
573         RNA_property_float_get_array(op->ptr, man->data.prop_plane_no, plane_no);
574         normalize_v3(plane_no);
575
576         float plane_no_proj[3];
577         project_plane_normalized_v3_v3v3(plane_no_proj, plane_no, man->data.rotate_axis);
578
579         if (!is_zero_v3(plane_no_proj)) {
580                 const float angle = -angle_signed_on_axis_v3v3_v3(plane_no_proj, man->data.rotate_up, man->data.rotate_axis);
581                 const float angle_delta = angle - angle_compat_rad(value[0], angle);
582                 if (angle_delta != 0.0f) {
583                         float mat[3][3];
584                         axis_angle_normalized_to_mat3(mat, man->data.rotate_axis, angle_delta);
585                         mul_m3_v3(mat, plane_no);
586
587                         /* re-normalize - seems acceptable */
588                         RNA_property_float_set_array(op->ptr, man->data.prop_plane_no, plane_no);
589
590                         manipulator_bisect_exec(man);
591                 }
592         }
593 }
594
595 static bool manipulator_mesh_bisect_poll(const bContext *C, wmManipulatorGroupType *wgt)
596 {
597         wmOperator *op = WM_operator_last_redo(C);
598         if (op == NULL || !STREQ(op->type->idname, "MESH_OT_bisect")) {
599                 WM_manipulator_group_type_unlink_delayed_ptr(wgt);
600                 return false;
601         }
602         return true;
603 }
604
605 static void manipulator_mesh_bisect_setup(const bContext *C, wmManipulatorGroup *mgroup)
606 {
607         wmOperator *op = WM_operator_last_redo(C);
608
609         if (op == NULL || !STREQ(op->type->idname, "MESH_OT_bisect")) {
610                 return;
611         }
612
613         struct ManipulatorGroup *man = MEM_callocN(sizeof(ManipulatorGroup), __func__);
614         mgroup->customdata = man;
615
616         const wmManipulatorType *wt_arrow = WM_manipulatortype_find("MANIPULATOR_WT_arrow_3d", true);
617         const wmManipulatorType *wt_grab = WM_manipulatortype_find("MANIPULATOR_WT_grab_3d", true);
618         const wmManipulatorType *wt_dial = WM_manipulatortype_find("MANIPULATOR_WT_dial_3d", true);
619
620         man->translate_z = WM_manipulator_new_ptr(wt_arrow, mgroup, NULL);
621         man->translate_c = WM_manipulator_new_ptr(wt_grab, mgroup, NULL);
622         man->rotate_c = WM_manipulator_new_ptr(wt_dial, mgroup, NULL);
623
624         UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->translate_z->color);
625         UI_GetThemeColor3fv(TH_MANIPULATOR_PRIMARY, man->translate_c->color);
626         UI_GetThemeColor3fv(TH_MANIPULATOR_SECONDARY, man->rotate_c->color);
627
628         RNA_enum_set(man->translate_z->ptr, "draw_style", ED_MANIPULATOR_ARROW_STYLE_NORMAL);
629         RNA_enum_set(man->translate_c->ptr, "draw_style", ED_MANIPULATOR_GRAB_STYLE_RING_2D);
630
631         WM_manipulator_set_flag(man->translate_c, WM_MANIPULATOR_DRAW_VALUE, true);
632         WM_manipulator_set_flag(man->rotate_c, WM_MANIPULATOR_DRAW_VALUE, true);
633
634         {
635                 man->data.context = (bContext *)C;
636                 man->data.op = op;
637                 man->data.prop_plane_co = RNA_struct_find_property(op->ptr, "plane_co");
638                 man->data.prop_plane_no = RNA_struct_find_property(op->ptr, "plane_no");
639         }
640
641         manipulator_mesh_bisect_update_from_op(man);
642
643         /* Setup property callbacks */
644         {
645                 WM_manipulator_target_property_def_func(
646                         man->translate_z, "offset",
647                         &(const struct wmManipulatorPropertyFnParams) {
648                             .value_get_fn = manipulator_bisect_prop_depth_get,
649                             .value_set_fn = manipulator_bisect_prop_depth_set,
650                             .range_get_fn = NULL,
651                             .user_data = NULL,
652                         });
653
654                 WM_manipulator_target_property_def_func(
655                         man->translate_c, "offset",
656                         &(const struct wmManipulatorPropertyFnParams) {
657                             .value_get_fn = manipulator_bisect_prop_translate_get,
658                             .value_set_fn = manipulator_bisect_prop_translate_set,
659                             .range_get_fn = NULL,
660                             .user_data = NULL,
661                         });
662
663                 WM_manipulator_target_property_def_func(
664                         man->rotate_c, "offset",
665                         &(const struct wmManipulatorPropertyFnParams) {
666                             .value_get_fn = manipulator_bisect_prop_angle_get,
667                             .value_set_fn = manipulator_bisect_prop_angle_set,
668                             .range_get_fn = NULL,
669                             .user_data = NULL,
670                         });
671         }
672 }
673
674 static void manipulator_mesh_bisect_draw_prepare(
675         const bContext *UNUSED(C), wmManipulatorGroup *mgroup)
676 {
677         ManipulatorGroup *man = mgroup->customdata;
678         if (man->data.op->next) {
679                 man->data.op = WM_operator_last_redo((bContext *)man->data.context);
680         }
681         manipulator_mesh_bisect_update_from_op(man);
682 }
683
684 static void MESH_WGT_bisect(struct wmManipulatorGroupType *wgt)
685 {
686         wgt->name = "Mesh Bisect";
687         wgt->idname = "MESH_WGT_bisect";
688
689         wgt->flag = WM_MANIPULATORGROUPTYPE_3D;
690
691         wgt->mmap_params.spaceid = SPACE_VIEW3D;
692         wgt->mmap_params.regionid = RGN_TYPE_WINDOW;
693
694         wgt->poll = manipulator_mesh_bisect_poll;
695         wgt->setup = manipulator_mesh_bisect_setup;
696         wgt->draw_prepare = manipulator_mesh_bisect_draw_prepare;
697 }
698
699 /** \} */
700
701 #endif  /* USE_MANIPULATOR */