Merging r55547 through r55594 from trunk into soc-2008-mxcurioni
[blender.git] / source / blender / editors / animation / anim_channels_edit.c
index 275cf723dcd686cdf27d49aab1ae6f3a9764f355..481430f37e487b7f9dd6d730c4617b96502517fe 100644 (file)
@@ -124,9 +124,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
                        case ANIMTYPE_DSMESH:
                        case ANIMTYPE_DSTEX:
                        case ANIMTYPE_DSLAT:
-#ifdef WITH_FREESTYLE
                        case ANIMTYPE_DSLINESTYLE:
-#endif
                        case ANIMTYPE_DSSPK:
                        {
                                /* need to verify that this data is valid for now */
@@ -172,9 +170,7 @@ void ANIM_set_active_channel(bAnimContext *ac, void *data, short datatype, int f
                        case ANIMTYPE_DSARM:
                        case ANIMTYPE_DSMESH:
                        case ANIMTYPE_DSLAT:
-#ifdef WITH_FREESTYLE
                        case ANIMTYPE_DSLINESTYLE:
-#endif
                        case ANIMTYPE_DSSPK:
                        {
                                /* need to verify that this data is valid for now */
@@ -255,9 +251,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
                                case ANIMTYPE_DSNTREE:
                                case ANIMTYPE_DSTEX:
                                case ANIMTYPE_DSLAT:
-#ifdef WITH_FREESTYLE
                                case ANIMTYPE_DSLINESTYLE:
-#endif
                                case ANIMTYPE_DSSPK:
                                {
                                        if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED))
@@ -352,9 +346,7 @@ void ANIM_deselect_anim_channels(bAnimContext *ac, void *data, short datatype, s
                        case ANIMTYPE_DSNTREE:
                        case ANIMTYPE_DSTEX:
                        case ANIMTYPE_DSLAT:
-#ifdef WITH_FREESTYLE
                        case ANIMTYPE_DSLINESTYLE:
-#endif
                        case ANIMTYPE_DSSPK:
                        {
                                /* need to verify that this data is valid for now */
@@ -1159,6 +1151,218 @@ static void ANIM_OT_channels_move(wmOperatorType *ot)
        ot->prop = RNA_def_enum(ot->srna, "direction", prop_animchannel_rearrange_types, REARRANGE_ANIMCHAN_DOWN, "Direction", "");
 }
 
+/* ******************** Group Channel Operator ************************ */
+
+static int animchannels_grouping_poll(bContext *C)
+{
+       ScrArea *sa = CTX_wm_area(C);
+       SpaceLink *sl;
+
+       /* channels region test */
+       /* TODO: could enhance with actually testing if channels region? */
+       if (ELEM(NULL, sa, CTX_wm_region(C)))
+               return 0;
+               
+       /* animation editor test - must be suitable modes only */
+       sl = CTX_wm_space_data(C);
+       
+       switch (sa->spacetype) {
+               /* supported... */
+               case SPACE_ACTION:
+               {
+                       SpaceAction *saction = (SpaceAction *)sl;
+                       
+                       /* dopesheet and action only - all others are for other datatypes or have no groups */
+                       if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_DOPESHEET) == 0)
+                               return 0;
+               }
+                       break;
+                       
+               case SPACE_IPO:
+               {
+                       SpaceIpo *sipo = (SpaceIpo *)sl;
+                       
+                       /* drivers can't have groups... */
+                       if (sipo->mode != SIPO_MODE_ANIMATION)
+                               return 0;
+               }
+                       break;
+                       
+               /* unsupported... */
+               default:
+                       return 0;
+       }
+       
+       return 1;
+}
+
+/* ----------------------------------------------------------- */
+
+static void animchannels_group_channels(bAnimContext *ac, bAnimListElem *adt_ref, const char name[])
+{      
+       AnimData *adt = adt_ref->adt;
+       bAction *act = adt->action;
+       
+       if (act) {
+               ListBase anim_data = {NULL, NULL};
+               int filter;
+               
+               /* find selected F-Curves to re-group */
+               filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL);
+               ANIM_animdata_filter(ac, &anim_data, filter, adt_ref, ANIMCONT_CHANNEL);
+               
+               if (anim_data.first) {
+                       bActionGroup *agrp;
+                       bAnimListElem *ale;
+                       
+                       /* create new group, which should now be part of the action */
+                       agrp = action_groups_add_new(act, name);
+                       BLI_assert(agrp != NULL);
+                       
+                       /* transfer selected F-Curves across to new group  */
+                       for (ale = anim_data.first; ale; ale = ale->next) {
+                               FCurve *fcu = (FCurve *)ale->data;
+                               bActionGroup *grp = fcu->grp;
+                               
+                               /* remove F-Curve from group, then group too if it is now empty */
+                               action_groups_remove_channel(act, fcu);
+                               
+                               if ((grp) && (grp->channels.first == NULL)) {
+                                       BLI_freelinkN(&act->groups, grp);
+                               }
+                               
+                               /* add F-Curve to group */
+                               action_groups_add_channel(act, agrp, fcu);
+                       }
+               }
+               
+               /* cleanup */
+               BLI_freelistN(&anim_data);
+       }
+}
+
+static int animchannels_group_exec(bContext *C, wmOperator *op)
+{
+       bAnimContext ac;
+       char name[MAX_NAME];
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+       
+       /* get name for new group */
+       RNA_string_get(op->ptr, "name", name);
+       
+       /* XXX: name for group should never be empty... */
+       if (name[0]) {
+               ListBase anim_data = {NULL, NULL};
+               bAnimListElem *ale;
+               int filter;
+               
+               /* handle each animdata block separately, so that the regrouping doesn't flow into blocks  */
+               filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_ANIMDATA | ANIMFILTER_NODUPLIS);
+               ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+               
+               for (ale = anim_data.first; ale; ale = ale->next) {
+                       animchannels_group_channels(&ac, ale, name);
+               }
+               
+               /* free temp data */
+               BLI_freelistN(&anim_data);
+               
+               /* updatss */
+               WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+       }
+       
+       return OPERATOR_FINISHED;
+}
+
+static void ANIM_OT_channels_group(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Group Channels";
+       ot->idname = "ANIM_OT_channels_group";
+       ot->description = "Add selected F-Curves to a new group";
+       
+       /* callbacks */
+       ot->invoke = WM_operator_props_popup;
+       ot->exec = animchannels_group_exec;
+       ot->poll = animchannels_grouping_poll;
+       
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+       
+       /* props */
+       ot->prop = RNA_def_string(ot->srna, "name", "New Group", 
+                                 sizeof(((bActionGroup *)NULL)->name), 
+                                 "Name", "Name of newly created group");
+       /* RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); */ /* XXX: still not too sure about this - keeping same text is confusing... */
+}
+
+/* ----------------------------------------------------------- */
+
+static int animchannels_ungroup_exec(bContext *C, wmOperator *UNUSED(op))
+{
+       bAnimContext ac;
+       
+       ListBase anim_data = {NULL, NULL};
+       bAnimListElem *ale;
+       int filter;
+       
+       /* get editor data */
+       if (ANIM_animdata_get_context(C, &ac) == 0)
+               return OPERATOR_CANCELLED;
+               
+       /* just selected F-Curves... */
+       filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_SEL | ANIMFILTER_NODUPLIS);
+       ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
+       
+       for (ale = anim_data.first; ale; ale = ale->next) {
+               /* find action for this F-Curve... */
+               if (ale->adt && ale->adt->action) {
+                       FCurve  *fcu = (FCurve *)ale->data;
+                       bAction *act = ale->adt->action;
+                       
+                       /* only proceed to remove if F-Curve is in a group... */
+                       if (fcu->grp) { 
+                               bActionGroup *agrp = fcu->grp;
+                               
+                               /* remove F-Curve from group and add at tail (ungrouped) */
+                               action_groups_remove_channel(act, fcu);
+                               BLI_addtail(&act->curves, fcu);
+                               
+                               /* delete group if it is now empty */
+                               if (agrp->channels.first == NULL) {
+                                       BLI_freelinkN(&act->groups, agrp);
+                               }
+                       }
+               }
+       }
+       
+       /* cleanup */
+       BLI_freelistN(&anim_data);
+       
+       /* updates */
+       WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL);
+       
+       return OPERATOR_FINISHED;
+}
+
+static void ANIM_OT_channels_ungroup(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Ungroup Channels";
+       ot->idname = "ANIM_OT_channels_ungroup";
+       ot->description = "Remove selected F-Curves from their current groups";
+       
+       /* callbacks */
+       ot->exec = animchannels_ungroup_exec;
+       ot->poll = animchannels_grouping_poll;
+       
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
 /* ******************** Delete Channel Operator *********************** */
 
 static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1245,13 +1449,13 @@ static int animchannels_delete_exec(bContext *C, wmOperator *UNUSED(op))
                                BLI_freelinkN(&gpd->layers, gpl);
                        }
                        break;
