Renaming: sl > scene_layer
[blender.git] / source / blender / editors / armature / armature_select.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  * API's and Operators for selecting armature bones in EditMode
26  */
27
28 /** \file blender/editors/armature/armature_select.c
29  *  \ingroup edarmature
30  */
31
32 #include "DNA_armature_types.h"
33 #include "DNA_object_types.h"
34 #include "DNA_scene_types.h"
35
36 #include "BLI_blenlib.h"
37 #include "BLI_math.h"
38 #include "BLI_string_utils.h"
39
40 #include "BKE_context.h"
41 //#include "BKE_deform.h"
42 #include "BKE_report.h"
43
44 #include "BIF_gl.h"
45
46 #include "RNA_access.h"
47 #include "RNA_define.h"
48
49 #include "WM_api.h"
50 #include "WM_types.h"
51
52 #include "ED_armature.h"
53 #include "ED_screen.h"
54 #include "ED_view3d.h"
55
56 #include "armature_intern.h"
57
58 /* utility macros for storing a temp int in the bone (selection flag) */
59 #define EBONE_PREV_FLAG_GET(ebone) ((void)0, (ebone)->temp.i)
60 #define EBONE_PREV_FLAG_SET(ebone, val) ((ebone)->temp.i = val)
61
62 /* **************** PoseMode & EditMode Selection Buffer Queries *************************** */
63
64 /* only for opengl selection indices */
65 Bone *get_indexed_bone(Object *ob, int index)
66 {
67         bPoseChannel *pchan;
68         if (ob->pose == NULL) return NULL;
69         index >>= 16;     // bone selection codes use left 2 bytes
70         
71         pchan = BLI_findlink(&ob->pose->chanbase, index);
72         return pchan ? pchan->bone : NULL;
73 }
74
75 /* See if there are any selected bones in this buffer */
76 /* only bones from base are checked on */
77 void *get_bone_from_selectbuffer(
78         Scene *scene, Base *base, const unsigned int *buffer, short hits,
79         bool findunsel, bool do_nearest)
80 {
81         Object *obedit = scene->obedit; // XXX get from context
82         Bone *bone;
83         EditBone *ebone;
84         void *firstunSel = NULL, *firstSel = NULL, *data;
85         unsigned int hitresult;
86         short i;
87         bool takeNext = false;
88         int minsel = 0xffffffff, minunsel = 0xffffffff;
89         
90         for (i = 0; i < hits; i++) {
91                 hitresult = buffer[3 + (i * 4)];
92                 
93                 if (!(hitresult & BONESEL_NOSEL)) {
94                         if (hitresult & BONESEL_ANY) {  /* to avoid including objects in selection */
95                                 bool sel;
96                                 
97                                 hitresult &= ~(BONESEL_ANY);
98                                 /* Determine what the current bone is */
99                                 if (obedit == NULL || base->object != obedit) {
100                                         /* no singular posemode, so check for correct object */
101                                         if (base->selcol == (hitresult & 0xFFFF)) {
102                                                 bone = get_indexed_bone(base->object, hitresult);
103                                                 
104                                                 if (findunsel)
105                                                         sel = (bone->flag & BONE_SELECTED);
106                                                 else
107                                                         sel = !(bone->flag & BONE_SELECTED);
108
109                                                 data = bone;
110                                         }
111                                         else {
112                                                 data = NULL;
113                                                 sel = 0;
114                                         }
115                                 }
116                                 else {
117                                         bArmature *arm = obedit->data;
118                                         
119                                         ebone = BLI_findlink(arm->edbo, hitresult);
120                                         if (findunsel)
121                                                 sel = (ebone->flag & BONE_SELECTED);
122                                         else
123                                                 sel = !(ebone->flag & BONE_SELECTED);
124                                         
125                                         data = ebone;
126                                 }
127                                 
128                                 if (data) {
129                                         if (sel) {
130                                                 if (do_nearest) {
131                                                         if (minsel > buffer[4 * i + 1]) {
132                                                                 firstSel = data;
133                                                                 minsel = buffer[4 * i + 1];
134                                                         }
135                                                 }
136                                                 else {
137                                                         if (!firstSel) firstSel = data;
138                                                         takeNext = 1;
139                                                 }
140                                         }
141                                         else {
142                                                 if (do_nearest) {
143                                                         if (minunsel > buffer[4 * i + 1]) {
144                                                                 firstunSel = data;
145                                                                 minunsel = buffer[4 * i + 1];
146                                                         }
147                                                 }
148                                                 else {
149                                                         if (!firstunSel) firstunSel = data;
150                                                         if (takeNext) return data;
151                                                 }
152                                         }
153                                 }
154                         }
155                 }
156         }
157         
158         if (firstunSel)
159                 return firstunSel;
160         else 
161                 return firstSel;
162 }
163
164 /* used by posemode as well editmode */
165 /* only checks scene->basact! */
166 /* x and y are mouse coords (area space) */
167 void *get_nearest_bone(bContext *C, const int xy[2], bool findunsel)
168 {
169         ViewContext vc;
170         rcti rect;
171         unsigned int buffer[MAXPICKBUF];
172         short hits;
173         
174         view3d_set_viewcontext(C, &vc);
175         
176         // rect.xmin = ... mouseco!
177         rect.xmin = rect.xmax = xy[0];
178         rect.ymin = rect.ymax = xy[1];
179         
180         hits = view3d_opengl_select(&vc, buffer, MAXPICKBUF, &rect, VIEW3D_SELECT_PICK_NEAREST);
181
182         if (hits > 0)
183                 return get_bone_from_selectbuffer(vc.scene, vc.scene_layer->basact, buffer, hits, findunsel, true);
184         
185         return NULL;
186 }
187
188 /* **************** EditMode stuff ********************** */
189
190 /* called in space.c */
191 /* previously "selectconnected_armature" */
192 static int armature_select_linked_invoke(bContext *C, wmOperator *op, const wmEvent *event)
193 {
194         bArmature *arm;
195         EditBone *bone, *curBone, *next;
196         const bool extend = RNA_boolean_get(op->ptr, "extend");
197         Object *obedit = CTX_data_edit_object(C);
198         arm = obedit->data;
199
200         view3d_operator_needs_opengl(C);
201
202         bone = get_nearest_bone(C, event->mval, !extend);
203
204         if (!bone)
205                 return OPERATOR_CANCELLED;
206
207         /* Select parents */
208         for (curBone = bone; curBone; curBone = next) {
209                 if ((curBone->flag & BONE_UNSELECTABLE) == 0) {
210                         if (extend) {
211                                 curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
212                         }
213                         else {
214                                 curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
215                         }
216                 }
217                 
218                 if (curBone->flag & BONE_CONNECTED)
219                         next = curBone->parent;
220                 else
221                         next = NULL;
222         }
223
224         /* Select children */
225         while (bone) {
226                 for (curBone = arm->edbo->first; curBone; curBone = next) {
227                         next = curBone->next;
228                         if ((curBone->parent == bone) && (curBone->flag & BONE_UNSELECTABLE) == 0) {
229                                 if (curBone->flag & BONE_CONNECTED) {
230                                         if (extend)
231                                                 curBone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
232                                         else
233                                                 curBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
234                                         bone = curBone;
235                                         break;
236                                 }
237                                 else {
238                                         bone = NULL;
239                                         break;
240                                 }
241                         }
242                 }
243                 if (!curBone)
244                         bone = NULL;
245         }
246         
247         ED_armature_sync_selection(arm->edbo);
248         
249         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
250         
251         return OPERATOR_FINISHED;
252 }
253
254 static int armature_select_linked_poll(bContext *C)
255 {
256         return (ED_operator_view3d_active(C) && ED_operator_editarmature(C));
257 }
258
259 void ARMATURE_OT_select_linked(wmOperatorType *ot)
260 {
261         /* identifiers */
262         ot->name = "Select Connected";
263         ot->idname = "ARMATURE_OT_select_linked";
264         ot->description = "Select bones related to selected ones by parent/child relationships";
265         
266         /* api callbacks */
267         /* leave 'exec' unset */
268         ot->invoke = armature_select_linked_invoke;
269         ot->poll = armature_select_linked_poll;
270         
271         /* flags */
272         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
273         
274         /* properties */
275         RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
276 }
277
278 /* utility function for get_nearest_editbonepoint */
279 static int selectbuffer_ret_hits_12(unsigned int *UNUSED(buffer), const int hits12)
280 {
281         return hits12;
282 }
283
284 static int selectbuffer_ret_hits_5(unsigned int *buffer, const int hits12, const int hits5)
285 {
286         const int offs = 4 * hits12;
287         memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(unsigned int));
288         return hits5;
289 }
290
291 /* does bones and points */
292 /* note that BONE ROOT only gets drawn for root bones (or without IK) */
293 static EditBone *get_nearest_editbonepoint(
294         ViewContext *vc, const int mval[2],
295         ListBase *edbo, bool findunsel, bool use_cycle, int *r_selmask)
296 {
297         bArmature *arm = (bArmature *)vc->obedit->data;
298         EditBone *ebone_next_act = arm->act_edbone;
299
300         EditBone *ebone;
301         rcti rect;
302         unsigned int buffer[MAXPICKBUF];
303         unsigned int hitresult, besthitresult = BONESEL_NOSEL;
304         int i, mindep = 5;
305         int hits12, hits5 = 0;
306
307         static int last_mval[2] = {-100, -100};
308
309         /* find the bone after the current active bone, so as to bump up its chances in selection.
310          * this way overlapping bones will cycle selection state as with objects. */
311         if (ebone_next_act &&
312             EBONE_VISIBLE(arm, ebone_next_act) &&
313             ebone_next_act->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL))
314         {
315                 ebone_next_act = ebone_next_act->next ? ebone_next_act->next : arm->edbo->first;
316         }
317         else {
318                 ebone_next_act = NULL;
319         }
320
321         bool do_nearest = false;
322
323         /* define if we use solid nearest select or not */
324         if (use_cycle) {
325                 if (vc->v3d->drawtype > OB_WIRE) {
326                         do_nearest = true;
327                         if (len_manhattan_v2v2_int(mval, last_mval) < 3) {
328                                 do_nearest = false;
329                         }
330                 }
331                 copy_v2_v2_int(last_mval, mval);
332         }
333         else {
334                 if (vc->v3d->drawtype > OB_WIRE) {
335                         do_nearest = true;
336                 }
337         }
338
339         /* matching logic from 'mixed_bones_object_selectbuffer' */
340         const int select_mode = (do_nearest ? VIEW3D_SELECT_PICK_NEAREST : VIEW3D_SELECT_PICK_ALL);
341         int hits = 0;
342
343         /* we _must_ end cache before return, use 'goto cache_end' */
344         view3d_opengl_select_cache_begin();
345
346         BLI_rcti_init_pt_radius(&rect, mval, 12);
347         hits12 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode);
348         if (hits12 == 1) {
349                 hits = selectbuffer_ret_hits_12(buffer, hits12);
350                 goto cache_end;
351         }
352         else if (hits12 > 0) {
353                 int offs;
354
355                 offs = 4 * hits12;
356                 BLI_rcti_init_pt_radius(&rect, mval, 5);
357                 hits5 = view3d_opengl_select(vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode);
358
359                 if (hits5 == 1) {
360                         hits = selectbuffer_ret_hits_5(buffer, hits12, hits5);
361                         goto cache_end;
362                 }
363
364                 if      (hits5 > 0) { hits = selectbuffer_ret_hits_5(buffer,  hits12, hits5); goto cache_end; }
365                 else                { hits = selectbuffer_ret_hits_12(buffer, hits12); goto cache_end; }
366         }
367
368 cache_end:
369         view3d_opengl_select_cache_end();
370
371         /* See if there are any selected bones in this group */
372         if (hits > 0) {
373
374                 if (hits == 1) {
375                         if (!(buffer[3] & BONESEL_NOSEL))
376                                 besthitresult = buffer[3];
377                 }
378                 else {
379                         for (i = 0; i < hits; i++) {
380                                 hitresult = buffer[3 + (i * 4)];
381                                 if (!(hitresult & BONESEL_NOSEL)) {
382                                         int dep;
383                                         
384                                         ebone = BLI_findlink(edbo, hitresult & ~BONESEL_ANY);
385                                         
386                                         /* clicks on bone points get advantage */
387                                         if (hitresult & (BONESEL_ROOT | BONESEL_TIP)) {
388                                                 /* but also the unselected one */
389                                                 if (findunsel) {
390                                                         if ( (hitresult & BONESEL_ROOT) && (ebone->flag & BONE_ROOTSEL) == 0)
391                                                                 dep = 1;
392                                                         else if ( (hitresult & BONESEL_TIP) && (ebone->flag & BONE_TIPSEL) == 0)
393                                                                 dep = 1;
394                                                         else 
395                                                                 dep = 2;
396                                                 }
397                                                 else {
398                                                         dep = 1;
399                                                 }
400                                         }
401                                         else {
402                                                 /* bone found */
403                                                 if (findunsel) {
404                                                         if ((ebone->flag & BONE_SELECTED) == 0)
405                                                                 dep = 3;
406                                                         else
407                                                                 dep = 4;
408                                                 }
409                                                 else {
410                                                         dep = 3;
411                                                 }
412                                         }
413
414                                         if (ebone == ebone_next_act) {
415                                                 dep -= 1;
416                                         }
417
418                                         if (dep < mindep) {
419                                                 mindep = dep;
420                                                 besthitresult = hitresult;
421                                         }
422                                 }
423                         }
424                 }
425                 
426                 if (!(besthitresult & BONESEL_NOSEL)) {
427                         
428                         ebone = BLI_findlink(edbo, besthitresult & ~BONESEL_ANY);
429                         
430                         *r_selmask = 0;
431                         if (besthitresult & BONESEL_ROOT)
432                                 *r_selmask |= BONE_ROOTSEL;
433                         if (besthitresult & BONESEL_TIP)
434                                 *r_selmask |= BONE_TIPSEL;
435                         if (besthitresult & BONESEL_BONE)
436                                 *r_selmask |= BONE_SELECTED;
437                         return ebone;
438                 }
439         }
440         *r_selmask = 0;
441         return NULL;
442 }
443
444 void ED_armature_deselect_all(Object *obedit)
445 {
446         bArmature *arm = obedit->data;
447         EditBone *ebone;
448
449         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
450                 ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
451         }
452 }
453
454 void ED_armature_deselect_all_visible(Object *obedit)
455 {
456         bArmature *arm = obedit->data;
457         EditBone    *ebone;
458
459         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
460                 /* first and foremost, bone must be visible and selected */
461                 if (EBONE_VISIBLE(arm, ebone)) {
462                         ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
463                 }
464         }
465
466         ED_armature_sync_selection(arm->edbo);
467 }
468
469 /* accounts for connected parents */
470 static int ebone_select_flag(EditBone *ebone)
471 {
472         if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
473                 return ((ebone->parent->flag & BONE_TIPSEL) ? BONE_ROOTSEL : 0) | (ebone->flag & (BONE_SELECTED | BONE_TIPSEL));
474         }
475         else {
476                 return ebone->flag & (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL);
477         }
478 }
479
480 /* context: editmode armature in view3d */
481 bool ED_armature_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle)
482 {
483         Object *obedit = CTX_data_edit_object(C);
484         bArmature *arm = obedit->data;
485         ViewContext vc;
486         EditBone *nearBone = NULL;
487         int selmask;
488
489         view3d_set_viewcontext(C, &vc);
490         
491         if (BIF_sk_selectStroke(C, mval, extend)) {
492                 return true;
493         }
494
495         nearBone = get_nearest_editbonepoint(&vc, mval, arm->edbo, true, true, &selmask);
496         if (nearBone) {
497
498                 if (!extend && !deselect && !toggle) {
499                         ED_armature_deselect_all(obedit);
500                 }
501                 
502                 /* by definition the non-root connected bones have no root point drawn,
503                  * so a root selection needs to be delivered to the parent tip */
504                 
505                 if (selmask & BONE_SELECTED) {
506                         if (nearBone->parent && (nearBone->flag & BONE_CONNECTED)) {
507                                 /* click in a chain */
508                                 if (extend) {
509                                         /* select this bone */
510                                         nearBone->flag |= BONE_TIPSEL;
511                                         nearBone->parent->flag |= BONE_TIPSEL;
512                                 }
513                                 else if (deselect) {
514                                         /* deselect this bone */
515                                         nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
516                                         /* only deselect parent tip if it is not selected */
517                                         if (!(nearBone->parent->flag & BONE_SELECTED))
518                                                 nearBone->parent->flag &= ~BONE_TIPSEL;
519                                 }
520                                 else if (toggle) {
521                                         /* hold shift inverts this bone's selection */
522                                         if (nearBone->flag & BONE_SELECTED) {
523                                                 /* deselect this bone */
524                                                 nearBone->flag &= ~(BONE_TIPSEL | BONE_SELECTED);
525                                                 /* only deselect parent tip if it is not selected */
526                                                 if (!(nearBone->parent->flag & BONE_SELECTED))
527                                                         nearBone->parent->flag &= ~BONE_TIPSEL;
528                                         }
529                                         else {
530                                                 /* select this bone */
531                                                 nearBone->flag |= BONE_TIPSEL;
532                                                 nearBone->parent->flag |= BONE_TIPSEL;
533                                         }
534                                 }
535                                 else {
536                                         /* select this bone */
537                                         nearBone->flag |= BONE_TIPSEL;
538                                         nearBone->parent->flag |= BONE_TIPSEL;
539                                 }
540                         }
541                         else {
542                                 if (extend) {
543                                         nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
544                                 }
545                                 else if (deselect) {
546                                         nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
547                                 }
548                                 else if (toggle) {
549                                         /* hold shift inverts this bone's selection */
550                                         if (nearBone->flag & BONE_SELECTED)
551                                                 nearBone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL);
552                                         else
553                                                 nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
554                                 }
555                                 else
556                                         nearBone->flag |= (BONE_TIPSEL | BONE_ROOTSEL);
557                         }
558                 }
559                 else {
560                         if (extend)
561                                 nearBone->flag |= selmask;
562                         else if (deselect)
563                                 nearBone->flag &= ~selmask;
564                         else if (toggle && (nearBone->flag & selmask))
565                                 nearBone->flag &= ~selmask;
566                         else
567                                 nearBone->flag |= selmask;
568                 }
569                 
570                 ED_armature_sync_selection(arm->edbo);
571                 
572                 if (nearBone) {
573                         /* then now check for active status */
574                         if (ebone_select_flag(nearBone)) {
575                                 arm->act_edbone = nearBone;
576                         }
577                 }
578                 
579                 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
580                 return true;
581         }
582
583         return false;
584 }
585
586
587 /* ****************  Selections  ******************/
588
589 static int armature_de_select_all_exec(bContext *C, wmOperator *op)
590 {
591         int action = RNA_enum_get(op->ptr, "action");
592
593         if (action == SEL_TOGGLE) {
594                 /* Determine if there are any selected bones
595                  * And therefore whether we are selecting or deselecting */
596                 action = SEL_SELECT;
597                 CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
598                 {
599                         if (ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)) {
600                                 action = SEL_DESELECT;
601                                 break;
602                         }
603                 }
604                 CTX_DATA_END;
605         }
606         
607         /*      Set the flags */
608         CTX_DATA_BEGIN(C, EditBone *, ebone, visible_bones)
609         {
610                 /* ignore bone if selection can't change */
611                 switch (action) {
612                         case SEL_SELECT:
613                                 if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
614                                         ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
615                                         if (ebone->parent) {
616                                                 ebone->parent->flag |= (BONE_TIPSEL);
617                                         }
618                                 }
619                                 break;
620                         case SEL_DESELECT:
621                                 ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
622                                 break;
623                         case SEL_INVERT:
624                                 if (ebone->flag & BONE_SELECTED) {
625                                         ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
626                                 }
627                                 else {
628                                         if ((ebone->flag & BONE_UNSELECTABLE) == 0) {
629                                                 ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
630                                                 if (ebone->parent) {
631                                                         ebone->parent->flag |= (BONE_TIPSEL);
632                                                 }
633                                         }
634                                 }
635                                 break;
636                 }
637         }
638         CTX_DATA_END;
639
640         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, NULL);
641         
642         return OPERATOR_FINISHED;
643 }
644
645 void ARMATURE_OT_select_all(wmOperatorType *ot)
646 {
647         /* identifiers */
648         ot->name = "(De)select All";
649         ot->idname = "ARMATURE_OT_select_all";
650         ot->description = "Toggle selection status of all bones";
651         
652         /* api callbacks */
653         ot->exec = armature_de_select_all_exec;
654         ot->poll = ED_operator_editarmature;
655         
656         /* flags */
657         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
658         
659         WM_operator_properties_select_all(ot);
660 }
661
662 /**************** Select more/less **************/
663
664 static void armature_select_more(bArmature *arm, EditBone *ebone)
665 {
666         if ((EBONE_PREV_FLAG_GET(ebone) & (BONE_ROOTSEL | BONE_TIPSEL)) != 0) {
667                 if (EBONE_SELECTABLE(arm, ebone)) {
668                         ED_armature_ebone_select_set(ebone, true);
669                 }
670         }
671
672         if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
673                 /* to parent */
674                 if ((EBONE_PREV_FLAG_GET(ebone) & BONE_ROOTSEL) != 0) {
675                         if (EBONE_SELECTABLE(arm, ebone->parent)) {
676                                 ED_armature_ebone_selectflag_enable(ebone->parent, (BONE_SELECTED | BONE_ROOTSEL | BONE_TIPSEL));
677                         }
678                 }
679
680                 /* from parent (difference from select less) */
681                 if ((EBONE_PREV_FLAG_GET(ebone->parent) & BONE_TIPSEL) != 0) {
682                         if (EBONE_SELECTABLE(arm, ebone)) {
683                                 ED_armature_ebone_selectflag_enable(ebone, (BONE_SELECTED | BONE_ROOTSEL));
684                         }
685                 }
686         }
687 }
688
689 static void armature_select_less(bArmature *UNUSED(arm), EditBone *ebone)
690 {
691         if ((EBONE_PREV_FLAG_GET(ebone) & (BONE_ROOTSEL | BONE_TIPSEL)) != (BONE_ROOTSEL | BONE_TIPSEL)) {
692                 ED_armature_ebone_select_set(ebone, false);
693         }
694
695         if (ebone->parent && (ebone->flag & BONE_CONNECTED)) {
696                 /* to parent */
697                 if ((EBONE_PREV_FLAG_GET(ebone) & BONE_SELECTED) == 0) {
698                         ED_armature_ebone_selectflag_disable(ebone->parent, (BONE_SELECTED | BONE_TIPSEL));
699                 }
700
701                 /* from parent (difference from select more) */
702                 if ((EBONE_PREV_FLAG_GET(ebone->parent) & BONE_SELECTED) == 0) {
703                         ED_armature_ebone_selectflag_disable(ebone, (BONE_SELECTED | BONE_ROOTSEL));
704                 }
705         }
706 }
707
708 static void armature_select_more_less(Object *ob, bool more)
709 {
710         bArmature *arm = (bArmature *)ob->data;
711         EditBone *ebone;
712
713         /* XXX, eventually we shouldn't need this - campbell */
714         ED_armature_sync_selection(arm->edbo);
715
716         /* count bones & store selection state */
717         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
718                 EBONE_PREV_FLAG_SET(ebone, ED_armature_ebone_selectflag_get(ebone));
719         }
720
721         /* do selection */
722         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
723                 if (EBONE_VISIBLE(arm, ebone)) {
724                         if (more) {
725                                 armature_select_more(arm, ebone);
726                         }
727                         else {
728                                 armature_select_less(arm, ebone);
729                         }
730                 }
731         }
732
733         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
734                 if (EBONE_VISIBLE(arm, ebone)) {
735                         if (more == false) {
736                                 if (ebone->flag & BONE_SELECTED) {
737                                         ED_armature_ebone_select_set(ebone, true);
738                                 }
739                         }
740                 }
741                 ebone->temp.p = NULL;
742         }
743
744         ED_armature_sync_selection(arm->edbo);
745 }
746
747 static int armature_de_select_more_exec(bContext *C, wmOperator *UNUSED(op))
748 {
749         Object *obedit = CTX_data_edit_object(C);
750         armature_select_more_less(obedit, true);
751         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
752
753         return OPERATOR_FINISHED;
754 }
755
756 void ARMATURE_OT_select_more(wmOperatorType *ot)
757 {
758         /* identifiers */
759         ot->name = "Select More";
760         ot->idname = "ARMATURE_OT_select_more";
761         ot->description = "Select those bones connected to the initial selection";
762
763         /* api callbacks */
764         ot->exec = armature_de_select_more_exec;
765         ot->poll = ED_operator_editarmature;
766
767         /* flags */
768         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
769 }
770
771 static int armature_de_select_less_exec(bContext *C, wmOperator *UNUSED(op))
772 {
773         Object *obedit = CTX_data_edit_object(C);
774         armature_select_more_less(obedit, false);
775         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
776
777         return OPERATOR_FINISHED;
778 }
779
780 void ARMATURE_OT_select_less(wmOperatorType *ot)
781 {
782         /* identifiers */
783         ot->name = "Select Less";
784         ot->idname = "ARMATURE_OT_select_less";
785         ot->description = "Deselect those bones at the boundary of each selection region";
786
787         /* api callbacks */
788         ot->exec = armature_de_select_less_exec;
789         ot->poll = ED_operator_editarmature;
790
791         /* flags */
792         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
793 }
794
795 enum {
796         SIMEDBONE_CHILDREN = 1,
797         SIMEDBONE_CHILDREN_IMMEDIATE,
798         SIMEDBONE_SIBLINGS,
799         SIMEDBONE_LENGTH,
800         SIMEDBONE_DIRECTION,
801         SIMEDBONE_PREFIX,
802         SIMEDBONE_SUFFIX,
803         SIMEDBONE_LAYER,
804 };
805
806 static EnumPropertyItem prop_similar_types[] = {
807         {SIMEDBONE_CHILDREN, "CHILDREN", 0, "Children", ""},
808         {SIMEDBONE_CHILDREN_IMMEDIATE, "CHILDREN_IMMEDIATE", 0, "Immediate children", ""},
809         {SIMEDBONE_SIBLINGS, "SIBLINGS", 0, "Siblings", ""},
810         {SIMEDBONE_LENGTH, "LENGTH", 0, "Length", ""},
811         {SIMEDBONE_DIRECTION, "DIRECTION", 0, "Direction (Y axis)", ""},
812         {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""},
813         {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""},
814         {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""},
815         {0, NULL, 0, NULL, NULL}
816 };
817
818
819 static void select_similar_length(bArmature *arm, EditBone *ebone_act, const float thresh)
820 {
821         EditBone *ebone;
822
823         /* thresh is always relative to current length */
824         const float len_min = ebone_act->length / (1.0f + thresh);
825         const float len_max = ebone_act->length * (1.0f + thresh);
826
827         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
828                 if (EBONE_SELECTABLE(arm, ebone)) {
829                         if ((ebone->length >= len_min) &&
830                             (ebone->length <= len_max))
831                         {
832                                 ED_armature_ebone_select_set(ebone, true);
833                         }
834                 }
835         }
836 }
837
838 static void select_similar_direction(bArmature *arm, EditBone *ebone_act, const float thresh)
839 {
840         EditBone *ebone;
841         float dir_act[3];
842         sub_v3_v3v3(dir_act, ebone_act->head, ebone_act->tail);
843
844         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
845                 if (EBONE_SELECTABLE(arm, ebone)) {
846                         float dir[3];
847                         sub_v3_v3v3(dir, ebone->head, ebone->tail);
848
849                         if (angle_v3v3(dir_act, dir) / (float)M_PI < thresh) {
850                                 ED_armature_ebone_select_set(ebone, true);
851                         }
852                 }
853         }
854 }
855
856 static void select_similar_layer(bArmature *arm, EditBone *ebone_act)
857 {
858         EditBone *ebone;
859
860         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
861                 if (EBONE_SELECTABLE(arm, ebone)) {
862                         if (ebone->layer & ebone_act->layer) {
863                                 ED_armature_ebone_select_set(ebone, true);
864                         }
865                 }
866         }
867 }
868
869 static void select_similar_prefix(bArmature *arm, EditBone *ebone_act)
870 {
871         EditBone *ebone;
872
873         char body_tmp[MAXBONENAME];
874         char prefix_act[MAXBONENAME];
875
876         BLI_string_split_prefix(ebone_act->name, prefix_act, body_tmp, sizeof(ebone_act->name));
877
878         if (prefix_act[0] == '\0')
879                 return;
880
881         /* Find matches */
882         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
883                 if (EBONE_SELECTABLE(arm, ebone)) {
884                         char prefix_other[MAXBONENAME];
885                         BLI_string_split_prefix(ebone->name, prefix_other, body_tmp, sizeof(ebone->name));
886                         if (STREQ(prefix_act, prefix_other)) {
887                                 ED_armature_ebone_select_set(ebone, true);
888                         }
889                 }
890         }
891 }
892
893 static void select_similar_suffix(bArmature *arm, EditBone *ebone_act)
894 {
895         EditBone *ebone;
896
897         char body_tmp[MAXBONENAME];
898         char suffix_act[MAXBONENAME];
899
900         BLI_string_split_suffix(ebone_act->name, body_tmp, suffix_act, sizeof(ebone_act->name));
901
902         if (suffix_act[0] == '\0')
903                 return;
904
905         /* Find matches */
906         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
907                 if (EBONE_SELECTABLE(arm, ebone)) {
908                         char suffix_other[MAXBONENAME];
909                         BLI_string_split_suffix(ebone->name, body_tmp, suffix_other, sizeof(ebone->name));
910                         if (STREQ(suffix_act, suffix_other)) {
911                                 ED_armature_ebone_select_set(ebone, true);
912                         }
913                 }
914         }
915 }
916
917 static void is_ancestor(EditBone * bone, EditBone * ancestor)
918 {
919         if (bone->temp.ebone == ancestor || bone->temp.ebone == NULL)
920                 return;
921
922         if (bone->temp.ebone->temp.ebone != NULL && bone->temp.ebone->temp.ebone != ancestor)
923                 is_ancestor(bone->temp.ebone, ancestor);
924
925         bone->temp.ebone = bone->temp.ebone->temp.ebone;
926 }
927
928 static void select_similar_children(bArmature *arm, EditBone *ebone_act)
929 {
930         EditBone *ebone_iter;
931
932         for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
933                 ebone_iter->temp.ebone = ebone_iter->parent;
934         }
935
936         for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
937                 is_ancestor(ebone_iter, ebone_act);
938
939                 if (ebone_iter->temp.ebone == ebone_act && EBONE_SELECTABLE(arm, ebone_iter))
940                         ED_armature_ebone_select_set(ebone_iter, true);
941         }
942 }
943
944 static void select_similar_children_immediate(bArmature *arm, EditBone *ebone_act)
945 {
946         EditBone *ebone_iter;
947         for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
948                 if (ebone_iter->parent == ebone_act && EBONE_SELECTABLE(arm, ebone_iter)) {
949                         ED_armature_ebone_select_set(ebone_iter, true);
950                 }
951         }
952 }
953
954 static void select_similar_siblings(bArmature *arm, EditBone *ebone_act)
955 {
956         EditBone *ebone_iter;
957
958         if (ebone_act->parent == NULL)
959                 return;
960
961         for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
962                 if (ebone_iter->parent == ebone_act->parent && EBONE_SELECTABLE(arm, ebone_iter)) {
963                         ED_armature_ebone_select_set(ebone_iter, true);
964                 }
965         }
966 }
967
968 static int armature_select_similar_exec(bContext *C, wmOperator *op)
969 {
970         Object *obedit = CTX_data_edit_object(C);
971         bArmature *arm = obedit->data;
972         EditBone *ebone_act = CTX_data_active_bone(C);
973
974         /* Get props */
975         int type = RNA_enum_get(op->ptr, "type");
976         float thresh = RNA_float_get(op->ptr, "threshold");
977
978         /* Check for active bone */
979         if (ebone_act == NULL) {
980                 BKE_report(op->reports, RPT_ERROR, "Operation requires an active bone");
981                 return OPERATOR_CANCELLED;
982         }
983
984         switch (type) {
985                 case SIMEDBONE_CHILDREN:
986                         select_similar_children(arm, ebone_act);
987                         break;
988                 case SIMEDBONE_CHILDREN_IMMEDIATE:
989                         select_similar_children_immediate(arm, ebone_act);
990                         break;
991                 case SIMEDBONE_SIBLINGS:
992                         select_similar_siblings(arm, ebone_act);
993                         break;
994                 case SIMEDBONE_LENGTH:
995                         select_similar_length(arm, ebone_act, thresh);
996                         break;
997                 case SIMEDBONE_DIRECTION:
998                         select_similar_direction(arm, ebone_act, thresh);
999                         break;
1000                 case SIMEDBONE_PREFIX:
1001                         select_similar_prefix(arm, ebone_act);
1002                         break;
1003                 case SIMEDBONE_SUFFIX:
1004                         select_similar_suffix(arm, ebone_act);
1005                         break;
1006                 case SIMEDBONE_LAYER:
1007                         select_similar_layer(arm, ebone_act);
1008                         break;
1009         }
1010
1011         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1012
1013         return OPERATOR_FINISHED;
1014 }
1015
1016 void ARMATURE_OT_select_similar(wmOperatorType *ot)
1017 {
1018         /* identifiers */
1019         ot->name = "Select Similar";
1020         ot->idname = "ARMATURE_OT_select_similar";
1021
1022         /* callback functions */
1023         ot->invoke = WM_menu_invoke;
1024         ot->exec = armature_select_similar_exec;
1025         ot->poll = ED_operator_editarmature;
1026         ot->description = "Select similar bones by property types";
1027
1028         /* flags */
1029         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1030
1031         /* properties */
1032         ot->prop = RNA_def_enum(ot->srna, "type", prop_similar_types, SIMEDBONE_LENGTH, "Type", "");
1033         RNA_def_float(ot->srna, "threshold", 0.1f, 0.0f, 1.0f, "Threshold", "", 0.0f, 1.0f);
1034 }
1035
1036 /* ********************* select hierarchy operator ************** */
1037
1038 static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
1039 {
1040         Object *obedit = CTX_data_edit_object(C);
1041         Object *ob;
1042         bArmature *arm;
1043         EditBone *ebone_active;
1044         int direction = RNA_enum_get(op->ptr, "direction");
1045         const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
1046         bool changed = false;
1047         
1048         ob = obedit;
1049         arm = (bArmature *)ob->data;
1050
1051         ebone_active = arm->act_edbone;
1052         if (ebone_active == NULL) {
1053                 return OPERATOR_CANCELLED;
1054         }
1055
1056         if (direction == BONE_SELECT_PARENT) {
1057                 if (ebone_active->parent) {
1058                         EditBone *ebone_parent;
1059
1060                         ebone_parent = ebone_active->parent;
1061
1062                         if (EBONE_SELECTABLE(arm, ebone_parent)) {
1063                                 arm->act_edbone = ebone_parent;
1064
1065                                 if (!add_to_sel) {
1066                                         ED_armature_ebone_select_set(ebone_active, false);
1067                                 }
1068                                 ED_armature_ebone_select_set(ebone_parent, true);
1069
1070                                 changed = true;
1071                         }
1072                 }
1073
1074         }
1075         else {  /* BONE_SELECT_CHILD */
1076                 EditBone *ebone_iter, *ebone_child = NULL;
1077                 int pass;
1078
1079                 /* first pass, only connected bones (the logical direct child) */
1080                 for (pass = 0; pass < 2 && (ebone_child == NULL); pass++) {
1081                         for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
1082                                 /* possible we have multiple children, some invisible */
1083                                 if (EBONE_SELECTABLE(arm, ebone_iter)) {
1084                                         if (ebone_iter->parent == ebone_active) {
1085                                                 if ((pass == 1) || (ebone_iter->flag & BONE_CONNECTED)) {
1086                                                         ebone_child = ebone_iter;
1087                                                         break;
1088                                                 }
1089                                         }
1090                                 }
1091                         }
1092                 }
1093
1094                 if (ebone_child) {
1095                         arm->act_edbone = ebone_child;
1096
1097                         if (!add_to_sel) {
1098                                 ED_armature_ebone_select_set(ebone_active, false);
1099                         }
1100                         ED_armature_ebone_select_set(ebone_child, true);
1101
1102                         changed = true;
1103                 }
1104         }
1105         
1106         if (changed == false) {
1107                 return OPERATOR_CANCELLED;
1108         }
1109
1110         ED_armature_sync_selection(arm->edbo);
1111         
1112         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
1113         
1114         return OPERATOR_FINISHED;
1115 }
1116
1117 void ARMATURE_OT_select_hierarchy(wmOperatorType *ot)
1118 {
1119         static EnumPropertyItem direction_items[] = {
1120                 {BONE_SELECT_PARENT, "PARENT", 0, "Select Parent", ""},
1121                 {BONE_SELECT_CHILD, "CHILD", 0, "Select Child", ""},
1122                 {0, NULL, 0, NULL, NULL}
1123         };
1124         
1125         /* identifiers */
1126         ot->name = "Select Hierarchy";
1127         ot->idname = "ARMATURE_OT_select_hierarchy";
1128         ot->description = "Select immediate parent/children of selected bones";
1129         
1130         /* api callbacks */
1131         ot->exec = armature_select_hierarchy_exec;
1132         ot->poll = ED_operator_editarmature;
1133         
1134         /* flags */
1135         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1136
1137         /* props */
1138         RNA_def_enum(ot->srna, "direction", direction_items,
1139                      BONE_SELECT_PARENT, "Direction", "");
1140         RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
1141 }
1142
1143 /****************** Mirror Select ****************/
1144
1145 /**
1146  * \note clone of #pose_select_mirror_exec keep in sync
1147  */
1148 static int armature_select_mirror_exec(bContext *C, wmOperator *op)
1149 {
1150         Object *obedit = CTX_data_edit_object(C);
1151         bArmature *arm = obedit->data;
1152         EditBone *ebone, *ebone_mirror_act = NULL;
1153         const bool active_only = RNA_boolean_get(op->ptr, "only_active");
1154         const bool extend = RNA_boolean_get(op->ptr, "extend");
1155
1156         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1157                 const int flag = ED_armature_ebone_selectflag_get(ebone);
1158                 EBONE_PREV_FLAG_SET(ebone, flag);
1159         }
1160
1161         for (ebone = arm->edbo->first; ebone; ebone = ebone->next) {
1162                 if (EBONE_SELECTABLE(arm, ebone)) {
1163                         EditBone *ebone_mirror;
1164                         int flag_new = extend ? EBONE_PREV_FLAG_GET(ebone) : 0;
1165
1166                         if ((ebone_mirror = ED_armature_bone_get_mirrored(arm->edbo, ebone)) &&
1167                             (EBONE_VISIBLE(arm, ebone_mirror)))
1168                         {
1169                                 const int flag_mirror = EBONE_PREV_FLAG_GET(ebone_mirror);
1170                                 flag_new |= flag_mirror;
1171
1172                                 if (ebone == arm->act_edbone) {
1173                                         ebone_mirror_act = ebone_mirror;
1174                                 }
1175
1176                                 /* skip all but the active or its mirror */
1177                                 if (active_only && !ELEM(arm->act_edbone, ebone, ebone_mirror)) {
1178                                         continue;
1179                                 }
1180                         }
1181
1182                         ED_armature_ebone_selectflag_set(ebone, flag_new);
1183                 }
1184         }
1185
1186         if (ebone_mirror_act) {
1187                 arm->act_edbone = ebone_mirror_act;
1188         }
1189
1190         ED_armature_sync_selection(arm->edbo);
1191
1192         WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1193
1194         return OPERATOR_FINISHED;
1195 }
1196
1197 void ARMATURE_OT_select_mirror(wmOperatorType *ot)
1198 {
1199         /* identifiers */
1200         ot->name = "Flip Active/Selected Bone";
1201         ot->idname = "ARMATURE_OT_select_mirror";
1202         ot->description = "Mirror the bone selection";
1203
1204         /* api callbacks */
1205         ot->exec = armature_select_mirror_exec;
1206         ot->poll = ED_operator_editarmature;
1207
1208         /* flags */
1209         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1210
1211         /* properties */
1212         RNA_def_boolean(ot->srna, "only_active", false, "Active Only", "Only operate on the active bone");
1213         RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
1214 }
1215
1216
1217 /****************** Select Path ****************/
1218
1219 static bool armature_shortest_path_select(bArmature *arm, EditBone *ebone_parent, EditBone *ebone_child,
1220                                           bool use_parent, bool is_test)
1221 {
1222         do {
1223
1224                 if (!use_parent && (ebone_child == ebone_parent))
1225                         break;
1226
1227                 if (is_test) {
1228                         if (!EBONE_SELECTABLE(arm, ebone_child)) {
1229                                 return false;
1230                         }
1231                 }
1232                 else {
1233                         ED_armature_ebone_selectflag_set(ebone_child, (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL));
1234                 }
1235
1236                 if (ebone_child == ebone_parent)
1237                         break;
1238
1239                 ebone_child = ebone_child->parent;
1240         } while (true);
1241
1242         return true;
1243 }
1244
1245 static int armature_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1246 {
1247         Object *obedit = CTX_data_edit_object(C);
1248         bArmature *arm = obedit->data;
1249         EditBone *ebone_src, *ebone_dst;
1250         EditBone *ebone_isect_parent = NULL;
1251         EditBone *ebone_isect_child[2];
1252         bool changed;
1253
1254         view3d_operator_needs_opengl(C);
1255
1256         ebone_src = arm->act_edbone;
1257         ebone_dst = get_nearest_bone(C, event->mval, false);
1258
1259         /* fallback to object selection */
1260         if (ELEM(NULL, ebone_src, ebone_dst) || (ebone_src == ebone_dst)) {
1261                 return OPERATOR_PASS_THROUGH;
1262         }
1263
1264         ebone_isect_child[0] = ebone_src;
1265         ebone_isect_child[1] = ebone_dst;
1266
1267
1268         /* ensure 'ebone_src' is the parent of 'ebone_dst', or set 'ebone_isect_parent' */
1269         if (ED_armature_ebone_is_child_recursive(ebone_src, ebone_dst)) {
1270                 /* pass */
1271         }
1272         else if (ED_armature_ebone_is_child_recursive(ebone_dst, ebone_src)) {
1273                 SWAP(EditBone *, ebone_src, ebone_dst);
1274         }
1275         else if ((ebone_isect_parent = ED_armature_bone_find_shared_parent(ebone_isect_child, 2))) {
1276                 /* pass */
1277         }
1278         else {
1279                 /* disconnected bones */
1280                 return OPERATOR_CANCELLED;
1281         }
1282
1283
1284         if (ebone_isect_parent) {
1285                 if (armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, true) &&
1286                     armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, true))
1287                 {
1288                         armature_shortest_path_select(arm, ebone_isect_parent, ebone_src, false, false);
1289                         armature_shortest_path_select(arm, ebone_isect_parent, ebone_dst, false, false);
1290                         changed = true;
1291                 }
1292                 else {
1293                         /* unselectable */
1294                         changed = false;
1295                 }
1296         }
1297         else {
1298                 if (armature_shortest_path_select(arm, ebone_src, ebone_dst, true, true)) {
1299                         armature_shortest_path_select(arm, ebone_src, ebone_dst, true, false);
1300                         changed = true;
1301                 }
1302                 else {
1303                         /* unselectable */
1304                         changed = false;
1305                 }
1306         }
1307
1308         if (changed) {
1309                 arm->act_edbone = ebone_dst;
1310                 ED_armature_sync_selection(arm->edbo);
1311                 WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit);
1312
1313                 return OPERATOR_FINISHED;
1314         }
1315         else {
1316                 BKE_report(op->reports, RPT_WARNING, "Unselectable bone in chain");
1317                 return OPERATOR_CANCELLED;
1318         }
1319 }
1320
1321 void ARMATURE_OT_shortest_path_pick(wmOperatorType *ot)
1322 {
1323         /* identifiers */
1324         ot->name = "Pick Shortest Path";
1325         ot->idname = "ARMATURE_OT_shortest_path_pick";
1326         ot->description = "Select shortest path between two bones";
1327
1328         /* api callbacks */
1329         ot->invoke = armature_shortest_path_pick_invoke;
1330         ot->poll = ED_operator_editarmature;
1331
1332         /* flags */
1333         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1334 }