2.5 - Action Editor
[blender.git] / source / blender / editors / animation / anim_channels.c
1 /**
2  * $Id: editaction.c 17746 2008-12-08 11:19:44Z aligorith $
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Joshua Leung
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include <math.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include <float.h>
34
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_arithb.h"
43
44 #include "DNA_listBase.h"
45 #include "DNA_action_types.h"
46 #include "DNA_armature_types.h"
47 #include "DNA_camera_types.h"
48 #include "DNA_curve_types.h"
49 #include "DNA_ipo_types.h"
50 #include "DNA_object_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_scene_types.h"
53 #include "DNA_space_types.h"
54 #include "DNA_constraint_types.h"
55 #include "DNA_key_types.h"
56 #include "DNA_lamp_types.h"
57 #include "DNA_material_types.h"
58 #include "DNA_userdef_types.h"
59 #include "DNA_gpencil_types.h"
60 #include "DNA_windowmanager_types.h"
61
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64
65 #include "BKE_action.h"
66 #include "BKE_depsgraph.h"
67 #include "BKE_ipo.h"
68 #include "BKE_key.h"
69 #include "BKE_material.h"
70 #include "BKE_object.h"
71 #include "BKE_context.h"
72 #include "BKE_utildefines.h"
73
74 #include "UI_interface.h"
75 #include "UI_resources.h"
76 #include "UI_view2d.h"
77
78 #include "ED_anim_api.h"
79 #include "ED_keyframes_edit.h" // XXX move the select modes out of there!
80 #include "ED_screen.h"
81 #include "ED_space_api.h"
82
83 #include "WM_api.h"
84 #include "WM_types.h"
85
86 /* ************************************************************************** */
87 /* Channels API */
88
89 /* -------------------------- Internal Tools -------------------------------- */
90
91 /* -------------------------- Exposed API ----------------------------------- */
92
93 /* ************************************************************************** */
94 /* Operators */
95
96
97 /* ******************** Mouse-Click Operator *********************** */
98 /* Depending on the channel that was clicked on, the mouse click will activate whichever
99  * part of the channel is relevant.
100  *
101  * NOTE: eventually, this should probably be phased out when many of these things are replaced with buttons
102  */
103
104 static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, short selectmode)
105 {
106         ListBase anim_data = {NULL, NULL};
107         bAnimListElem *ale;
108         int filter;
109         
110         /* get the channel that was clicked on */
111                 /* filter channels */
112         filter= (ANIMFILTER_FORDRAWING | ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
113         filter= ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
114         
115                 /* get channel from index */
116         ale= BLI_findlink(&anim_data, channel_index);
117         if (ale == NULL) {
118                 /* channel not found */
119                 printf("Error: animation channel not found in mouse_anim_channels() \n");
120                 printf("\t channel index = %d, channels = %d\n", channel_index, filter);
121                 
122                 BLI_freelistN(&anim_data);
123                 return;
124         }
125         
126         /* action to take depends on what channel we've got */
127         switch (ale->type) {
128                 case ANIMTYPE_OBJECT:
129                         {
130                                 bDopeSheet *ads= (bDopeSheet *)ac->data;
131                                 Scene *sce= (Scene *)ads->source;
132                                 Base *base= (Base *)ale->data;
133                                 Object *ob= base->object;
134                                 
135                                 if (x < 16) {
136                                         /* toggle expand */
137                                         ob->nlaflag ^= OB_ADS_COLLAPSED;
138                                 }
139                                 else {
140                                         /* set selection status */
141                                         // FIXME: this needs to use the new stuff...
142                                         if (selectmode) {
143                                                 /* swap select */
144                                                 base->flag ^= SELECT;
145                                                 ob->flag= base->flag;
146                                         }
147                                         else {
148                                                 Base *b;
149                                                 
150                                                 /* deleselect all */
151                                                 for (b= sce->base.first; b; b= b->next) {
152                                                         b->flag &= ~SELECT;
153                                                         b->object->flag= b->flag;
154                                                 }
155                                                 
156                                                 /* select object now */
157                                                 base->flag |= SELECT;
158                                                 ob->flag |= SELECT;
159                                         }
160                                         
161                                         //set_active_base(base);        /* editview.c */
162                                 }
163                         }
164                                 break;
165                 case ANIMTYPE_FILLIPOD:
166                         {
167                                 Object *ob= (Object *)ale->data;
168                                 ob->nlaflag ^= OB_ADS_SHOWIPO;
169                         }
170                                 break;
171                 case ANIMTYPE_FILLACTD:
172                         {
173                                 bAction *act= (bAction *)ale->data;
174                                 act->flag ^= ACTC_EXPANDED;
175                         }
176                                 break;
177                 case ANIMTYPE_FILLCOND:
178                         {
179                                 Object *ob= (Object *)ale->data;
180                                 ob->nlaflag ^= OB_ADS_SHOWCONS;
181                         }
182                                 break;
183                 case ANIMTYPE_FILLMATD:
184                         {
185                                 Object *ob= (Object *)ale->data;
186                                 ob->nlaflag ^= OB_ADS_SHOWMATS;
187                         }
188                                 break;
189                                 
190                 case ANIMTYPE_DSMAT:
191                         {
192                                 Material *ma= (Material *)ale->data;
193                                 ma->flag ^= MA_DS_EXPAND;
194                         }
195                                 break;
196                 case ANIMTYPE_DSLAM:
197                         {
198                                 Lamp *la= (Lamp *)ale->data;
199                                 la->flag ^= LA_DS_EXPAND;
200                         }
201                                 break;
202                 case ANIMTYPE_DSCAM:
203                         {
204                                 Camera *ca= (Camera *)ale->data;
205                                 ca->flag ^= CAM_DS_EXPAND;
206                         }
207                                 break;
208                 case ANIMTYPE_DSCUR:
209                         {
210                                 Curve *cu= (Curve *)ale->data;
211                                 cu->flag ^= CU_DS_EXPAND;
212                         }
213                                 break;
214                 case ANIMTYPE_DSSKEY:
215                         {
216                                 Key *key= (Key *)ale->data;
217                                 key->flag ^= KEYBLOCK_DS_EXPAND;
218                         }
219                                 break;
220                         
221                 case ANIMTYPE_GROUP: 
222                         {
223                                 bActionGroup *agrp= (bActionGroup *)ale->data;
224                                 short offset= (ac->datatype == ANIMCONT_DOPESHEET)? 21 : 0;
225                                 
226                                 if ((x < (offset+17)) && (agrp->channels.first)) {
227                                         /* toggle expand */
228                                         agrp->flag ^= AGRP_EXPANDED;
229                                 }
230                                 else if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
231                                         /* toggle protection/locking */
232                                         agrp->flag ^= AGRP_PROTECTED;
233                                 }
234                                 else {
235                                         /* select/deselect group */
236                                         if (selectmode == SELECT_INVERT) {
237                                                 /* inverse selection status of group */
238                                                 //select_action_group(act, agrp, SELECT_INVERT);
239                                         }
240                                         else if (/*G.qual == (LR_CTRLKEY|LR_SHIFTKEY)*/0) {
241                                                 // FIXME: need a special case for this!
242                                                 /* select all in group (and deselect everthing else) */ 
243                                                 //select_action_group_channels(act, agrp);
244                                                 //select_action_group(act, agrp, SELECT_ADD);
245                                         }
246                                         else {
247                                                 /* select group by itself */
248                                                 //deselect_actionchannels(act, ANIMCONT_ACTION, 0);
249                                                 //select_action_group(act, agrp, SELECT_ADD);
250                                         }
251                                         
252                                         // XXX
253                                         agrp->flag ^= AGRP_SELECTED;
254                                 }
255                         }
256                         break;
257                 case ANIMTYPE_ACHAN:
258                         {
259                                 bActionChannel *achan= (bActionChannel *)ale->data;
260                                 short offset= (ac->datatype == ANIMCONT_DOPESHEET)? 21 : 0;
261                                 
262                                 if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
263                                         /* toggle protect */
264                                         achan->flag ^= ACHAN_PROTECTED;
265                                 }
266                                 else if ((x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) && (achan->ipo)) {
267                                         /* toggle mute */
268                                         achan->ipo->muteipo = (achan->ipo->muteipo)? 0: 1;
269                                 }
270                                 else if (x <= (offset+17)) {
271                                         /* toggle expand */
272                                         achan->flag ^= ACHAN_EXPANDED;
273                                 }                               
274                                 else {
275                                         /* select/deselect achan */             
276                                         if (selectmode == SELECT_INVERT) {
277                                                 //select_channel(act, achan, SELECT_INVERT);
278                                         }
279                                         else {
280                                                 //deselect_actionchannels(act, ACTCONT_ACTION, 0);
281                                                 //select_channel(act, achan, SELECT_ADD);
282                                         }
283                                         
284                                         /* messy... set active bone */
285                                         //select_poseelement_by_name(achan->name, 2);
286                                         
287                                         // XXX for now only
288                                         achan->flag ^= ACHAN_SELECTED;
289                                 }
290                         }
291                                 break;
292                 case ANIMTYPE_FILLIPO:
293                         {
294                                 bActionChannel *achan= (bActionChannel *)ale->data;
295                                 
296                                 achan->flag ^= ACHAN_SHOWIPO;
297                                 
298                                 if ((x > 24) && (achan->flag & ACHAN_SHOWIPO)) {
299                                         /* select+make active achan */          
300                                         //deselect_actionchannels(act, ACTCONT_ACTION, 0);
301                                         //select_channel(act, achan, SELECT_ADD);
302                                         
303                                         /* messy... set active bone */
304                                         //select_poseelement_by_name(achan->name, 2);
305                                         
306                                         // XXX for now only
307                                         achan->flag ^= ACHAN_SELECTED;
308                                 }       
309                         }
310                         break;
311                 case ANIMTYPE_FILLCON:
312                         {
313                                 bActionChannel *achan= (bActionChannel *)ale->data;
314                                 
315                                 achan->flag ^= ACHAN_SHOWCONS;
316                                 
317                                 if ((x > 24) && (achan->flag & ACHAN_SHOWCONS)) {
318                                         /* select+make active achan */  
319                                         //deselect_actionchannels(act, ACTCONT_ACTION, 0);
320                                         //select_channel(act, achan, SELECT_ADD);
321                                         
322                                         /* messy... set active bone */
323                                         //select_poseelement_by_name(achan->name, 2);
324                                         
325                                         // XXX for now only
326                                         achan->flag ^= ACHAN_SELECTED;
327                                 }       
328                         }
329                         break;
330                 case ANIMTYPE_ICU: 
331                         {
332                                 IpoCurve *icu= (IpoCurve *)ale->data;
333                                 
334                                 if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
335                                         /* toggle protection */
336                                         icu->flag ^= IPO_PROTECT;
337                                 }
338                                 else if (x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) {
339                                         /* toggle mute */
340                                         icu->flag ^= IPO_MUTE;
341                                 }
342                                 else {
343                                         /* select/deselect */
344                                         //select_icu_channel(act, icu, SELECT_INVERT);
345                                         
346                                         // XXX for now only
347                                         icu->flag ^= IPO_SELECT;
348                                 }
349                         }
350                         break;
351                 case ANIMTYPE_CONCHAN:
352                         {
353                                 bConstraintChannel *conchan= (bConstraintChannel *)ale->data;
354                                 
355                                 if (x >= (ACHANNEL_NAMEWIDTH-16)) {
356                                         /* toggle protection */
357                                         conchan->flag ^= CONSTRAINT_CHANNEL_PROTECTED;
358                                 }
359                                 else if ((x >= (ACHANNEL_NAMEWIDTH-32)) && (conchan->ipo)) {
360                                         /* toggle mute */
361                                         conchan->ipo->muteipo = (conchan->ipo->muteipo)? 0: 1;
362                                 }
363                                 else {
364                                         /* select/deselect */
365                                         //select_constraint_channel(act, conchan, SELECT_INVERT);
366                                         
367                                         // XXX for now only
368                                         conchan->flag ^= CONSTRAINT_CHANNEL_SELECT;
369                                 }
370                         }
371                                 break;
372                 case ANIMTYPE_GPDATABLOCK:
373                         {
374                                 bGPdata *gpd= (bGPdata *)ale->data;
375                                 
376                                 /* toggle expand */
377                                 gpd->flag ^= GP_DATA_EXPAND;
378                         }
379                                 break;
380                 case ANIMTYPE_GPLAYER:
381                         {
382 #if 0 // XXX future of this is unclear
383                                 bGPdata *gpd= (bGPdata *)ale->owner;
384                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
385                                 
386                                 if (x >= (ACHANNEL_NAMEWIDTH-16)) {
387                                         /* toggle lock */
388                                         gpl->flag ^= GP_LAYER_LOCKED;
389                                 }
390                                 else if (x >= (ACHANNEL_NAMEWIDTH-32)) {
391                                         /* toggle hide */
392                                         gpl->flag ^= GP_LAYER_HIDE;
393                                 }
394                                 else {
395                                         /* select/deselect */
396                                         //if (G.qual & LR_SHIFTKEY) {
397                                                 //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
398                                         //}
399                                         //else {
400                                                 //deselect_gpencil_layers(data, 0);
401                                                 //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
402                                         //}
403                                 }
404 #endif // XXX future of this is unclear
405                         }
406                                 break;
407                 case ANIMTYPE_SHAPEKEY:
408                         /* TODO: shapekey channels cannot be selected atm... */
409                         break;
410                 default:
411                         printf("Error: Invalid channel type in mouse_anim_channels() \n");
412         }
413         
414         /* free channels */
415         BLI_freelistN(&anim_data);
416 }
417
418 /* ------------------- */
419
420 /* handle clicking */
421 static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
422 {
423         bAnimContext ac;
424         Scene *scene;
425         ARegion *ar;
426         View2D *v2d;
427         int mval[2], channel_index;
428         short selectmode;
429         float x, y;
430         
431         
432         /* get editor data */
433         if (ANIM_animdata_get_context(C, &ac) == 0)
434                 return OPERATOR_CANCELLED;
435                 
436         /* get useful pointers from animation context data */
437         scene= ac.scene;
438         ar= ac.ar;
439         v2d= &ar->v2d;
440         
441         /* get mouse coordinates (in region coordinates) */
442         mval[0]= (event->x - ar->winrct.xmin);
443         mval[1]= (event->y - ar->winrct.ymin);
444         
445         /* select mode is either replace (deselect all, then add) or add/extend */
446         if (RNA_boolean_get(op->ptr, "extend_select"))
447                 selectmode= SELECT_INVERT;
448         else
449                 selectmode= SELECT_REPLACE;
450         
451         /* figure out which channel user clicked in 
452          * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height
453          *              so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
454          *              ACHANNEL_HEIGHT_HALF.
455          */
456         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
457         UI_view2d_listview_get_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
458         
459         /* handle mouse-click in the relevant channel then */
460         mouse_anim_channels(&ac, x, channel_index, selectmode);
461         
462         /* set notifier tha things have changed */
463         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
464         
465         return OPERATOR_FINISHED;
466 }
467  
468 void ANIM_OT_channels_mouseclick (wmOperatorType *ot)
469 {
470         /* identifiers */
471         ot->name= "Mouse Click on Channels";
472         ot->idname= "ANIM_OT_channels_mouseclick";
473         
474         /* api callbacks */
475         ot->invoke= animchannels_mouseclick_invoke;
476         ot->poll= ED_operator_areaactive;
477         
478         /* id-props */
479         RNA_def_property(ot->srna, "extend_select", PROP_BOOLEAN, PROP_NONE); // SHIFTKEY
480 }
481
482 /* ************************************************************************** */
483 /* Operator Registration */
484
485 void ED_operatortypes_animchannels(void)
486 {
487         WM_operatortype_append(ANIM_OT_channels_mouseclick);
488 }
489
490 void ED_keymap_animchannels(wmWindowManager *wm)
491 {
492         ListBase *keymap = WM_keymap_listbase(wm, "Animation_Channels", 0, 0);
493         
494         /* click-select */
495                 // XXX for now, only leftmouse.... 
496         WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, 0, 0);
497         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend_select", 1);
498 }
499
500 /* ************************************************************************** */