-
+                       
                        case ANIMTYPE_MASKLAYER:
                        {
                                /* Mask layer */
                                Mask *mask = (Mask *)ale->id;
                                MaskLayer *masklay = (MaskLayer *)ale->data;
-
+                               
                                /* try to delete the layer's data and the layer itself */
                                BKE_mask_layer_remove(mask, masklay);
                        }
@@ -1342,10 +1546,10 @@ static int animchannels_visibility_set_exec(bContext *C, wmOperator *UNUSED(op))
                /* TODO: find out why this is the case, and fix that */
                if (ale->type == ANIMTYPE_OBJECT)
                        continue;
-
+               
                /* enable the setting */
                ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, ACHANNEL_SETFLAG_ADD);
-
+               
                /* now, also flush selection status up/down as appropriate */
                ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, 1);
        }
@@ -1419,10 +1623,10 @@ static int animchannels_visibility_toggle_exec(bContext *C, wmOperator *UNUSED(o
                /* TODO: find out why this is the case, and fix that */
                if (ale->type == ANIMTYPE_OBJECT)
                        continue;
-
+               
                /* change the setting */
                ANIM_channel_setting_set(&ac, ale, ACHANNEL_SETTING_VISIBLE, vis);
-
+               
                /* now, also flush selection status up/down as appropriate */
                ANIM_flush_setting_anim_channels(&ac, &all_data, ale, ACHANNEL_SETTING_VISIBLE, (vis == ACHANNEL_SETFLAG_ADD));
        }
@@ -2060,7 +2264,7 @@ static void rename_anim_channels(bAnimContext *ac, int channel_index)
        ED_region_tag_redraw(ac->ar);
 }
 
