code cleanup: spelling
[blender.git] / source / blender / editors / armature / armature_edit.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) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation, 2002-2009 full recode.
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  *
25  * Armature EditMode tools - transforms, chain based editing, and other settings
26  */
27
28 /** \file blender/editors/armature/armature_edit.c
29  *  \ingroup edarmature
30  */
31
32 #include <assert.h> 
33
34 #include "DNA_armature_types.h"
35 #include "DNA_constraint_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_scene_types.h"
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_math.h"
43
44 #include "BKE_action.h"
45 #include "BKE_armature.h"
46 #include "BKE_constraint.h"
47 #include "BKE_context.h"
48 #include "BKE_global.h"
49 #include "BKE_report.h"
50
51 #include "RNA_access.h"
52 #include "RNA_define.h"
53
54 #include "WM_api.h"
55 #include "WM_types.h"
56
57 #include "ED_armature.h"
58 #include "ED_screen.h"
59 #include "ED_view3d.h"
60
61 #include "armature_intern.h"
62
63 /* ************************** Object Tools Exports ******************************* */
64 /* NOTE: these functions are exported to the Object module to be called from the tools there */
65
66 void ED_armature_apply_transform(Object *ob, float mat[4][4])
67 {
68         EditBone *ebone;
69         bArmature *arm = ob->data;
70         float scale = mat4_to_scale(mat);   /* store the scale of the matrix here to use on envelopes */
71         float mat3[3][3];
72         
73         copy_m3_m4(mat3, mat);
74         normalize_m3(mat3);
75         
76         /* Put the armature into editmode */
77         ED_armature_to_edit(ob);
78         
79         /* Do the rotations */
80         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
81                 float tmat[3][3];
82                 
83                 /* find the current bone's roll matrix */
84                 ED_armature_ebone_to_mat3(ebone, tmat);
85                 
86                 /* transform the roll matrix */
87                 mul_m3_m3m3(tmat, mat3, tmat);
88                 
89                 /* transform the bone */
90                 mul_m4_v3(mat, ebone->head);
91                 mul_m4_v3(mat, ebone->tail);
92                 
93                 /* apply the transfiormed roll back */
94                 mat3_to_vec_roll(tmat, NULL, &ebone->roll);
95                 
96                 ebone->rad_head *= scale;
97                 ebone->rad_tail *= scale;
98                 ebone->dist     *= scale;
99                 
100                 /* we could be smarter and scale by the matrix along the x & z axis */
101                 ebone->xwidth   *= scale;
102                 ebone->zwidth   *= scale;
103         }
104         
105         /* Turn the list into an armature */
106         ED_armature_from_edit(ob);
107         ED_armature_edit_free(ob);
108 }
109
110 /* exported for use in editors/object/ */
111 /* 0 == do center, 1 == center new, 2 == center cursor */
112 void ED_armature_origin_set(Scene *scene, Object *ob, float cursor[3], int centermode, int around)
113 {
114         Object *obedit = scene->obedit; // XXX get from context
115         EditBone *ebone;
116         bArmature *arm = ob->data;
117         float cent[3];
118
119         /* Put the armature into editmode */
120         if (ob != obedit) {
121                 ED_armature_to_edit(ob);
122                 obedit = NULL; /* we cant use this so behave as if there is no obedit */
123         }
124
125         /* Find the centerpoint */
126         if (centermode == 2) {
127                 copy_v3_v3(cent, cursor);
128                 invert_m4_m4(ob->imat, ob->obmat);
129                 mul_m4_v3(ob->imat, cent);
130         }
131         else {
132                 if (around == V3D_CENTROID) {
133                         int total = 0;
134                         zero_v3(cent);
135                         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
136                                 total += 2;
137                                 add_v3_v3(cent, ebone->head);
138                                 add_v3_v3(cent, ebone->tail);
139                         }
140                         if (total) {
141                                 mul_v3_fl(cent, 1.0f / (float)total);
142                         }
143                 }
144                 else {
145                         float min[3], max[3];
146                         INIT_MINMAX(min, max);
147                         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
148                                 minmax_v3v3_v3(min, max, ebone->head);
149                                 minmax_v3v3_v3(min, max, ebone->tail);
150                         }
151                         mid_v3_v3v3(cent, min, max);
152                 }
153         }
154         
155         /* Do the adjustments */
156         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
157                 sub_v3_v3(ebone->head, cent);
158                 sub_v3_v3(ebone->tail, cent);
159         }
160         
161         /* Turn the list into an armature */
162         if (obedit == NULL) {
163                 ED_armature_from_edit(ob);
164                 ED_armature_edit_free(ob);
165         }
166
167         /* Adjust object location for new centerpoint */
168         if (centermode && obedit == NULL) {
169                 mul_mat3_m4_v3(ob->obmat, cent); /* ommit translation part */
170                 add_v3_v3(ob->loc, cent);
171         }
172 }
173
174 /* ********************************* Roll ******************************* */
175
176 /* adjust bone roll to align Z axis with vector
177  * vec is in local space and is normalized
178  */
179 float ED_rollBoneToVector(EditBone *bone, const float align_axis[3], const short axis_only)
180 {
181         float mat[3][3], nor[3];
182
183         sub_v3_v3v3(nor, bone->tail, bone->head);
184         vec_roll_to_mat3(nor, 0.0f, mat);
185         
186         /* check the bone isn't aligned with the axis */
187         if (!is_zero_v3(align_axis) && angle_v3v3(align_axis, mat[2]) > FLT_EPSILON) {
188                 float vec[3], align_axis_proj[3], roll;
189                 
190                 /* project the new_up_axis along the normal */
191                 project_v3_v3v3(vec, align_axis, nor);
192                 sub_v3_v3v3(align_axis_proj, align_axis, vec);
193                 
194                 if (axis_only) {
195                         if (angle_v3v3(align_axis_proj, mat[2]) > (float)(M_PI / 2.0)) {
196                                 negate_v3(align_axis_proj);
197                         }
198                 }
199                 
200                 roll = angle_v3v3(align_axis_proj, mat[2]);
201                 
202                 cross_v3_v3v3(vec, mat[2], align_axis_proj);
203                 
204                 if (dot_v3v3(vec, nor) < 0) {
205                         roll = -roll;
206                 }
207                 
208                 return roll;
209         }
210
211         return 0.0f;
212 }
213
214
215 typedef enum eCalcRollTypes {
216         CALC_ROLL_X          = 0,
217         CALC_ROLL_Y          = 1,
218         CALC_ROLL_Z          = 2,
219         
220         CALC_ROLL_ACTIVE     = 5,
221         CALC_ROLL_VIEW       = 6,
222         CALC_ROLL_CURSOR     = 7
223 } eCalcRollTypes;
224
225 static EnumPropertyItem prop_calc_roll_types[] = {
226         {CALC_ROLL_X, "X", 0, "X Axis", ""},
227         {CALC_ROLL_Y, "Y", 0, "Y Axis", ""},
228         {CALC_ROLL_Z, "Z", 0, "Z Axis", ""},
229         {CALC_ROLL_ACTIVE, "ACTIVE", 0, "Active Bone", ""},
230         {CALC_ROLL_VIEW, "VIEW", 0, "View Axis", ""},
231         {CALC_ROLL_CURSOR, "CURSOR", 0, "Cursor", ""},
232         {0, NULL, 0, NULL, NULL}
233 };
234
235
236 static int armature_calc_roll_exec(bContext *C, wmOperator *op) 
237 {
238         Object *ob = CTX_data_edit_object(C);
239         const short type = RNA_enum_get(op->ptr, "type");
240         const short axis_only = RNA_boolean_get(op->ptr, "axis_only");
241         const short axis_flip = RNA_boolean_get(op->ptr, "axis_flip");
242
243         float imat[3][3];
244
245         bArmature *arm = ob->data;
246         EditBone *ebone;
247
248         copy_m3_m4(imat, ob->obmat);
249         invert_m3(imat);
250
251         if (type == CALC_ROLL_CURSOR) { /* Cursor */
252                 Scene *scene = CTX_data_scene(C);
253                 View3D *v3d = CTX_wm_view3d(C); /* can be NULL */
254                 float cursor_local[3];
255                 const float   *cursor = ED_view3d_cursor3d_get(scene, v3d);
256                 
257                 
258                 copy_v3_v3(cursor_local, cursor);
259                 mul_m3_v3(imat, cursor_local);
260                 
261                 /* cursor */
262                 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
263                         if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
264                                 float cursor_rel[3];
265                                 sub_v3_v3v3(cursor_rel, cursor_local, ebone->head);
266                                 if (axis_flip) negate_v3(cursor_rel);
267                                 ebone->roll = ED_rollBoneToVector(ebone, cursor_rel, axis_only);
268                         }
269                 }
270         }
271         else {
272                 float vec[3] = {0.0f, 0.0f, 0.0f};
273                 if (type == CALC_ROLL_VIEW) { /* View */
274                         RegionView3D *rv3d = CTX_wm_region_view3d(C);
275                         if (rv3d == NULL) {
276                                 BKE_report(op->reports, RPT_ERROR, "No region view3d available");
277                                 return OPERATOR_CANCELLED;
278                         }
279                         
280                         copy_v3_v3(vec, rv3d->viewinv[2]);
281                         mul_m3_v3(imat, vec);
282                 }
283                 else if (type == CALC_ROLL_ACTIVE) {
284                         float mat[3][3];
285                         ebone = (EditBone *)arm->act_edbone;
286                         if (ebone == NULL) {
287                                 BKE_report(op->reports, RPT_ERROR, "No active bone set");
288                                 return OPERATOR_CANCELLED;
289                         }
290                         
291                         ED_armature_ebone_to_mat3(ebone, mat);
292                         copy_v3_v3(vec, mat[2]);
293                 }
294                 else { /* Axis */
295                         assert(type >= 0 && type <= 5);
296                         if (type < 3) vec[type] = 1.0f;
297                         else vec[type - 2] = -1.0f;
298                         mul_m3_v3(imat, vec);
299                 }
300                 
301                 if (axis_flip) negate_v3(vec);
302                 
303                 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
304                         if (EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) {
305                                 /* roll func is a callback which assumes that all is well */
306                                 ebone->roll = ED_rollBoneToVector(ebone, vec, axis_only);
307                         }
308                 }
309         }
310         
311         if (arm->flag & ARM_MIRROR_EDIT) {
312                 for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
313                         if ((EBONE_VISIBLE(arm, ebone) && EBONE_EDITABLE(ebone)) == 0) {
314                                 EditBone *ebone_mirr = ED_armature_bone_get_mirrored(arm->edbo, ebone);
315                                 if (ebone_mirr && (EBONE_VISIBLE(arm, ebone_mirr) && EBONE_EDITABLE(ebone_mirr))) {
316                                         ebone->roll = -ebone_mirr->roll;
317                                 }
318                         }
319                 }
320         }
321         
322         /* note, notifier might evolve */
323         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, ob);
324         
325         return OPERATOR_FINISHED;
326 }
327
328 void ARMATURE_OT_calculate_roll(wmOperatorType *ot)
329 {
330         /* identifiers */
331         ot->name = "Recalculate Roll";
332         ot->idname = "ARMATURE_OT_calculate_roll";
333         ot->description = "Automatically fix alignment of select bones' axes";
334         
335         /* api callbacks */
336         ot->invoke = WM_menu_invoke;
337         ot->exec = armature_calc_roll_exec;
338         ot->poll = ED_operator_editarmature;
339         
340         /* flags */
341         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
342
343         /* properties */
344         ot->prop = RNA_def_enum(ot->srna, "type", prop_calc_roll_types, 0, "Type", "");
345         RNA_def_boolean(ot->srna, "axis_flip", 0, "Flip Axis", "Negate the alignment axis");
346         RNA_def_boolean(ot->srna, "axis_only", 0, "Shortest Rotation", "Ignore the axis direction, use the shortest rotation to align");
347 }
348
349 /* ******************************** Chain-Based Tools ********************************* */
350
351 /* temporary data-structure for merge/fill bones */
352 typedef struct EditBonePoint {
353         struct EditBonePoint *next, *prev;
354         
355         EditBone *head_owner;       /* EditBone which uses this point as a 'head' point */
356         EditBone *tail_owner;       /* EditBone which uses this point as a 'tail' point */
357         
358         float vec[3];               /* the actual location of the point in local/EditMode space */
359 } EditBonePoint;
360
361 /* find chain-tips (i.e. bones without children) */
362 static void chains_find_tips(ListBase *edbo, ListBase *list)
363 {
364         EditBone *curBone, *ebo;
365         LinkData *ld;
366         
367         /* note: this is potentially very slow ... there's got to be a better way */
368         for (curBone = edbo->first; curBone; curBone = curBone->next) {
369                 short stop = 0;
370                 
371                 /* is this bone contained within any existing chain? (skip if so) */
372                 for (ld = list->first; ld; ld = ld->next) {
373                         for (ebo = ld->data; ebo; ebo = ebo->parent) {
374                                 if (ebo == curBone) {
375                                         stop = 1;
376                                         break;
377                                 }
378                         }
379                         
380                         if (stop) break;
381                 }
382                 /* skip current bone if it is part of an existing chain */
383                 if (stop) continue;
384                 
385                 /* is any existing chain part of the chain formed by this bone? */
386                 stop = 0;
387                 for (ebo = curBone->parent; ebo; ebo = ebo->parent) {
388                         for (ld = list->first; ld; ld = ld->next) {
389                                 if (ld->data == ebo) {
390                                         ld->data = curBone;
391                                         stop = 1;
392                                         break;
393                                 }
394                         }
395                         
396                         if (stop) break;
397                 }
398                 /* current bone has already been added to a chain? */
399                 if (stop) continue;
400                 
401                 /* add current bone to a new chain */
402                 ld = MEM_callocN(sizeof(LinkData), "BoneChain");
403                 ld->data = curBone;
404                 BLI_addtail(list, ld);
405         }
406 }
407
408 /* --------------------- */
409
410 static void fill_add_joint(EditBone *ebo, short eb_tail, ListBase *points)
411 {
412         EditBonePoint *ebp;
413         float vec[3];
414         short found = 0;
415         
416         if (eb_tail) {
417                 copy_v3_v3(vec, ebo->tail);
418         }
419         else {
420                 copy_v3_v3(vec, ebo->head);
421         }
422         
423         for (ebp = points->first; ebp; ebp = ebp->next) {
424                 if (equals_v3v3(ebp->vec, vec)) {
425                         if (eb_tail) {
426                                 if ((ebp->head_owner) && (ebp->head_owner->parent == ebo)) {
427                                         /* so this bone's tail owner is this bone */
428                                         ebp->tail_owner = ebo;
429                                         found = 1;
430                                         break;
431                                 }
432                         }
433                         else {
434                                 if ((ebp->tail_owner) && (ebo->parent == ebp->tail_owner)) {
435                                         /* so this bone's head owner is this bone */
436                                         ebp->head_owner = ebo;
437                                         found = 1;
438                                         break;
439                                 }
440                         }
441                 }
442         }
443         
444         /* allocate a new point if no existing point was related */
445         if (found == 0) {
446                 ebp = MEM_callocN(sizeof(EditBonePoint), "EditBonePoint");
447                 
448                 if (eb_tail) {
449                         copy_v3_v3(ebp->vec, ebo->tail);
450                         ebp->tail_owner = ebo;
451                 }
452                 else {
453                         copy_v3_v3(ebp->vec, ebo->head);
454                         ebp->head_owner = ebo;
455                 }
456                 
457                 BLI_addtail(points, ebp);
458         }
459 }
460
461 /* bone adding between selected joints */
462 static int armature_fill_bones_exec(bContext *C, wmOperator *op)
463 {
464         Object *obedit = CTX_data_edit_object(C);
465         bArmature *arm = (obedit) ? obedit->data : NULL;
466         Scene *scene = CTX_data_scene(C);
467         View3D *v3d = CTX_wm_view3d(C);
468         ListBase points = {NULL, NULL};
469         int count;
470
471         /* sanity checks */
472         if (ELEM(NULL, obedit, arm))
473                 return OPERATOR_CANCELLED;
474
475         /* loop over all bones, and only consider if visible */
476         CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
477         {
478                 if (!(ebone->flag & BONE_CONNECTED) && (ebone->flag & BONE_ROOTSEL))
479                         fill_add_joint(ebone, 0, &points);
480                 if (ebone->flag & BONE_TIPSEL) 
481                         fill_add_joint(ebone, 1, &points);
482         }
483         CTX_DATA_END;
484         
485         /* the number of joints determines how we fill:
486          *  1) between joint and cursor (joint=head, cursor=tail)
487          *  2) between the two joints (order is dependent on active-bone/hierachy)
488          *  3+) error (a smarter method involving finding chains needs to be worked out
489          */
490         count = BLI_countlist(&points);
491         
492         if (count == 0) {
493                 BKE_report(op->reports, RPT_ERROR, "No joints selected");
494                 return OPERATOR_CANCELLED;
495         }
496         else if (count == 1) {
497                 EditBonePoint *ebp;
498                 float curs[3];
499                 
500                 /* Get Points - selected joint */
501                 ebp = (EditBonePoint *)points.first;
502                 
503                 /* Get points - cursor (tail) */
504                 invert_m4_m4(obedit->imat, obedit->obmat);
505                 mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
506                 
507                 /* Create a bone */
508                 /* newbone = */ add_points_bone(obedit, ebp->vec, curs);
509         }
510         else if (count == 2) {
511                 EditBonePoint *ebp, *ebp2;
512                 float head[3], tail[3];
513                 short headtail = 0;
514                 
515                 /* check that the points don't belong to the same bone */
516                 ebp = (EditBonePoint *)points.first;
517                 ebp2 = ebp->next;
518                 
519                 if ((ebp->head_owner == ebp2->tail_owner) && (ebp->head_owner != NULL)) {
520                         BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
521                         BLI_freelistN(&points);
522                         return OPERATOR_CANCELLED;
523                 }
524                 if ((ebp->tail_owner == ebp2->head_owner) && (ebp->tail_owner != NULL)) {
525                         BKE_report(op->reports, RPT_ERROR, "Same bone selected...");
526                         BLI_freelistN(&points);
527                         return OPERATOR_CANCELLED;
528                 }
529                 
530                 /* find which one should be the 'head' */
531                 if ((ebp->head_owner && ebp2->head_owner) || (ebp->tail_owner && ebp2->tail_owner)) {
532                         /* rule: whichever one is closer to 3d-cursor */
533                         float curs[3];
534                         float vecA[3], vecB[3];
535                         float distA, distB;
536                         
537                         /* get cursor location */
538                         invert_m4_m4(obedit->imat, obedit->obmat);
539                         mul_v3_m4v3(curs, obedit->imat, ED_view3d_cursor3d_get(scene, v3d));
540                         
541                         /* get distances */
542                         sub_v3_v3v3(vecA, ebp->vec, curs);
543                         sub_v3_v3v3(vecB, ebp2->vec, curs);
544                         distA = len_v3(vecA);
545                         distB = len_v3(vecB);
546                         
547                         /* compare distances - closer one therefore acts as direction for bone to go */
548                         headtail = (distA < distB) ? 2 : 1;
549                 }
550                 else if (ebp->head_owner) {
551                         headtail = 1;
552                 }
553                 else if (ebp2->head_owner) {
554                         headtail = 2;
555                 }
556                 
557                 /* assign head/tail combinations */
558                 if (headtail == 2) {
559                         copy_v3_v3(head, ebp->vec);
560                         copy_v3_v3(tail, ebp2->vec);
561                 }
562                 else if (headtail == 1) {
563                         copy_v3_v3(head, ebp2->vec);
564                         copy_v3_v3(tail, ebp->vec);
565                 }
566                 
567                 /* add new bone and parent it to the appropriate end */
568                 if (headtail) {
569                         EditBone *newbone = add_points_bone(obedit, head, tail);
570                         
571                         /* do parenting (will need to set connected flag too) */
572                         if (headtail == 2) {
573                                 /* ebp tail or head - tail gets priority */
574                                 if (ebp->tail_owner)
575                                         newbone->parent = ebp->tail_owner;
576                                 else
577                                         newbone->parent = ebp->head_owner;
578                         }
579                         else {
580                                 /* ebp2 tail or head - tail gets priority */
581                                 if (ebp2->tail_owner)
582                                         newbone->parent = ebp2->tail_owner;
583                                 else
584                                         newbone->parent = ebp2->head_owner;
585                         }
586
587                         /* don't set for bone connecting two head points of bones */
588                         if (ebp->tail_owner || ebp2->tail_owner) {
589                                 newbone->flag |= BONE_CONNECTED;
590                         }
591                 }
592         }
593         else {
594                 /* FIXME.. figure out a method for multiple bones */
595                 BKE_reportf(op->reports, RPT_ERROR, "Too many points selected: %d", count);
596                 BLI_freelistN(&points);
597                 return OPERATOR_CANCELLED;
598         }
599         
600         /* updates */
601         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
602         
603         /* free points */
604         BLI_freelistN(&points);
605         
606         return OPERATOR_FINISHED;
607 }
608
609 void ARMATURE_OT_fill(wmOperatorType *ot)
610 {
611         /* identifiers */
612         ot->name = "Fill Between Joints";
613         ot->idname = "ARMATURE_OT_fill";
614         ot->description = "Add bone between selected joint(s) and/or 3D-Cursor";
615         
616         /* callbacks */
617         ot->exec = armature_fill_bones_exec;
618         ot->poll = ED_operator_editarmature;
619         
620         /* flags */
621         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
622 }
623
624 /* --------------------- */
625
626 /* this function merges between two bones, removes them and those in-between, 
627  * and adjusts the parent relationships for those in-between
628  */
629 static void bones_merge(Object *obedit, EditBone *start, EditBone *end, EditBone *endchild, ListBase *chains)
630 {
631         bArmature *arm = obedit->data;
632         EditBone *ebo, *ebone, *newbone;
633         LinkData *chain;
634         float head[3], tail[3];
635         
636         /* check if same bone */
637         if (start == end) {
638                 if (G.debug & G_DEBUG) {
639                         printf("Error: same bone!\n");
640                         printf("\tstart = %s, end = %s\n", start->name, end->name);
641                 }
642         }
643         
644         /* step 1: add a new bone
645          *      - head = head/tail of start (default head)
646          *      - tail = head/tail of end (default tail)
647          *      - parent = parent of start
648          */
649         if ((start->flag & BONE_TIPSEL) && (start->flag & BONE_SELECTED) == 0) {
650                 copy_v3_v3(head, start->tail);
651         }
652         else {
653                 copy_v3_v3(head, start->head);
654         }
655         if ((end->flag & BONE_ROOTSEL) && (end->flag & BONE_SELECTED) == 0) {
656                 copy_v3_v3(tail, end->head);
657         }
658         else {
659                 copy_v3_v3(tail, end->tail);
660         }
661         newbone = add_points_bone(obedit, head, tail);
662         newbone->parent = start->parent;
663
664         /* TODO, copy more things to the new bone */
665         newbone->flag = start->flag & (BONE_HINGE | BONE_NO_DEFORM | BONE_NO_SCALE |
666                                        BONE_NO_CYCLICOFFSET | BONE_NO_LOCAL_LOCATION | BONE_DONE);
667         
668         /* step 2a: reparent any side chains which may be parented to any bone in the chain of bones to merge 
669          *      - potentially several tips for side chains leading to some tree exist...
670          */
671         for (chain = chains->first; chain; chain = chain->next) {
672                 /* traverse down chain until we hit the bottom or if we run into the tip of the chain of bones we're 
673                  * merging (need to stop in this case to avoid corrupting this chain too!) 
674                  */
675                 for (ebone = chain->data; (ebone) && (ebone != end); ebone = ebone->parent) {
676                         short found = 0;
677                         
678                         /* check if this bone is parented to one in the merging chain
679                          * ! WATCHIT: must only go check until end of checking chain
680                          */
681                         for (ebo = end; (ebo) && (ebo != start->parent); ebo = ebo->parent) {
682                                 /* side-chain found? --> remap parent to new bone, then we're done with this chain :) */
683                                 if (ebone->parent == ebo) {
684                                         ebone->parent = newbone;
685                                         found = 1;
686                                         break;
687                                 }
688                         }
689                         
690                         /* carry on to the next tip now  */
691                         if (found) 
692                                 break;
693                 }
694         }
695         
696         /* step 2b: parent child of end to newbone (child from this chain) */
697         if (endchild)
698                 endchild->parent = newbone;
699         
700         /* step 3: delete all bones between and including start and end */
701         for (ebo = end; ebo; ebo = ebone) {
702                 ebone = (ebo == start) ? (NULL) : (ebo->parent);
703                 bone_free(arm, ebo);
704         }
705         
706         newbone->flag |= (BONE_ROOTSEL | BONE_TIPSEL | BONE_SELECTED);
707         ED_armature_sync_selection(arm->edbo);
708 }
709
710
711 static int armature_merge_exec(bContext *C, wmOperator *op)
712 {
713         Object *obedit = CTX_data_edit_object(C);
714         bArmature *arm = (obedit) ? obedit->data : NULL;
715         short type = RNA_enum_get(op->ptr, "type");
716         
717         /* sanity checks */
718         if (ELEM(NULL, obedit, arm))
719                 return OPERATOR_CANCELLED;
720         
721         /* for now, there's only really one type of merging that's performed... */
722         if (type == 1) {
723                 /* go down chains, merging bones */
724                 ListBase chains = {NULL, NULL};
725                 LinkData *chain, *nchain;
726                 EditBone *ebo;
727                 
728                 armature_tag_select_mirrored(arm);
729                 
730                 /* get chains (ends on chains) */
731                 chains_find_tips(arm->edbo, &chains);
732                 if (chains.first == NULL) return OPERATOR_CANCELLED;
733                 
734                 /* each 'chain' is the last bone in the chain (with no children) */
735                 for (chain = chains.first; chain; chain = nchain) {
736                         EditBone *bstart = NULL, *bend = NULL;
737                         EditBone *bchild = NULL, *child = NULL;
738                         
739                         /* temporarily remove chain from list of chains */
740                         nchain = chain->next;
741                         BLI_remlink(&chains, chain);
742                         
743                         /* only consider bones that are visible and selected */
744                         for (ebo = chain->data; ebo; child = ebo, ebo = ebo->parent) {
745                                 /* check if visible + selected */
746                                 if (EBONE_VISIBLE(arm, ebo) &&
747                                     ((ebo->flag & BONE_CONNECTED) || (ebo->parent == NULL)) &&
748                                     (ebo->flag & BONE_SELECTED) )
749                                 {
750                                         /* set either end or start (end gets priority, unless it is already set) */
751                                         if (bend == NULL) {
752                                                 bend = ebo;
753                                                 bchild = child;
754                                         }
755                                         else 
756                                                 bstart = ebo;
757                                 }
758                                 else {
759                                         /* chain is broken... merge any continous segments then clear */
760                                         if (bstart && bend)
761                                                 bones_merge(obedit, bstart, bend, bchild, &chains);
762                                         
763                                         bstart = NULL;
764                                         bend = NULL;
765                                         bchild = NULL;
766                                 }
767                         }
768                         
769                         /* merge from bstart to bend if something not merged */
770                         if (bstart && bend)
771                                 bones_merge(obedit, bstart, bend, bchild, &chains);
772                         
773                         /* put back link */
774                         BLI_insertlinkbefore(&chains, nchain, chain);
775                 }
776                 
777                 armature_tag_unselect(arm);
778                 
779                 BLI_freelistN(&chains);
780         }
781         
782         /* updates */
783         ED_armature_sync_selection(arm->edbo);
784         WM_event_add_notifier(C, NC_OBJECT | ND_POSE, obedit);
785         
786         return OPERATOR_FINISHED;
787 }
788
789 void ARMATURE_OT_merge(wmOperatorType *ot)
790 {
791         static EnumPropertyItem merge_types[] = {
792                 {1, "WITHIN_CHAIN", 0, "Within Chains", ""},
793                 {0, NULL, 0, NULL, NULL}
794         };
795
796         /* identifiers */
797         ot->name = "Merge Bones";
798         ot->idname = "ARMATURE_OT_merge";
799         ot->description = "Merge continuous chains of selected bones";
800         
801         /* callbacks */
802         ot->invoke = WM_menu_invoke;
803         ot->exec = armature_merge_exec;
804         ot->poll = ED_operator_editarmature;
805         
806         /* flags */
807         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
808         
809         /* properties */
810         ot->prop = RNA_def_enum(ot->srna, "type", merge_types, 0, "Type", "");
811 }
812
813 /* --------------------- */
814
815 /* Switch Direction operator:
816  * Currently, this does not use context loops, as context loops do not make it
817  * easy to retrieve any hierarchical/chain relationships which are necessary for
818  * this to be done easily.
819  */
820  
821 /* helper to clear BONE_TRANSFORM flags */
822 static void armature_clear_swap_done_flags(bArmature *arm)
823 {
824         EditBone *ebone;
825         
826         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
827                 ebone->flag &= ~BONE_TRANSFORM;
828         }
829 }
830
831 static int armature_switch_direction_exec(bContext *C, wmOperator *UNUSED(op)) 
832 {
833         Object *ob = CTX_data_edit_object(C);
834         bArmature *arm = (bArmature *)ob->data;
835         ListBase chains = {NULL, NULL};
836         LinkData *chain;
837         
838         /* get chains of bones (ends on chains) */
839         chains_find_tips(arm->edbo, &chains);
840         if (chains.first == NULL) return OPERATOR_CANCELLED;
841         
842         /* ensure that mirror bones will also be operated on */
843         armature_tag_select_mirrored(arm);
844         
845         /* clear BONE_TRANSFORM flags 
846          * - used to prevent duplicate/canceling operations from occurring [#34123]
847          * - BONE_DONE cannot be used here as that's already used for mirroring
848          */
849         armature_clear_swap_done_flags(arm);
850         
851         /* loop over chains, only considering selected and visible bones */
852         for (chain = chains.first; chain; chain = chain->next) {
853                 EditBone *ebo, *child = NULL, *parent = NULL;
854                 
855                 /* loop over bones in chain */
856                 for (ebo = chain->data; ebo; ebo = parent) {
857                         /* parent is this bone's original parent
858                          *      - we store this, as the next bone that is checked is this one
859                          *        but the value of ebo->parent may change here...
860                          */
861                         parent = ebo->parent;
862                         
863                         /* skip bone if already handled... [#34123] */
864                         if ((ebo->flag & BONE_TRANSFORM) == 0) {
865                                 /* only if selected and editable */
866                                 if (EBONE_VISIBLE(arm, ebo) && EBONE_EDITABLE(ebo)) {
867                                         /* swap head and tail coordinates */
868                                         SWAP(float, ebo->head[0], ebo->tail[0]);
869                                         SWAP(float, ebo->head[1], ebo->tail[1]);
870                                         SWAP(float, ebo->head[2], ebo->tail[2]);
871                                         
872                                         /* do parent swapping:
873                                          *      - use 'child' as new parent
874                                          *      - connected flag is only set if points are coincidental
875                                          */
876                                         ebo->parent = child;
877                                         if ((child) && equals_v3v3(ebo->head, child->tail))
878                                                 ebo->flag |= BONE_CONNECTED;
879                                         else
880                                                 ebo->flag &= ~BONE_CONNECTED;
881                                         
882                                         /* get next bones 
883                                          *      - child will become the new parent of next bone
884                                          */
885                                         child = ebo;
886                                 }
887                                 else {
888                                         /* not swapping this bone, however, if its 'parent' got swapped, unparent us from it 
889                                          * as it will be facing in opposite direction
890                                          */
891                                         if ((parent) && (EBONE_VISIBLE(arm, parent) && EBONE_EDITABLE(parent))) {
892                                                 ebo->parent = NULL;
893                                                 ebo->flag &= ~BONE_CONNECTED;
894                                         }
895                                         
896                                         /* get next bones
897                                          *      - child will become new parent of next bone (not swapping occurred, 
898                                          *        so set to NULL to prevent infinite-loop)
899                                          */
900                                         child = NULL;
901                                 }
902                                 
903                                 /* tag as done (to prevent double-swaps) */
904                                 ebo->flag |= BONE_TRANSFORM;
905                         }
906                 }
907         }
908         
909         /* free chains */
910         BLI_freelistN(&chains);
911         
912         /* clear temp flags */
913         armature_clear_swap_done_flags(arm);
914         armature_tag_unselect(arm);
915         
916         /* note, notifier might evolve */
917         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
918         
919         return OPERATOR_FINISHED;
920 }
921
922 void ARMATURE_OT_switch_direction(wmOperatorType *ot)
923 {
924         /* identifiers */
925         ot->name = "Switch Direction";
926         ot->idname = "ARMATURE_OT_switch_direction";
927         ot->description = "Change the direction that a chain of bones points in (head <-> tail swap)";
928         
929         /* api callbacks */
930         ot->exec = armature_switch_direction_exec;
931         ot->poll = ED_operator_editarmature;
932         
933         /* flags */
934         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
935 }
936
937 /* ********************************* Align ******************************* */
938
939 /* helper to fix a ebone position if its parent has moved due to alignment*/
940 static void fix_connected_bone(EditBone *ebone)
941 {
942         float diff[3];
943         
944         if (!(ebone->parent) || !(ebone->flag & BONE_CONNECTED) || equals_v3v3(ebone->parent->tail, ebone->head))
945                 return;
946         
947         /* if the parent has moved we translate child's head and tail accordingly */
948         sub_v3_v3v3(diff, ebone->parent->tail, ebone->head);
949         add_v3_v3(ebone->head, diff);
950         add_v3_v3(ebone->tail, diff);
951 }
952
953 /* helper to recursively find chains of connected bones starting at ebone and fix their position */
954 static void fix_editbone_connected_children(ListBase *edbo, EditBone *ebone)
955 {
956         EditBone *selbone;
957         
958         for (selbone = edbo->first; selbone; selbone = selbone->next) {
959                 if ((selbone->parent) && (selbone->parent == ebone) && (selbone->flag & BONE_CONNECTED)) {
960                         fix_connected_bone(selbone);
961                         fix_editbone_connected_children(edbo, selbone);
962                 }
963         }
964 }                       
965
966 static void bone_align_to_bone(ListBase *edbo, EditBone *selbone, EditBone *actbone)
967 {
968         float selboneaxis[3], actboneaxis[3], length;
969
970         sub_v3_v3v3(actboneaxis, actbone->tail, actbone->head);
971         normalize_v3(actboneaxis);
972
973         sub_v3_v3v3(selboneaxis, selbone->tail, selbone->head);
974         length =  len_v3(selboneaxis);
975
976         mul_v3_fl(actboneaxis, length);
977         add_v3_v3v3(selbone->tail, selbone->head, actboneaxis);
978         selbone->roll = actbone->roll;
979         
980         /* if the bone being aligned has connected descendants they must be moved
981          * according to their parent new position, otherwise they would be left
982          * in an inconsistent state: connected but away from the parent*/
983         fix_editbone_connected_children(edbo, selbone);
984 }
985
986 static int armature_align_bones_exec(bContext *C, wmOperator *op) 
987 {
988         Object *ob = CTX_data_edit_object(C);
989         bArmature *arm = (bArmature *)ob->data;
990         EditBone *actbone = CTX_data_active_bone(C);
991         EditBone *actmirb = NULL;
992         
993         /* there must be an active bone */
994         if (actbone == NULL) {
995                 BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
996                 return OPERATOR_CANCELLED;
997         }
998         else if (arm->flag & ARM_MIRROR_EDIT) {
999                 /* For X-Axis Mirror Editing option, we may need a mirror copy of actbone
1000                  * - if there's a mirrored copy of selbone, try to find a mirrored copy of actbone 
1001                  *   (i.e.  selbone="child.L" and actbone="parent.L", find "child.R" and "parent.R").
1002                  *   This is useful for arm-chains, for example parenting lower arm to upper arm
1003                  * - if there's no mirrored copy of actbone (i.e. actbone = "parent.C" or "parent")
1004                  *   then just use actbone. Useful when doing upper arm to spine.
1005                  */
1006                 actmirb = ED_armature_bone_get_mirrored(arm->edbo, actbone);
1007                 if (actmirb == NULL) 
1008                         actmirb = actbone;
1009         }
1010         
1011         /* if there is only 1 selected bone, we assume that that is the active bone, 
1012          * since a user will need to have clicked on a bone (thus selecting it) to make it active
1013          */
1014         if (CTX_DATA_COUNT(C, selected_editable_bones) <= 1) {
1015                 /* When only the active bone is selected, and it has a parent,
1016                  * align it to the parent, as that is the only possible outcome. 
1017                  */
1018                 if (actbone->parent) {
1019                         bone_align_to_bone(arm->edbo, actbone, actbone->parent);
1020                         
1021                         if ((arm->flag & ARM_MIRROR_EDIT) && (actmirb->parent))
1022                                 bone_align_to_bone(arm->edbo, actmirb, actmirb->parent);
1023                 }
1024         }
1025         else {
1026                 /* Align 'selected' bones to the active one
1027                  * - the context iterator contains both selected bones and their mirrored copies,
1028                  *   so we assume that unselected bones are mirrored copies of some selected bone
1029                  * - since the active one (and/or its mirror) will also be selected, we also need 
1030                  *   to check that we are not trying to operate on them, since such an operation
1031                  *   would cause errors
1032                  */
1033                 
1034                 /* align selected bones to the active one */
1035                 CTX_DATA_BEGIN(C, EditBone *, ebone, selected_editable_bones)
1036                 {
1037                         if (ELEM(ebone, actbone, actmirb) == 0) {
1038                                 if (ebone->flag & BONE_SELECTED)
1039                                         bone_align_to_bone(arm->edbo, ebone, actbone);
1040                                 else
1041                                         bone_align_to_bone(arm->edbo, ebone, actmirb);
1042                         }
1043                 }
1044                 CTX_DATA_END;
1045         }
1046         
1047         /* note, notifier might evolve */
1048         WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, ob);
1049         
1050         return OPERATOR_FINISHED;
1051 }
1052
1053 void ARMATURE_OT_align(wmOperatorType *ot)
1054 {
1055         /* identifiers */
1056         ot->name = "Align Bones";
1057         ot->idname = "ARMATURE_OT_align";
1058         ot->description = "Align selected bones to the active bone (or to their parent)";
1059         
1060         /* api callbacks */
1061         ot->invoke = WM_operator_confirm;
1062         ot->exec = armature_align_bones_exec;
1063         ot->poll = ED_operator_editarmature;
1064         
1065         /* flags */
1066         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1067 }
1068
1069 /* ********************************* Split ******************************* */
1070
1071 static int armature_split_exec(bContext *C, wmOperator *UNUSED(op))
1072 {
1073         Object *ob = CTX_data_edit_object(C);
1074         bArmature *arm = (bArmature *)ob->data;
1075         EditBone *bone;
1076
1077         for (bone = arm->edbo->first; bone; bone = bone->next) {
1078                 if (bone->parent && (bone->flag & BONE_SELECTED) != (bone->parent->flag & BONE_SELECTED)) {
1079                         bone->parent = NULL;
1080                         bone->flag &= ~BONE_CONNECTED;
1081                 }
1082         }
1083         for (bone = arm->edbo->first; bone; bone = bone->next) {
1084                 ED_armature_ebone_select_set(bone, (bone->flag & BONE_SELECTED) != 0);
1085         }
1086
1087         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1088
1089         return OPERATOR_FINISHED;
1090 }
1091
1092 void ARMATURE_OT_split(wmOperatorType *ot)
1093 {
1094         /* identifiers */
1095         ot->name = "Split";
1096         ot->idname = "ARMATURE_OT_split";
1097         ot->description = "Split off selected bones from connected unselected bones";
1098
1099         /* api callbacks */
1100         ot->exec = armature_split_exec;
1101         ot->poll = ED_operator_editarmature;
1102
1103         /* flags */
1104         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1105 }
1106
1107 /* ********************************* Delete ******************************* */
1108
1109 /* previously delete_armature */
1110 /* only editmode! */
1111 static int armature_delete_selected_exec(bContext *C, wmOperator *UNUSED(op))
1112 {
1113         bArmature *arm;
1114         EditBone *curBone, *ebone_next;
1115         bConstraint *con;
1116         Object *obedit = CTX_data_edit_object(C); // XXX get from context
1117         arm = obedit->data;
1118
1119         /* cancel if nothing selected */
1120         if (CTX_DATA_COUNT(C, selected_bones) == 0)
1121                 return OPERATOR_CANCELLED;
1122         
1123         armature_select_mirrored(arm);
1124         
1125         /*  First erase any associated pose channel */
1126         if (obedit->pose) {
1127                 bPoseChannel *pchan, *pchan_next;
1128                 for (pchan = obedit->pose->chanbase.first; pchan; pchan = pchan_next) {
1129                         pchan_next = pchan->next;
1130                         curBone = editbone_name_exists(arm->edbo, pchan->name);
1131                         
1132                         if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
1133                                 BKE_pose_channel_free(pchan);
1134                                 BKE_pose_channels_hash_free(obedit->pose);
1135                                 BLI_freelinkN(&obedit->pose->chanbase, pchan);
1136                         }
1137                         else {
1138                                 for (con = pchan->constraints.first; con; con = con->next) {
1139                                         bConstraintTypeInfo *cti = BKE_constraint_get_typeinfo(con);
1140                                         ListBase targets = {NULL, NULL};
1141                                         bConstraintTarget *ct;
1142                                         
1143                                         if (cti && cti->get_constraint_targets) {
1144                                                 cti->get_constraint_targets(con, &targets);
1145                                                 
1146                                                 for (ct = targets.first; ct; ct = ct->next) {
1147                                                         if (ct->tar == obedit) {
1148                                                                 if (ct->subtarget[0]) {
1149                                                                         curBone = editbone_name_exists(arm->edbo, ct->subtarget);
1150                                                                         if (curBone && (curBone->flag & BONE_SELECTED) && (arm->layer & curBone->layer)) {
1151                                                                                 con->flag |= CONSTRAINT_DISABLE;
1152                                                                                 ct->subtarget[0] = 0;
1153                                                                         }
1154                                                                 }
1155                                                         }
1156                                                 }
1157                                                 
1158                                                 if (cti->flush_constraint_targets)
1159                                                         cti->flush_constraint_targets(con, &targets, 0);
1160                                         }
1161                                 }
1162                         }
1163                 }
1164         }
1165         
1166         
1167         for (curBone = arm->edbo->first; curBone; curBone = ebone_next) {
1168                 ebone_next = curBone->next;
1169                 if (arm->layer & curBone->layer) {
1170                         if (curBone->flag & BONE_SELECTED) {
1171                                 if (curBone == arm->act_edbone) arm->act_edbone = NULL;
1172                                 ED_armature_edit_bone_remove(arm, curBone);
1173                         }
1174                 }
1175         }
1176         
1177         
1178         ED_armature_sync_selection(arm->edbo);
1179
1180         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1181
1182         return OPERATOR_FINISHED;
1183 }
1184
1185 void ARMATURE_OT_delete(wmOperatorType *ot)
1186 {
1187         /* identifiers */
1188         ot->name = "Delete Selected Bone(s)";
1189         ot->idname = "ARMATURE_OT_delete";
1190         ot->description = "Remove selected bones from the armature";
1191         
1192         /* api callbacks */
1193         ot->invoke = WM_operator_confirm;
1194         ot->exec = armature_delete_selected_exec;
1195         ot->poll = ED_operator_editarmature;
1196         
1197         /* flags */
1198         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1199 }
1200
1201 /* ********************************* Show/Hide ******************************* */
1202
1203 static int armature_hide_exec(bContext *C, wmOperator *op)
1204 {
1205         Object *obedit = CTX_data_edit_object(C);
1206         bArmature *arm = obedit->data;
1207         EditBone *ebone;
1208         const int invert = RNA_boolean_get(op->ptr, "unselected") ? BONE_SELECTED : 0;
1209
1210         /* cancel if nothing selected */
1211         if (CTX_DATA_COUNT(C, selected_bones) == 0)
1212                 return OPERATOR_CANCELLED;
1213
1214         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1215                 if (EBONE_VISIBLE(arm, ebone)) {
1216                         if ((ebone->flag & BONE_SELECTED) != invert) {
1217                                 ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
1218                                 ebone->flag |= BONE_HIDDEN_A;
1219                         }
1220                 }
1221         }
1222         ED_armature_validate_active(arm);
1223         ED_armature_sync_selection(arm->edbo);
1224
1225         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1226
1227         return OPERATOR_FINISHED;
1228 }
1229
1230 void ARMATURE_OT_hide(wmOperatorType *ot)
1231 {
1232         /* identifiers */
1233         ot->name = "Hide Selected Bones";
1234         ot->idname = "ARMATURE_OT_hide";
1235         ot->description = "Tag selected bones to not be visible in Edit Mode";
1236         
1237         /* api callbacks */
1238         ot->exec = armature_hide_exec;
1239         ot->poll = ED_operator_editarmature;
1240         
1241         /* flags */
1242         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1243
1244         /* props */
1245         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected");
1246 }
1247
1248 static int armature_reveal_exec(bContext *C, wmOperator *UNUSED(op))
1249 {
1250         Object *obedit = CTX_data_edit_object(C);
1251         bArmature *arm = obedit->data;
1252         EditBone *ebone;
1253         
1254         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1255                 if (arm->layer & ebone->layer) {
1256                         if (ebone->flag & BONE_HIDDEN_A) {
1257                                 ebone->flag |= (BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL);
1258                                 ebone->flag &= ~BONE_HIDDEN_A;
1259                         }
1260                 }
1261         }
1262         ED_armature_validate_active(arm);
1263         ED_armature_sync_selection(arm->edbo);
1264
1265         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1266
1267         return OPERATOR_FINISHED;
1268 }
1269
1270 void ARMATURE_OT_reveal(wmOperatorType *ot)
1271 {
1272         /* identifiers */
1273         ot->name = "Reveal Bones";
1274         ot->idname = "ARMATURE_OT_reveal";
1275         ot->description = "Unhide all bones that have been tagged to be hidden in Edit Mode";
1276         
1277         /* api callbacks */
1278         ot->exec = armature_reveal_exec;
1279         ot->poll = ED_operator_editarmature;
1280         
1281         /* flags */
1282         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1283
1284 }