2.5 Animation Channels - Borderselect Tool
[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 Macros ------------------------------- */
90
91 /* set/clear/toggle macro 
92  *      - channel - channel with a 'flag' member that we're setting
93  *      - smode - 0=clear, 1=set, 2=toggle
94  *      - sflag - bitflag to set
95  */
96 #define ACHANNEL_SET_FLAG(channel, smode, sflag) \
97         { \
98                 if (smode == ACHANNEL_SETFLAG_TOGGLE)   (channel)->flag ^= (sflag); \
99                 else if (smode == ACHANNEL_SETFLAG_ADD) (channel)->flag |= (sflag); \
100                 else                                                                    (channel)->flag &= ~(sflag); \
101         }
102
103 /* -------------------------- Internal Tools -------------------------------- */
104
105 /* -------------------------- Exposed API ----------------------------------- */
106
107 /* Deselect all animation channels 
108  *      - data: pointer to datatype, as contained in bAnimContext
109  *      - datatype: the type of data that 'data' represents (eAnim_ChannelType)
110  *      - test: check if deselecting instead of selecting
111  *      - sel: eAnimChannels_SetFlag;
112  */
113 void ANIM_deselect_anim_channels (void *data, short datatype, short test, short sel)
114 {
115         ListBase anim_data = {NULL, NULL};
116         bAnimListElem *ale;
117         int filter;
118         
119         /* filter data */
120         filter= ANIMFILTER_VISIBLE;
121         ANIM_animdata_filter(&anim_data, filter, data, datatype);
122         
123         /* See if we should be selecting or deselecting */
124         if (test) {
125                 for (ale= anim_data.first; ale; ale= ale->next) {
126                         if (sel == 0) 
127                                 break;
128                         
129                         switch (ale->type) {
130                                 case ANIMTYPE_OBJECT:
131                                         if (ale->flag & SELECT)
132                                                 sel= ACHANNEL_SETFLAG_CLEAR;
133                                         break;
134                                 case ANIMTYPE_FILLACTD:
135                                         if (ale->flag & ACTC_SELECTED)
136                                                 sel= ACHANNEL_SETFLAG_CLEAR;
137                                         break;
138                                 case ANIMTYPE_GROUP:
139                                         if (ale->flag & AGRP_SELECTED)
140                                                 sel= ACHANNEL_SETFLAG_CLEAR;
141                                         break;
142                                 case ANIMTYPE_ACHAN:
143                                         if (ale->flag & ACHAN_SELECTED) 
144                                                 sel= ACHANNEL_SETFLAG_CLEAR;
145                                         break;
146                                 case ANIMTYPE_CONCHAN:
147                                         if (ale->flag & CONSTRAINT_CHANNEL_SELECT) 
148                                                 sel= ACHANNEL_SETFLAG_CLEAR;
149                                         break;
150                                 case ANIMTYPE_ICU:
151                                         if (ale->flag & IPO_SELECT)
152                                                 sel= ACHANNEL_SETFLAG_CLEAR;
153                                         break;
154                         }
155                 }
156         }
157                 
158         /* Now set the flags */
159         for (ale= anim_data.first; ale; ale= ale->next) {
160                 switch (ale->type) {
161                         case ANIMTYPE_OBJECT:
162                         {
163                                 Base *base= (Base *)ale->data;
164                                 Object *ob= base->object;
165                                 
166                                 ACHANNEL_SET_FLAG(base, sel, SELECT);
167                                 ACHANNEL_SET_FLAG(ob, sel, SELECT);
168                         }
169                                 break;
170                         case ANIMTYPE_FILLACTD:
171                         {
172                                 bAction *act= (bAction *)ale->data;
173                                 
174                                 ACHANNEL_SET_FLAG(act, sel, ACTC_SELECTED);
175                         }
176                                 break;
177                         case ANIMTYPE_GROUP:
178                         {
179                                 bActionGroup *agrp= (bActionGroup *)ale->data;
180                                 
181                                 ACHANNEL_SET_FLAG(agrp, sel, AGRP_SELECTED);
182                                 agrp->flag &= ~AGRP_ACTIVE;
183                         }
184                                 break;
185                         case ANIMTYPE_ACHAN:
186                         {
187                                 bActionChannel *achan= (bActionChannel *)ale->data;
188                                 
189                                 ACHANNEL_SET_FLAG(achan, sel, ACHAN_SELECTED);
190                                 
191                                 //select_poseelement_by_name(achan->name, sel); // XXX
192                                 achan->flag &= ~ACHAN_HILIGHTED;
193                         }
194                                 break;
195                         case ANIMTYPE_CONCHAN:
196                         {
197                                 bConstraintChannel *conchan= (bConstraintChannel *)ale->data;
198                                 
199                                 ACHANNEL_SET_FLAG(conchan, sel, CONSTRAINT_CHANNEL_SELECT);
200                         }
201                                 break;
202                         case ANIMTYPE_ICU:
203                         {
204                                 IpoCurve *icu= (IpoCurve *)ale->data;
205                                 
206                                 ACHANNEL_SET_FLAG(icu, sel, IPO_SELECT);
207                                 icu->flag &= ~IPO_ACTIVE;
208                         }
209                                 break;
210                 }
211         }
212         
213         /* Cleanup */
214         BLI_freelistN(&anim_data);
215 }
216
217 /* ************************************************************************** */
218 /* OPERATORS */
219
220 /* ********************** Select All Operator *********************** */
221
222 static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
223 {
224         bAnimContext ac;
225         
226         /* get editor data */
227         if (ANIM_animdata_get_context(C, &ac) == 0)
228                 return OPERATOR_CANCELLED;
229                 
230         /* 'standard' behaviour - check if selected, then apply relevant selection */
231         if (RNA_boolean_get(op->ptr, "invert"))
232                 ANIM_deselect_anim_channels(ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE);
233         else
234                 ANIM_deselect_anim_channels(ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
235         
236         /* set notifier tha things have changed */
237         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
238         
239         return OPERATOR_FINISHED;
240 }
241  
242 void ANIM_OT_channels_deselectall (wmOperatorType *ot)
243 {
244         /* identifiers */
245         ot->name= "Select All";
246         ot->idname= "ANIM_OT_channels_deselectall";
247         
248         /* api callbacks */
249         ot->exec= animchannels_deselectall_exec;
250         ot->poll= ED_operator_areaactive;
251         
252         /* flags */
253         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
254         
255         /* props */
256         RNA_def_property(ot->srna, "invert", PROP_BOOLEAN, PROP_NONE);
257 }
258
259 /* ******************** Borderselect Operator *********************** */
260
261 // XXX do we need to set some extra thingsfor each channel selected?
262 static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short selectmode)
263 {
264         ListBase anim_data = {NULL, NULL};
265         bAnimListElem *ale;
266         int filter;
267         
268         View2D *v2d= &ac->ar->v2d;
269         rctf rectf;
270         float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT);
271         
272         /* convert border-region to view coordinates */
273         UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin+2, &rectf.xmin, &rectf.ymin);
274         UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax-2, &rectf.xmax, &rectf.ymax);
275         
276         /* filter data */
277         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
278         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
279         
280         /* loop over data, doing border select */
281         for (ale= anim_data.first; ale; ale= ale->next) {
282                 ymin= ymax - ACHANNEL_STEP;
283                 
284                 /* if channel is within border-select region, alter it */
285                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
286                         /* only the following types can be selected */
287                         switch (ale->type) {
288                                 case ANIMTYPE_OBJECT: /* object */
289                                 {
290                                         Base *base= (Base *)ale->data;
291                                         Object *ob= base->object;
292                                         
293                                         ACHANNEL_SET_FLAG(base, selectmode, SELECT);
294                                         ACHANNEL_SET_FLAG(ob, selectmode, SELECT);
295                                 }
296                                         break;
297                                 case ANIMTYPE_GROUP: /* action group */
298                                 {
299                                         bActionGroup *agrp= (bActionGroup *)ale->data;
300                                         
301                                         ACHANNEL_SET_FLAG(agrp, selectmode, AGRP_SELECTED);
302                                 }
303                                         break;
304                                 case ANIMTYPE_ACHAN: /* action channel */
305                                 case ANIMTYPE_FILLIPO: /* expand ipo curves = action channel */
306                                 case ANIMTYPE_FILLCON: /* expand constraint channels = action channel */
307                                 {
308                                         bActionChannel *achan= (bActionChannel *)ale->data;
309                                         
310                                         ACHANNEL_SET_FLAG(achan, selectmode, ACHAN_SELECTED);
311                                         
312                                         /* messy... set active bone */
313                                         //select_poseelement_by_name(achan->name, selectmode);
314                                 }
315                                         break;
316                                 case ANIMTYPE_CONCHAN: /* constraint channel */
317                                 {
318                                         bConstraintChannel *conchan = (bConstraintChannel *)ale->data;
319                                         
320                                         ACHANNEL_SET_FLAG(conchan, selectmode, CONSTRAINT_CHANNEL_SELECT);
321                                 }
322                                         break;
323                                 case ANIMTYPE_ICU: /* ipo-curve channel */
324                                 {
325                                         IpoCurve *icu = (IpoCurve *)ale->data;
326                                         
327                                         ACHANNEL_SET_FLAG(icu, selectmode, IPO_SELECT);
328                                 }
329                                         break;
330                                 case ANIMTYPE_GPLAYER: /* grease-pencil layer */
331                                 {
332                                         bGPDlayer *gpl = (bGPDlayer *)ale->data;
333                                         
334                                         ACHANNEL_SET_FLAG(gpl, selectmode, GP_LAYER_SELECT);
335                                 }
336                                         break;
337                         }
338                         
339                         /* select action-channel 'owner' */
340                         if ((ale->owner) && (ale->ownertype == ANIMTYPE_ACHAN)) {
341                                 //bActionChannel *achano= (bActionChannel *)ale->owner;
342                                 
343                                 /* messy... set active bone */
344                                 //select_poseelement_by_name(achano->name, selectmode);
345                         }
346                 }
347                 
348                 /* set minimum extent to be the maximum of the next channel */
349                 ymax= ymin;
350         }
351         
352         /* cleanup */
353         BLI_freelistN(&anim_data);
354 }
355
356 /* ------------------- */
357
358 static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
359 {
360         bAnimContext ac;
361         rcti rect;
362         short selectmode=0;
363         int event;
364         
365         /* get editor data */
366         if (ANIM_animdata_get_context(C, &ac) == 0)
367                 return OPERATOR_CANCELLED;
368         
369         /* get settings from operator */
370         rect.xmin= RNA_int_get(op->ptr, "xmin");
371         rect.ymin= RNA_int_get(op->ptr, "ymin");
372         rect.xmax= RNA_int_get(op->ptr, "xmax");
373         rect.ymax= RNA_int_get(op->ptr, "ymax");
374                 
375         event= RNA_int_get(op->ptr, "event_type");
376         if (event == LEFTMOUSE) // FIXME... hardcoded
377                 selectmode = ACHANNEL_SETFLAG_ADD;
378         else
379                 selectmode = ACHANNEL_SETFLAG_CLEAR;
380         
381         /* apply borderselect animation channels */
382         borderselect_anim_channels(&ac, &rect, selectmode);
383         
384         return OPERATOR_FINISHED;
385
386
387 void ANIM_OT_channels_borderselect(wmOperatorType *ot)
388 {
389         /* identifiers */
390         ot->name= "Border Select";
391         ot->idname= "ANIM_OT_channels_borderselect";
392         
393         /* api callbacks */
394         ot->invoke= WM_border_select_invoke;
395         ot->exec= animchannels_borderselect_exec;
396         ot->modal= WM_border_select_modal;
397         
398         ot->poll= ED_operator_areaactive;
399         
400         /* flags */
401         // XXX er...
402         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
403         
404         /* rna */
405         RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
406         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
407         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
408         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
409         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
410 }
411
412 /* ******************** Mouse-Click Operator *********************** */
413 /* Depending on the channel that was clicked on, the mouse click will activate whichever
414  * part of the channel is relevant.
415  *
416  * NOTE: eventually, this should probably be phased out when many of these things are replaced with buttons
417  */
418
419 static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, short selectmode)
420 {
421         ListBase anim_data = {NULL, NULL};
422         bAnimListElem *ale;
423         int filter;
424         
425         /* get the channel that was clicked on */
426                 /* filter channels */
427         filter= (ANIMFILTER_FORDRAWING | ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
428         filter= ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
429         
430                 /* get channel from index */
431         ale= BLI_findlink(&anim_data, channel_index);
432         if (ale == NULL) {
433                 /* channel not found */
434                 printf("Error: animation channel not found in mouse_anim_channels() \n");
435                         // XXX remove me..
436                 printf("\t channel index = %d, channels = %d\n", channel_index, filter);
437                 
438                 BLI_freelistN(&anim_data);
439                 return;
440         }
441         
442         /* action to take depends on what channel we've got */
443         switch (ale->type) {
444                 case ANIMTYPE_OBJECT:
445                         {
446                                 bDopeSheet *ads= (bDopeSheet *)ac->data;
447                                 Scene *sce= (Scene *)ads->source;
448                                 Base *base= (Base *)ale->data;
449                                 Object *ob= base->object;
450                                 
451                                 if (x < 16) {
452                                         /* toggle expand */
453                                         ob->nlaflag ^= OB_ADS_COLLAPSED;
454                                 }
455                                 else {
456                                         /* set selection status */
457                                         // FIXME: this needs to use the new stuff...
458                                         if (selectmode == SELECT_INVERT) {
459                                                 /* swap select */
460                                                 base->flag ^= SELECT;
461                                                 ob->flag= base->flag;
462                                         }
463                                         else {
464                                                 Base *b;
465                                                 
466                                                 /* deleselect all */
467                                                 for (b= sce->base.first; b; b= b->next) {
468                                                         b->flag &= ~SELECT;
469                                                         b->object->flag= b->flag;
470                                                 }
471                                                 
472                                                 /* select object now */
473                                                 base->flag |= SELECT;
474                                                 ob->flag |= SELECT;
475                                         }
476                                         
477                                         //set_active_base(base);        /* editview.c */
478                                 }
479                         }
480                                 break;
481                 case ANIMTYPE_FILLIPOD:
482                         {
483                                 Object *ob= (Object *)ale->data;
484                                 ob->nlaflag ^= OB_ADS_SHOWIPO;
485                         }
486                                 break;
487                 case ANIMTYPE_FILLACTD:
488                         {
489                                 bAction *act= (bAction *)ale->data;
490                                 act->flag ^= ACTC_EXPANDED;
491                         }
492                                 break;
493                 case ANIMTYPE_FILLCOND:
494                         {
495                                 Object *ob= (Object *)ale->data;
496                                 ob->nlaflag ^= OB_ADS_SHOWCONS;
497                         }
498                                 break;
499                 case ANIMTYPE_FILLMATD:
500                         {
501                                 Object *ob= (Object *)ale->data;
502                                 ob->nlaflag ^= OB_ADS_SHOWMATS;
503                         }
504                                 break;
505                                 
506                 case ANIMTYPE_DSMAT:
507                         {
508                                 Material *ma= (Material *)ale->data;
509                                 ma->flag ^= MA_DS_EXPAND;
510                         }
511                                 break;
512                 case ANIMTYPE_DSLAM:
513                         {
514                                 Lamp *la= (Lamp *)ale->data;
515                                 la->flag ^= LA_DS_EXPAND;
516                         }
517                                 break;
518                 case ANIMTYPE_DSCAM:
519                         {
520                                 Camera *ca= (Camera *)ale->data;
521                                 ca->flag ^= CAM_DS_EXPAND;
522                         }
523                                 break;
524                 case ANIMTYPE_DSCUR:
525                         {
526                                 Curve *cu= (Curve *)ale->data;
527                                 cu->flag ^= CU_DS_EXPAND;
528                         }
529                                 break;
530                 case ANIMTYPE_DSSKEY:
531                         {
532                                 Key *key= (Key *)ale->data;
533                                 key->flag ^= KEYBLOCK_DS_EXPAND;
534                         }
535                                 break;
536                         
537                 case ANIMTYPE_GROUP: 
538                         {
539                                 bActionGroup *agrp= (bActionGroup *)ale->data;
540                                 short offset= (ac->datatype == ANIMCONT_DOPESHEET)? 21 : 0;
541                                 
542                                 if ((x < (offset+17)) && (agrp->channels.first)) {
543                                         /* toggle expand */
544                                         agrp->flag ^= AGRP_EXPANDED;
545                                 }
546                                 else if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
547                                         /* toggle protection/locking */
548                                         agrp->flag ^= AGRP_PROTECTED;
549                                 }
550                                 else {
551                                         /* select/deselect group */
552                                         if (selectmode == SELECT_INVERT) {
553                                                 /* inverse selection status of group */
554                                                 //select_action_group(act, agrp, SELECT_INVERT);
555                                         }
556                                         else if (/*G.qual == (LR_CTRLKEY|LR_SHIFTKEY)*/selectmode == -1) {
557                                                 // FIXME: need a special case for this!
558                                                 /* select all in group (and deselect everthing else) */ 
559                                                 //select_action_group_channels(act, agrp);
560                                                 //select_action_group(act, agrp, SELECT_ADD);
561                                         }
562                                         else {
563                                                 /* select group by itself */
564                                                 ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
565                                                 //select_action_group(act, agrp, SELECT_ADD);
566                                         }
567                                         
568                                         // XXX
569                                         agrp->flag ^= AGRP_SELECTED;
570                                 }
571                         }
572                         break;
573                 case ANIMTYPE_ACHAN:
574                         {
575                                 bActionChannel *achan= (bActionChannel *)ale->data;
576                                 short offset= (ac->datatype == ANIMCONT_DOPESHEET)? 21 : 0;
577                                 
578                                 if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
579                                         /* toggle protect */
580                                         achan->flag ^= ACHAN_PROTECTED;
581                                 }
582                                 else if ((x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) && (achan->ipo)) {
583                                         /* toggle mute */
584                                         achan->ipo->muteipo = (achan->ipo->muteipo)? 0: 1;
585                                 }
586                                 else if (x <= (offset+17)) {
587                                         /* toggle expand */
588                                         achan->flag ^= ACHAN_EXPANDED;
589                                 }                               
590                                 else {
591                                         /* select/deselect achan */             
592                                         if (selectmode == SELECT_INVERT) {
593                                                 //select_channel(act, achan, SELECT_INVERT);
594                                         }
595                                         else {
596                                                 ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
597                                                 //select_channel(act, achan, SELECT_ADD);
598                                         }
599                                         
600                                         /* messy... set active bone */
601                                         //select_poseelement_by_name(achan->name, 2);
602                                         
603                                         // XXX for now only
604                                         achan->flag ^= ACHAN_SELECTED;
605                                 }
606                         }
607                                 break;
608                 case ANIMTYPE_FILLIPO:
609                         {
610                                 bActionChannel *achan= (bActionChannel *)ale->data;
611                                 
612                                 achan->flag ^= ACHAN_SHOWIPO;
613                                 
614                                 if ((x > 24) && (achan->flag & ACHAN_SHOWIPO)) {
615                                         /* select+make active achan */          
616                                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
617                                         //select_channel(act, achan, SELECT_ADD);
618                                         
619                                         /* messy... set active bone */
620                                         //select_poseelement_by_name(achan->name, 2);
621                                         
622                                         // XXX for now only
623                                         achan->flag ^= ACHAN_SELECTED;
624                                 }       
625                         }
626                         break;
627                 case ANIMTYPE_FILLCON:
628                         {
629                                 bActionChannel *achan= (bActionChannel *)ale->data;
630                                 
631                                 achan->flag ^= ACHAN_SHOWCONS;
632                                 
633                                 if ((x > 24) && (achan->flag & ACHAN_SHOWCONS)) {
634                                         /* select+make active achan */  
635                                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
636                                         //select_channel(act, achan, SELECT_ADD);
637                                         
638                                         /* messy... set active bone */
639                                         //select_poseelement_by_name(achan->name, 2);
640                                         
641                                         // XXX for now only
642                                         achan->flag ^= ACHAN_SELECTED;
643                                 }       
644                         }
645                         break;
646                 case ANIMTYPE_ICU: 
647                         {
648                                 IpoCurve *icu= (IpoCurve *)ale->data;
649                                 
650                                 if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
651                                         /* toggle protection */
652                                         icu->flag ^= IPO_PROTECT;
653                                 }
654                                 else if (x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) {
655                                         /* toggle mute */
656                                         icu->flag ^= IPO_MUTE;
657                                 }
658                                 else {
659                                         /* select/deselect */
660                                         //select_icu_channel(act, icu, SELECT_INVERT);
661                                         
662                                         // XXX for now only
663                                         icu->flag ^= IPO_SELECT;
664                                 }
665                         }
666                         break;
667                 case ANIMTYPE_CONCHAN:
668                         {
669                                 bConstraintChannel *conchan= (bConstraintChannel *)ale->data;
670                                 
671                                 if (x >= (ACHANNEL_NAMEWIDTH-16)) {
672                                         /* toggle protection */
673                                         conchan->flag ^= CONSTRAINT_CHANNEL_PROTECTED;
674                                 }
675                                 else if ((x >= (ACHANNEL_NAMEWIDTH-32)) && (conchan->ipo)) {
676                                         /* toggle mute */
677                                         conchan->ipo->muteipo = (conchan->ipo->muteipo)? 0: 1;
678                                 }
679                                 else {
680                                         /* select/deselect */
681                                         //select_constraint_channel(act, conchan, SELECT_INVERT);
682                                         
683                                         // XXX for now only
684                                         conchan->flag ^= CONSTRAINT_CHANNEL_SELECT;
685                                 }
686                         }
687                                 break;
688                 case ANIMTYPE_GPDATABLOCK:
689                         {
690                                 bGPdata *gpd= (bGPdata *)ale->data;
691                                 
692                                 /* toggle expand */
693                                 gpd->flag ^= GP_DATA_EXPAND;
694                         }
695                                 break;
696                 case ANIMTYPE_GPLAYER:
697                         {
698 #if 0 // XXX future of this is unclear
699                                 bGPdata *gpd= (bGPdata *)ale->owner;
700                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
701                                 
702                                 if (x >= (ACHANNEL_NAMEWIDTH-16)) {
703                                         /* toggle lock */
704                                         gpl->flag ^= GP_LAYER_LOCKED;
705                                 }
706                                 else if (x >= (ACHANNEL_NAMEWIDTH-32)) {
707                                         /* toggle hide */
708                                         gpl->flag ^= GP_LAYER_HIDE;
709                                 }
710                                 else {
711                                         /* select/deselect */
712                                         //if (G.qual & LR_SHIFTKEY) {
713                                                 //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
714                                         //}
715                                         //else {
716                                                 //deselect_gpencil_layers(data, 0);
717                                                 //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
718                                         //}
719                                 }
720 #endif // XXX future of this is unclear
721                         }
722                                 break;
723                 case ANIMTYPE_SHAPEKEY:
724                         /* TODO: shapekey channels cannot be selected atm... */
725                         break;
726                 default:
727                         printf("Error: Invalid channel type in mouse_anim_channels() \n");
728         }
729         
730         /* free channels */
731         BLI_freelistN(&anim_data);
732 }
733
734 /* ------------------- */
735
736 /* handle clicking */
737 static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
738 {
739         bAnimContext ac;
740         Scene *scene;
741         ARegion *ar;
742         View2D *v2d;
743         int mval[2], channel_index;
744         short selectmode;
745         float x, y;
746         
747         
748         /* get editor data */
749         if (ANIM_animdata_get_context(C, &ac) == 0)
750                 return OPERATOR_CANCELLED;
751                 
752         /* get useful pointers from animation context data */
753         scene= ac.scene;
754         ar= ac.ar;
755         v2d= &ar->v2d;
756         
757         /* get mouse coordinates (in region coordinates) */
758         mval[0]= (event->x - ar->winrct.xmin);
759         mval[1]= (event->y - ar->winrct.ymin);
760         
761         /* select mode is either replace (deselect all, then add) or add/extend */
762         if (RNA_boolean_get(op->ptr, "extend_select"))
763                 selectmode= SELECT_INVERT;
764         else
765                 selectmode= SELECT_REPLACE;
766         
767         /* figure out which channel user clicked in 
768          * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height
769          *              so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
770          *              ACHANNEL_HEIGHT_HALF.
771          */
772         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
773         UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
774         
775         /* handle mouse-click in the relevant channel then */
776         mouse_anim_channels(&ac, x, channel_index, selectmode);
777         
778         /* set notifier tha things have changed */
779         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
780         
781         return OPERATOR_FINISHED;
782 }
783  
784 void ANIM_OT_channels_mouseclick (wmOperatorType *ot)
785 {
786         /* identifiers */
787         ot->name= "Mouse Click on Channels";
788         ot->idname= "ANIM_OT_channels_mouseclick";
789         
790         /* api callbacks */
791         ot->invoke= animchannels_mouseclick_invoke;
792         ot->poll= ED_operator_areaactive;
793         
794         /* id-props */
795         RNA_def_property(ot->srna, "extend_select", PROP_BOOLEAN, PROP_NONE); // SHIFTKEY
796 }
797
798 /* ************************************************************************** */
799 /* Operator Registration */
800
801 void ED_operatortypes_animchannels(void)
802 {
803         WM_operatortype_append(ANIM_OT_channels_deselectall);
804         WM_operatortype_append(ANIM_OT_channels_borderselect);
805         WM_operatortype_append(ANIM_OT_channels_mouseclick);
806 }
807
808 void ED_keymap_animchannels(wmWindowManager *wm)
809 {
810         ListBase *keymap = WM_keymap_listbase(wm, "Animation_Channels", 0, 0);
811         
812         /* selection */
813                 /* click-select */
814                 // XXX for now, only leftmouse.... 
815         WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, 0, 0);
816         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend_select", 1);
817         
818                 /* deselect all */
819         WM_keymap_add_item(keymap, "ANIM_OT_channels_deselectall", AKEY, KM_PRESS, 0, 0);
820         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_deselectall", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
821         
822                 /* borderselect */
823         WM_keymap_add_item(keymap, "ANIM_OT_channels_borderselect", BKEY, KM_PRESS, 0, 0);
824 }
825
826 /* ************************************************************************** */