2.5:
[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 /* Channel Drawing */
95 // XXX should these get their own file or go in anim_draw instead???
96
97
98 /* ************************************************************************** */
99 /* Operators */
100
101
102 /* ******************** Mouse-Click Operator *********************** */
103 /* Depending on the channel that was clicked on, the mouse click will activate whichever
104  * part of the channel is relevant.
105  *
106  * NOTE: eventually, this should probably be phased out when many of these things are replaced with buttons
107  */
108
109 static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, short selectmode)
110 {
111         ListBase anim_data = {NULL, NULL};
112         bAnimListElem *ale;
113         int filter;
114         
115         /* get the channel that was clicked on */
116                 /* filter channels */
117         filter= (ANIMFILTER_FORDRAWING | ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
118         filter= ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
119         
120                 /* get channel from index */
121         ale= BLI_findlink(&anim_data, channel_index);
122         if (ale == NULL) {
123                 /* channel not found */
124                 printf("Error: animation channel not found in mouse_anim_channels() \n");
125                 printf("\t channel index = %d, channels = %d\n", channel_index, filter);
126                 
127                 BLI_freelistN(&anim_data);
128                 return;
129         }
130         
131         /* action to take depends on what channel we've got */
132         switch (ale->type) {
133                 case ANIMTYPE_OBJECT:
134                         {
135                                 bDopeSheet *ads= (bDopeSheet *)ac->data;
136                                 Scene *sce= (Scene *)ads->source;
137                                 Base *base= (Base *)ale->data;
138                                 Object *ob= base->object;
139                                 
140                                 if (x < 16) {
141                                         /* toggle expand */
142                                         ob->nlaflag ^= OB_ADS_COLLAPSED;
143                                 }
144                                 else {
145                                         /* set selection status */
146                                         // FIXME: this needs to use the new stuff...
147                                         if (selectmode) {
148                                                 /* swap select */
149                                                 base->flag ^= SELECT;
150                                                 ob->flag= base->flag;
151                                         }
152                                         else {
153                                                 Base *b;
154                                                 
155                                                 /* deleselect all */
156                                                 for (b= sce->base.first; b; b= b->next) {
157                                                         b->flag &= ~SELECT;
158                                                         b->object->flag= b->flag;
159                                                 }
160                                                 
161                                                 /* select object now */
162                                                 base->flag |= SELECT;
163                                                 ob->flag |= SELECT;
164                                         }
165                                         
166                                         //set_active_base(base);        /* editview.c */
167                                 }
168                         }
169                                 break;
170                 case ANIMTYPE_FILLIPOD:
171                         {
172                                 Object *ob= (Object *)ale->data;
173                                 ob->nlaflag ^= OB_ADS_SHOWIPO;
174                         }
175                                 break;
176                 case ANIMTYPE_FILLACTD:
177                         {
178                                 bAction *act= (bAction *)ale->data;
179                                 act->flag ^= ACTC_EXPANDED;
180                         }
181                                 break;
182                 case ANIMTYPE_FILLCOND:
183                         {
184                                 Object *ob= (Object *)ale->data;
185                                 ob->nlaflag ^= OB_ADS_SHOWCONS;
186                         }
187                                 break;
188                 case ANIMTYPE_FILLMATD:
189                         {
190                                 Object *ob= (Object *)ale->data;
191                                 ob->nlaflag ^= OB_ADS_SHOWMATS;
192                         }
193                                 break;
194                                 
195                 case ANIMTYPE_DSMAT:
196                         {
197                                 Material *ma= (Material *)ale->data;
198                                 ma->flag ^= MA_DS_EXPAND;
199                         }
200                                 break;
201                 case ANIMTYPE_DSLAM:
202                         {
203                                 Lamp *la= (Lamp *)ale->data;
204                                 la->flag ^= LA_DS_EXPAND;
205                         }
206                                 break;
207                 case ANIMTYPE_DSCAM:
208                         {
209                                 Camera *ca= (Camera *)ale->data;
210                                 ca->flag ^= CAM_DS_EXPAND;
211                         }
212                                 break;
213                 case ANIMTYPE_DSCUR:
214                         {
215                                 Curve *cu= (Curve *)ale->data;
216                                 cu->flag ^= CU_DS_EXPAND;
217                         }
218                                 break;
219                 case ANIMTYPE_DSSKEY:
220                         {
221                                 Key *key= (Key *)ale->data;
222                                 key->flag ^= KEYBLOCK_DS_EXPAND;
223                         }
224                                 break;
225                         
226                 case ANIMTYPE_GROUP: 
227                         {
228                                 bActionGroup *agrp= (bActionGroup *)ale->data;
229                                 short offset= (ac->datatype == ANIMCONT_DOPESHEET)? 21 : 0;
230                                 
231                                 if ((x < (offset+17)) && (agrp->channels.first)) {
232                                         /* toggle expand */
233                                         agrp->flag ^= AGRP_EXPANDED;
234                                 }
235                                 else if (x >= (ACHANNEL_NAMEWIDTH-16)) {
236                                         /* toggle protection/locking */
237                                         agrp->flag ^= AGRP_PROTECTED;
238                                 }
239                                 else {
240                                         /* select/deselect group */
241                                         if (selectmode == SELECT_INVERT) {
242                                                 /* inverse selection status of group */
243                                                 //select_action_group(act, agrp, SELECT_INVERT);
244                                         }
245                                         else if (/*G.qual == (LR_CTRLKEY|LR_SHIFTKEY)*/0) {
246                                                 // FIXME: need a special case for this!
247                                                 /* select all in group (and deselect everthing else) */ 
248                                                 //select_action_group_channels(act, agrp);
249                                                 //select_action_group(act, agrp, SELECT_ADD);
250                                         }
251                                         else {
252                                                 /* select group by itself */
253                                                 //deselect_actionchannels(act, ANIMCONT_ACTION, 0);
254                                                 //select_action_group(act, agrp, SELECT_ADD);
255                                         }
256                                 }
257                         }
258                         break;
259                 case ANIMTYPE_ACHAN:
260                         {
261                                 bActionChannel *achan= (bActionChannel *)ale->data;
262                                 short offset= (ac->datatype == ANIMCONT_DOPESHEET)? 21 : 0;
263                                 
264                                 if (x >= (ACHANNEL_NAMEWIDTH-16)) {
265                                         /* toggle protect */
266                                         achan->flag ^= ACHAN_PROTECTED;
267                                 }
268                                 else if ((x >= (ACHANNEL_NAMEWIDTH-32)) && (achan->ipo)) {
269                                         /* toggle mute */
270                                         achan->ipo->muteipo = (achan->ipo->muteipo)? 0: 1;
271                                 }
272                                 else if (x <= (offset+17)) {
273                                         /* toggle expand */
274                                         achan->flag ^= ACHAN_EXPANDED;
275                                 }                               
276                                 else {
277                                         /* select/deselect achan */             
278                                         if (selectmode == SELECT_INVERT) {
279                                                 //select_channel(act, achan, SELECT_INVERT);
280                                         }
281                                         else {
282                                                 //deselect_actionchannels(act, ACTCONT_ACTION, 0);
283                                                 //select_channel(act, achan, SELECT_ADD);
284                                         }
285                                         
286                                         /* messy... set active bone */
287                                         //select_poseelement_by_name(achan->name, 2);
288                                         
289                                         // XXX for now only
290                                         achan->flag ^= ACHAN_SELECTED;
291                                 }
292                         }
293                                 break;
294                 case ANIMTYPE_FILLIPO:
295                         {
296                                 bActionChannel *achan= (bActionChannel *)ale->data;
297                                 
298                                 achan->flag ^= ACHAN_SHOWIPO;
299                                 
300                                 if ((x > 24) && (achan->flag & ACHAN_SHOWIPO)) {
301                                         /* select+make active achan */          
302                                         //deselect_actionchannels(act, ACTCONT_ACTION, 0);
303                                         //select_channel(act, achan, SELECT_ADD);
304                                         
305                                         /* messy... set active bone */
306                                         //select_poseelement_by_name(achan->name, 2);
307                                         
308                                         // XXX for now only
309                                         achan->flag ^= ACHAN_SELECTED;
310                                 }       
311                         }
312                         break;
313                 case ANIMTYPE_FILLCON:
314                         {
315                                 bActionChannel *achan= (bActionChannel *)ale->data;
316                                 
317                                 achan->flag ^= ACHAN_SHOWCONS;
318                                 
319                                 if ((x > 24) && (achan->flag & ACHAN_SHOWCONS)) {
320                                         /* select+make active achan */  
321                                         //deselect_actionchannels(act, ACTCONT_ACTION, 0);
322                                         //select_channel(act, achan, SELECT_ADD);
323                                         
324                                         /* messy... set active bone */
325                                         //select_poseelement_by_name(achan->name, 2);
326                                         
327                                         // XXX for now only
328                                         achan->flag ^= ACHAN_SELECTED;
329                                 }       
330                         }
331                         break;
332                 case ANIMTYPE_ICU: 
333                         {
334                                 IpoCurve *icu= (IpoCurve *)ale->data;
335                                 
336                                 if (x >= (ACHANNEL_NAMEWIDTH-16)) {
337                                         /* toggle protection */
338                                         icu->flag ^= IPO_PROTECT;
339                                 }
340                                 else if (x >= (ACHANNEL_NAMEWIDTH-16)) {
341                                         /* toggle mute */
342                                         icu->flag ^= IPO_MUTE;
343                                 }
344                                 else {
345                                         /* select/deselect */
346                                         //select_icu_channel(act, icu, SELECT_INVERT);
347                                         
348                                         // XXX for now only
349                                         icu->flag ^= IPO_SELECT;
350                                 }
351                         }
352                         break;
353                 case ANIMTYPE_CONCHAN:
354                         {
355                                 bConstraintChannel *conchan= (bConstraintChannel *)ale->data;
356                                 
357                                 if (x >= (ACHANNEL_NAMEWIDTH-16)) {
358                                         /* toggle protection */
359                                         conchan->flag ^= CONSTRAINT_CHANNEL_PROTECTED;
360                                 }
361                                 else if ((x >= (ACHANNEL_NAMEWIDTH-32)) && (conchan->ipo)) {
362                                         /* toggle mute */
363                                         conchan->ipo->muteipo = (conchan->ipo->muteipo)? 0: 1;
364                                 }
365                                 else {
366                                         /* select/deselect */
367                                         //select_constraint_channel(act, conchan, SELECT_INVERT);
368                                         
369                                         // XXX for now only
370                                         conchan->flag ^= CONSTRAINT_CHANNEL_SELECT;
371                                 }
372                         }
373                                 break;
374                 case ANIMTYPE_GPDATABLOCK:
375                         {
376                                 bGPdata *gpd= (bGPdata *)ale->data;
377                                 
378                                 /* toggle expand */
379                                 gpd->flag ^= GP_DATA_EXPAND;
380                         }
381                                 break;
382                 case ANIMTYPE_GPLAYER:
383                         {
384 #if 0 // XXX future of this is unclear
385                                 bGPdata *gpd= (bGPdata *)ale->owner;
386                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
387                                 
388                                 if (x >= (ACHANNEL_NAMEWIDTH-16)) {
389                                         /* toggle lock */
390                                         gpl->flag ^= GP_LAYER_LOCKED;
391                                 }
392                                 else if (x >= (ACHANNEL_NAMEWIDTH-32)) {
393                                         /* toggle hide */
394                                         gpl->flag ^= GP_LAYER_HIDE;
395                                 }
396                                 else {
397                                         /* select/deselect */
398                                         //if (G.qual & LR_SHIFTKEY) {
399                                                 //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
400                                         //}
401                                         //else {
402                                                 //deselect_gpencil_layers(data, 0);
403                                                 //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
404                                         //}
405                                 }
406 #endif // XXX future of this is unclear
407                         }
408                                 break;
409                 case ANIMTYPE_SHAPEKEY:
410                         /* TODO: shapekey channels cannot be selected atm... */
411                         break;
412                 default:
413                         printf("Error: Invalid channel type in mouse_anim_channels() \n");
414         }
415         
416         /* free channels */
417         BLI_freelistN(&anim_data);
418 }
419
420 /* ------------------- */
421
422 /* handle clicking */
423 static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
424 {
425         bAnimContext ac;
426         Scene *scene;
427         ARegion *ar;
428         View2D *v2d;
429         int mval[2], channel_index;
430         short selectmode;
431         float x, y;
432         
433         
434         /* get editor data */
435         if (ANIM_animdata_get_context(C, &ac) == 0)
436                 return OPERATOR_CANCELLED;
437                 
438         /* get useful pointers from animation context data */
439         scene= ac.scene;
440         ar= ac.ar;
441         v2d= &ar->v2d;
442         
443         /* get mouse coordinates (in region coordinates) */
444         mval[0]= (event->x - ar->winrct.xmin);
445         mval[1]= (event->y - ar->winrct.ymin);
446         
447         /* select mode is either replace (deselect all, then add) or add/extend */
448         if (RNA_boolean_get(op->ptr, "extend_select"))
449                 selectmode= SELECT_INVERT;
450         else
451                 selectmode= SELECT_REPLACE;
452         
453         /* figure out which channel user clicked in 
454          * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height
455          *              so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
456          *              ACHANNEL_HEIGHT_HALF.
457          */
458         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
459         UI_view2d_listview_get_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
460         
461         /* handle mouse-click in the relevant channel then */
462         mouse_anim_channels(&ac, x, channel_index, selectmode);
463         
464         /* set notifier tha things have changed */
465         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
466         
467         return OPERATOR_FINISHED;
468 }
469  
470 void ANIM_OT_channels_mouseclick (wmOperatorType *ot)
471 {
472         /* identifiers */
473         ot->name= "Mouse Click on Channels";
474         ot->idname= "ANIM_OT_channels_mouseclick";
475         
476         /* api callbacks */
477         ot->invoke= animchannels_mouseclick_invoke;
478         ot->poll= ED_operator_areaactive;
479         
480         /* id-props */
481         RNA_def_property(ot->srna, "extend_select", PROP_BOOLEAN, PROP_NONE); // SHIFTKEY
482 }
483
484 /* ************************************************************************** */
485 /* Operator Registration */
486
487 void ED_operatortypes_animchannels(void)
488 {
489         WM_operatortype_append(ANIM_OT_channels_mouseclick);
490 }
491
492 void ED_keymap_animchannels(wmWindowManager *wm)
493 {
494         ListBase *keymap = WM_keymap_listbase(wm, "Animation_Channels", 0, 0);
495         
496         /* click-select */
497                 // XXX for now, only leftmouse.... 
498         WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, 0, 0);
499         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend_select", 1);
500 }
501
502 /* ************************************************************************** */