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