-static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *evt)
+static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event)
 {
        bAnimContext ac;
        ARegion *ar;
@@ -2081,7 +2285,7 @@ static int animchannels_rename_invoke(bContext *C, wmOperator *UNUSED(op), wmEve
         *              so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
         *              ACHANNEL_HEIGHT_HALF.
         */
-       UI_view2d_region_to_view(v2d, evt->mval[0], evt->mval[1], &x, &y);
+       UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
        
        if (ac.datatype == ANIMCONT_NLA) {
                SpaceNla *snla = (SpaceNla *)ac.sl;
@@ -2219,9 +2423,7 @@ static int mouse_anim_channels(bAnimContext *ac, float UNUSED(x), int channel_in
                case ANIMTYPE_DSNTREE:
                case ANIMTYPE_DSTEX:
                case ANIMTYPE_DSLAT:
-#ifdef WITH_FREESTYLE
                case ANIMTYPE_DSLINESTYLE:
-#endif
                case ANIMTYPE_DSSPK:
                {
                        /* sanity checking... */
@@ -2243,7 +2445,7 @@ static int mouse_anim_channels(bAnimContext *ac, float UNUSED(x), int channel_in
                        }
                        
                        notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
-       }
+               }
                break;
                
                case ANIMTYPE_GROUP: 
@@ -2397,7 +2599,7 @@ static int mouse_anim_channels(bAnimContext *ac, float UNUSED(x), int channel_in
 /* ------------------- */
 
 /* handle clicking */
-static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
 {
        bAnimContext ac;
        ARegion *ar;
@@ -2455,7 +2657,7 @@ static void ANIM_OT_channels_click(wmOperatorType *ot)
        ot->poll = animedit_poll_channels_active;
        
        /* flags */
-       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+       ot->flag = OPTYPE_UNDO;
        
        /* properties */
        /* NOTE: don't save settings, otherwise, can end up with some weird behaviour (sticky extend) */
@@ -2495,6 +2697,9 @@ void ED_operatortypes_animchannels(void)
        WM_operatortype_append(ANIM_OT_channels_visibility_set);
        
        WM_operatortype_append(ANIM_OT_channels_fcurves_enable);
+       
+       WM_operatortype_append(ANIM_OT_channels_group);
+       WM_operatortype_append(ANIM_OT_channels_ungroup);
 }
 
 // TODO: check on a poll callback for this, to get hotkeys into menus
@@ -2548,6 +2753,10 @@ void ED_keymap_animchannels(wmKeyConfig *keyconf)
        RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEUPKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "direction", REARRANGE_ANIMCHAN_TOP);
        RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_move", PAGEDOWNKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "direction", REARRANGE_ANIMCHAN_BOTTOM);
        
+       /* grouping */
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_group", GKEY, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "ANIM_OT_channels_ungroup", GKEY, KM_PRESS, KM_ALT, 0);
+       
        /* Graph Editor only */
        WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_set", VKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "ANIM_OT_channels_visibility_toggle", VKEY, KM_PRESS, KM_SHIFT, 0);