Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Ebb <matt@mke3.net>2008-08-04 15:47:17 +0400
committerMatt Ebb <matt@mke3.net>2008-08-04 15:47:17 +0400
commit2e6a3710bba93cf2d6b86cf511a123068ead61bd (patch)
tree04a77cc0d431565f801f7b25a336d114164413dd /source/blender
parent3598dcd2796f819bd762f88c2d275816fed0e0d6 (diff)
* Armature hierarchy selection tools
These are for use in pose mode or armature edit mode, to let you quickly traverse up and down a chain of bones. It's quite useful for bones that are in hard-to-click places. The tools are: *Select parent/child ( [ and ] ) selects the parent or child of the active bone, deselecting the original active bone * Extend select parent/child (shift [ and shift ] ) selects the parent or child of the active bone, adding to the selection Thanks to Joshua for reviewing this so promptly! PS. I'd like to use these [ and ] keys more widely in blender as consistent 'select next / previous' tools. I can imagine it being very useful for a lot of things like keyframes, nodes, mesh edges, etc.
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/include/BIF_editarmature.h7
-rw-r--r--source/blender/include/BIF_poseobject.h2
-rw-r--r--source/blender/src/editarmature.c164
-rw-r--r--source/blender/src/header_view3d.c58
-rw-r--r--source/blender/src/poseobject.c61
-rw-r--r--source/blender/src/space.c17
6 files changed, 213 insertions, 96 deletions
diff --git a/source/blender/include/BIF_editarmature.h b/source/blender/include/BIF_editarmature.h
index da98eb3d4f1..13c16749612 100644
--- a/source/blender/include/BIF_editarmature.h
+++ b/source/blender/include/BIF_editarmature.h
@@ -108,7 +108,8 @@ void mouse_armature(void);
void remake_editArmature(void);
void selectconnected_armature(void);
void selectconnected_posearmature(void);
-void select_bone_parent(void);
+void armature_select_hierarchy(short direction, short add_to_sel);
+
void setflag_armature(short mode);
void unique_editbone_name (struct ListBase *ebones, char *name);
@@ -143,6 +144,10 @@ void set_locks_armature_bones(short lock);
#define BONESEL_NOSEL 0x80000000 /* Indicates a negative number */
+/* used in bone_select_hierachy() */
+#define BONE_SELECT_PARENT 0
+#define BONE_SELECT_CHILD 1
+
#endif
diff --git a/source/blender/include/BIF_poseobject.h b/source/blender/include/BIF_poseobject.h
index 58c67ff102a..ab96f7ec03e 100644
--- a/source/blender/include/BIF_poseobject.h
+++ b/source/blender/include/BIF_poseobject.h
@@ -65,6 +65,8 @@ void pose_assign_to_posegroup(short active);
void pose_remove_from_posegroups(void);
void pgroup_operation_with_menu(void);
+void pose_select_hierarchy(short direction, short add_to_sel);
+
void pose_select_grouped(short nr);
void pose_select_grouped_menu(void);
diff --git a/source/blender/src/editarmature.c b/source/blender/src/editarmature.c
index 3d0f26960d6..80c24f3a989 100644
--- a/source/blender/src/editarmature.c
+++ b/source/blender/src/editarmature.c
@@ -1033,87 +1033,6 @@ static void *get_nearest_bone (short findunsel)
return NULL;
}
-/* used by posemode and editmode */
-void select_bone_parent (void)
-{
- Object *ob;
- bArmature *arm;
-
- /* get data */
- if (G.obedit)
- ob= G.obedit;
- else if (OBACT)
- ob= OBACT;
- else
- return;
- arm= (bArmature *)ob->data;
-
- /* determine which mode armature is in */
- if ((!G.obedit) && (ob->flag & OB_POSEMODE)) {
- /* deal with pose channels */
- /* channels are sorted on dependency, so the loop below won't result in a flood-select */
- bPoseChannel *pchan=NULL;
-
- for (pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
- /* check if bone in original selection */
- if (pchan->bone->flag & BONE_SELECTED) {
- bPoseChannel *chanpar= pchan->parent;
-
- /* check if any parent */
- if ((chanpar) && ((chanpar->bone->flag & BONE_SELECTED)==0)) {
- chanpar->bone->flag |= BONE_SELECTED;
- select_actionchannel_by_name (ob->action, pchan->name, 1);
- }
- }
- }
- }
- else if (G.obedit) {
- /* deal with editbones */
- EditBone *curbone, *parbone, *parpar;
-
- /* prevent floods */
- for (curbone= G.edbo.first; curbone; curbone= curbone->next)
- curbone->temp= NULL;
-
- for (curbone= G.edbo.first; curbone; curbone= curbone->next) {
- /* check if bone selected */
- if ((curbone->flag & BONE_SELECTED) && curbone->temp==NULL) {
- parbone= curbone->parent;
-
- /* check if any parent */
- if ((parbone) && ((parbone->flag & BONE_SELECTED)==0)) {
- /* select the parent bone */
- parbone->flag |= (BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
-
- /* check if parent has parent */
- parpar= parbone->parent;
-
- if ((parpar) && (parbone->flag & BONE_CONNECTED)) {
- parpar->flag |= BONE_TIPSEL;
- }
- /* tag this bone to not flood selection */
- parbone->temp= parbone;
- }
- }
- }
-
- /* to be sure... */
- for (curbone= G.edbo.first; curbone; curbone= curbone->next)
- curbone->temp= NULL;
-
- }
-
- /* undo + redraw pushes */
- countall(); // flushes selection!
-
- allqueue (REDRAWVIEW3D, 0);
- allqueue (REDRAWBUTSEDIT, 0);
- allqueue(REDRAWBUTSOBJECT, 0);
- allqueue(REDRAWOOPS, 0);
-
- BIF_undo_push("Select Parent");
-}
-
/* helper for setflag_sel_bone() */
static void bone_setflag (int *bone, int flag, short mode)
{
@@ -1139,6 +1058,89 @@ static void bone_setflag (int *bone, int flag, short mode)
}
}
+/* Get the first available child of an editbone */
+static EditBone *editbone_get_child(EditBone *pabone, short use_visibility)
+{
+ Object *ob;
+ bArmature *arm;
+ EditBone *curbone, *chbone=NULL;
+
+ if (!G.obedit) return NULL;
+ else ob= G.obedit;
+ arm= (bArmature *)ob->data;
+
+ for (curbone= G.edbo.first; curbone; curbone= curbone->next) {
+ if (curbone->parent == pabone) {
+ if (use_visibility) {
+ if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A))
+ chbone = curbone;
+ }
+ else
+ chbone = curbone;
+ }
+ }
+
+ return chbone;
+}
+
+void armature_select_hierarchy(short direction, short add_to_sel)
+{
+ Object *ob;
+ bArmature *arm;
+ EditBone *curbone, *pabone, *chbone;
+
+ if (!G.obedit) return;
+ else ob= G.obedit;
+ arm= (bArmature *)ob->data;
+
+ for (curbone= G.edbo.first; curbone; curbone= curbone->next) {
+ if (arm->layer & curbone->layer) {
+ if (curbone->flag & (BONE_ACTIVE)) {
+ if (direction == BONE_SELECT_PARENT) {
+ if (curbone->parent == NULL) continue;
+ else pabone = curbone->parent;
+
+ if ((arm->layer & pabone->layer) && !(pabone->flag & BONE_HIDDEN_A)) {
+ pabone->flag |= (BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+ if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL;
+
+ if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+ curbone->flag &= ~BONE_ACTIVE;
+ break;
+ }
+
+ } else { // BONE_SELECT_CHILD
+ chbone = editbone_get_child(curbone, 1);
+ if (chbone == NULL) continue;
+
+ if ((arm->layer & chbone->layer) && !(chbone->flag & BONE_HIDDEN_A)) {
+ chbone->flag |= (BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
+
+ if (!add_to_sel) {
+ curbone->flag &= ~(BONE_SELECTED|BONE_ROOTSEL);
+ if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
+ }
+ curbone->flag &= ~BONE_ACTIVE;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ countall(); // flushes selection!
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWBUTSEDIT, 0);
+ allqueue (REDRAWBUTSOBJECT, 0);
+ allqueue (REDRAWOOPS, 0);
+
+ if (direction==BONE_SELECT_PARENT)
+ BIF_undo_push("Select edit bone parent");
+ if (direction==BONE_SELECT_CHILD)
+ BIF_undo_push("Select edit bone child");
+}
+
/* used by posemode and editmode */
void setflag_armature (short mode)
{
diff --git a/source/blender/src/header_view3d.c b/source/blender/src/header_view3d.c
index d834bd70321..948023bebfb 100644
--- a/source/blender/src/header_view3d.c
+++ b/source/blender/src/header_view3d.c
@@ -1325,12 +1325,21 @@ static void do_view3d_select_armaturemenu(void *arg, int event)
case 2: /* Select/Deselect all */
deselectall_armature(1, 1);
break;
- case 3: /* Select Parent(s) */
- select_bone_parent();
- break;
- case 4: /* Swap Select All */
+ case 3: /* Swap Select All */
deselectall_armature(3, 1);
break;
+ case 4: /* Select parent */
+ armature_select_hierarchy(BONE_SELECT_PARENT, 0);
+ break;
+ case 5: /* Select child */
+ armature_select_hierarchy(BONE_SELECT_CHILD, 0);
+ break;
+ case 6: /* Extend Select parent */
+ armature_select_hierarchy(BONE_SELECT_PARENT, 1);
+ break;
+ case 7: /* Extend Select child */
+ armature_select_hierarchy(BONE_SELECT_CHILD, 1);
+ break;
}
allqueue(REDRAWVIEW3D, 0);
}
@@ -1348,11 +1357,18 @@ static uiBlock *view3d_select_armaturemenu(void *arg_unused)
uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Inverse|Ctrl I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Swap Select All|Ctrl I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Parent|[", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Child|]", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Select Parent|Shift [", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Select Child|Shift ]", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Parent(s)|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
-
if(curarea->headertype==HEADERTOP) {
uiBlockSetDirection(block, UI_DOWN);
}
@@ -1379,12 +1395,21 @@ static void do_view3d_select_pose_armaturemenu(void *arg, int event)
case 3: /* Select Target(s) of Constraint(s) */
pose_select_constraint_target();
break;
- case 4: /* Select Bone's Parent */
- select_bone_parent();
- break;
case 5: /* Swap Select All */
deselectall_posearmature(OBACT, 3, 1);
break;
+ case 6: /* Select parent */
+ pose_select_hierarchy(BONE_SELECT_PARENT, 0);
+ break;
+ case 7: /* Select child */
+ pose_select_hierarchy(BONE_SELECT_CHILD, 0);
+ break;
+ case 8: /* Extend Select parent */
+ pose_select_hierarchy(BONE_SELECT_PARENT, 1);
+ break;
+ case 9: /* Extend Select child */
+ pose_select_hierarchy(BONE_SELECT_CHILD, 1);
+ break;
}
allqueue(REDRAWVIEW3D, 0);
}
@@ -1404,8 +1429,17 @@ static uiBlock *view3d_select_pose_armaturemenu(void *arg_unused)
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select/Deselect All|A", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 2, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Swap Select All|Ctrl I", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 5, "");
uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Constraint Target|W", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 3, "");
- uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Parent(s)|P", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 4, "");
-
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Parent|[", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 6, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Select Child|]", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 7, "");
+
+ uiDefBut(block, SEPR, 0, "", 0, yco-=6, menuwidth, 6, NULL, 0.0, 0.0, 0, 0, "");
+
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Select Parent|Shift [", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 8, "");
+ uiDefIconTextBut(block, BUTM, 1, ICON_BLANK1, "Extend Select Child|Shift ]", 0, yco-=20, menuwidth, 19, NULL, 0.0, 0.0, 1, 9, "");
+
if(curarea->headertype==HEADERTOP) {
uiBlockSetDirection(block, UI_DOWN);
}
diff --git a/source/blender/src/poseobject.c b/source/blender/src/poseobject.c
index b054b435002..28b8729a247 100644
--- a/source/blender/src/poseobject.c
+++ b/source/blender/src/poseobject.c
@@ -479,6 +479,67 @@ void pose_select_constraint_target(void)
}
+void pose_select_hierarchy(short direction, short add_to_sel)
+{
+ Object *ob= OBACT;
+ bArmature *arm= ob->data;
+ bPoseChannel *pchan;
+ Bone *curbone, *pabone, *chbone;
+
+ /* paranoia checks */
+ if (!ob && !ob->pose) return;
+ if (ob==G.obedit || (ob->flag & OB_POSEMODE)==0) return;
+
+ for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
+ curbone= pchan->bone;
+
+ if (arm->layer & curbone->layer) {
+ if (curbone->flag & (BONE_ACTIVE)) {
+ if (direction == BONE_SELECT_PARENT) {
+
+ if (pchan->parent == NULL) continue;
+ else pabone= pchan->parent->bone;
+
+ if ((arm->layer & pabone->layer) && !(pabone->flag & BONE_HIDDEN_P)) {
+
+ if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
+ curbone->flag &= ~BONE_ACTIVE;
+ pabone->flag |= (BONE_ACTIVE|BONE_SELECTED);
+
+ select_actionchannel_by_name (ob->action, pchan->name, 0);
+ select_actionchannel_by_name (ob->action, pchan->parent->name, 1);
+ break;
+ }
+ } else { // BONE_SELECT_CHILD
+
+ if (pchan->child == NULL) continue;
+ else chbone = pchan->child->bone;
+
+ if ((arm->layer & chbone->layer) && !(chbone->flag & BONE_HIDDEN_P)) {
+
+ if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
+ curbone->flag &= ~BONE_ACTIVE;
+ chbone->flag |= (BONE_ACTIVE|BONE_SELECTED);
+
+ select_actionchannel_by_name (ob->action, pchan->name, 0);
+ select_actionchannel_by_name (ob->action, pchan->child->name, 1);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ allqueue (REDRAWVIEW3D, 0);
+ allqueue (REDRAWBUTSOBJECT, 0);
+ allqueue (REDRAWOOPS, 0);
+
+ if (direction==BONE_SELECT_PARENT)
+ BIF_undo_push("Select pose bone parent");
+ if (direction==BONE_SELECT_CHILD)
+ BIF_undo_push("Select pose bone child");
+}
+
/* context: active channel */
void pose_special_editmenu(void)
{
diff --git a/source/blender/src/space.c b/source/blender/src/space.c
index b4702788e0c..8d86336e12e 100644
--- a/source/blender/src/space.c
+++ b/source/blender/src/space.c
@@ -2428,7 +2428,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
else if(G.qual==LR_ALTKEY && G.obedit->type==OB_ARMATURE)
clear_bone_parent();
else if((G.qual==0) && (G.obedit->type==OB_ARMATURE))
- select_bone_parent();
+ armature_select_hierarchy(BONE_SELECT_PARENT, 1); // 1 = add to selection
else if((G.qual==(LR_CTRLKEY|LR_ALTKEY)) && (G.obedit->type==OB_ARMATURE))
separate_armature();
else if((G.qual==0) && G.obedit->type==OB_MESH)
@@ -2458,7 +2458,7 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
start_RBSimulation();
}
else if((G.qual==0) && (OBACT) && (OBACT->type==OB_ARMATURE) && (OBACT->flag & OB_POSEMODE))
- select_bone_parent();
+ pose_select_hierarchy(BONE_SELECT_PARENT, 1); // 1 = add to selection
else if((G.qual==0)) {
start_game();
}
@@ -2761,6 +2761,19 @@ static void winqreadview3dspace(ScrArea *sa, void *spacedata, BWinEvent *evt)
scrarea_queue_winredraw(curarea);
break;
+ case LEFTBRACKETKEY:
+ if ((G.obedit) && (G.obedit->type == OB_ARMATURE))
+ armature_select_hierarchy(BONE_SELECT_PARENT, (G.qual == LR_SHIFTKEY));
+ else if ((ob) && (ob->flag & OB_POSEMODE))
+ pose_select_hierarchy(BONE_SELECT_PARENT, (G.qual == LR_SHIFTKEY));
+ break;
+ case RIGHTBRACKETKEY:
+ if ((G.obedit) && (G.obedit->type == OB_ARMATURE))
+ armature_select_hierarchy(BONE_SELECT_CHILD, (G.qual == LR_SHIFTKEY));
+ if ((ob) && (ob->flag & OB_POSEMODE))
+ pose_select_hierarchy(BONE_SELECT_CHILD, (G.qual == LR_SHIFTKEY));
+ break;
+
case PADSLASHKEY:
if(G.qual==0) {
if(G.vd->localview) {