2.5 - Action Editor: Toggle settings
[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 /* ********************** Set Flags Operator *********************** */
221
222 enum {
223 //      ACHANNEL_SETTING_SELECT = 0,
224         ACHANNEL_SETTING_PROTECT = 1,
225         ACHANNEL_SETTING_MUTE,
226 } eAnimChannel_Settings;
227
228 /* defines for setting animation-channel flags */
229 EnumPropertyItem prop_animchannel_setflag_types[] = {
230         {ACHANNEL_SETFLAG_CLEAR, "DISABLE", "Disable", ""},
231         {ACHANNEL_SETFLAG_ADD, "ENABLE", "Enable", ""},
232         {ACHANNEL_SETFLAG_TOGGLE, "TOGGLE", "Toggle", ""},
233         {0, NULL, NULL, NULL}
234 };
235
236 /* defines for set animation-channel settings */
237 EnumPropertyItem prop_animchannel_settings_types[] = {
238         {ACHANNEL_SETTING_PROTECT, "PROTECT", "Protect", ""},
239         {ACHANNEL_SETTING_MUTE, "MUTE", "Mute", ""},
240         {0, NULL, NULL, NULL}
241 };
242
243
244 /* ------------------- */
245
246 /* Set/clear a particular flag (setting) for all selected + visible channels 
247  *      setting: the setting to modify
248  *      mode: eAnimChannels_SetFlag
249  */
250 static void setflag_anim_channels (bAnimContext *ac, short setting, short mode)
251 {
252         ListBase anim_data = {NULL, NULL};
253         bAnimListElem *ale;
254         int filter;
255         
256         /* filter data */
257         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS | ANIMFILTER_SEL);
258         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
259         
260         /* affect selected channels */
261         for (ale= anim_data.first; ale; ale= ale->next) {
262                 switch (ale->type) {
263                         case ANIMTYPE_GROUP:
264                         {
265                                 bActionGroup *agrp= (bActionGroup *)ale->data;
266                                 
267                                 /* only 'protect' is available */
268                                 if (setting == ACHANNEL_SETTING_PROTECT) {
269                                         ACHANNEL_SET_FLAG(agrp, mode, AGRP_PROTECTED);
270                                 }
271                         }
272                                 break;
273                         case ANIMTYPE_ACHAN:
274                         {
275                                 bActionChannel *achan= (bActionChannel *)ale->data;
276                                 
277                                 /* 'protect' and 'mute' */
278                                 if ((setting == ACHANNEL_SETTING_MUTE) && (achan->ipo)) {
279                                         Ipo *ipo= achan->ipo;
280                                         
281                                         /* mute */
282                                         if (mode == 0)
283                                                 ipo->muteipo= 0;
284                                         else if (mode == 1)
285                                                 ipo->muteipo= 1;
286                                         else if (mode == 2) 
287                                                 ipo->muteipo= (ipo->muteipo) ? 0 : 1;
288                                 }
289                                 else if (setting == ACHANNEL_SETTING_PROTECT) {
290                                         /* protected */
291                                         ACHANNEL_SET_FLAG(achan, mode, ACHAN_PROTECTED);
292                                 }
293                         }
294                                 break;
295                         case ANIMTYPE_CONCHAN:
296                         {
297                                 bConstraintChannel *conchan= (bConstraintChannel *)ale->data;
298                                 
299                                 /* 'protect' and 'mute' */
300                                 if ((setting == ACHANNEL_SETTING_MUTE) && (conchan->ipo)) {
301                                         Ipo *ipo= conchan->ipo;
302                                         
303                                         /* mute */
304                                         if (mode == 0)
305                                                 ipo->muteipo= 0;
306                                         else if (mode == 1)
307                                                 ipo->muteipo= 1;
308                                         else if (mode == 2) 
309                                                 ipo->muteipo= (ipo->muteipo) ? 0 : 1;
310                                 }
311                                 else if (setting == ACHANNEL_SETTING_PROTECT) {
312                                         /* protect */
313                                         ACHANNEL_SET_FLAG(conchan, mode, CONSTRAINT_CHANNEL_PROTECTED);
314                                 }
315                         }
316                                 break;
317                         case ANIMTYPE_ICU:
318                         {
319                                 IpoCurve *icu= (IpoCurve *)ale->data;
320                                 
321                                 /* mute */
322                                 if (setting == ACHANNEL_SETTING_MUTE) {
323                                         ACHANNEL_SET_FLAG(icu, mode, IPO_MUTE);
324                                 }
325                                 else if (setting == ACHANNEL_SETTING_PROTECT) {
326                                         ACHANNEL_SET_FLAG(icu, mode, IPO_PROTECT);
327                                 }
328                         }
329                                 break;
330                         case ANIMTYPE_GPLAYER:
331                         {
332                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
333                                 
334                                 /* 'protect' and 'mute' */
335                                 if (setting == ACHANNEL_SETTING_MUTE) {
336                                         /* mute */
337                                         ACHANNEL_SET_FLAG(gpl, mode, GP_LAYER_HIDE);
338                                 }
339                                 else if (setting == ACHANNEL_SETTING_PROTECT) {
340                                         /* protected */
341                                         ACHANNEL_SET_FLAG(gpl, mode, GP_LAYER_LOCKED);
342                                 }
343                         }
344                                 break;
345                 }
346         }
347         
348         BLI_freelistN(&anim_data);
349 }
350
351 /* ------------------- */
352
353 static int animchannels_setflag_exec(bContext *C, wmOperator *op)
354 {
355         bAnimContext ac;
356         short mode, setting;
357         
358         /* get editor data */
359         if (ANIM_animdata_get_context(C, &ac) == 0)
360                 return OPERATOR_CANCELLED;
361                 
362         /* mode (eAnimChannels_SetFlag), setting (eAnimChannel_Settings) */
363         mode= RNA_enum_get(op->ptr, "mode");
364         setting= RNA_enum_get(op->ptr, "type");
365         
366         /* modify setting */
367         setflag_anim_channels(&ac, setting, mode);
368         
369         /* set notifier tha things have changed */
370         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
371         
372         return OPERATOR_FINISHED;
373 }
374
375
376 void ANIM_OT_channels_enable_setting (wmOperatorType *ot)
377 {
378         PropertyRNA *prop;
379         
380         /* identifiers */
381         ot->name= "Enable Channel Setting";
382         ot->idname= "ANIM_OT_channels_enable_setting";
383         
384         /* api callbacks */
385         ot->invoke= WM_menu_invoke;
386         ot->exec= animchannels_setflag_exec;
387         ot->poll= ED_operator_areaactive;
388         
389         /* flags */
390         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
391         
392         /* props */
393                 /* flag-setting mode */
394         prop= RNA_def_property(ot->srna, "mode", PROP_ENUM, PROP_NONE);
395         RNA_def_property_enum_items(prop, prop_animchannel_setflag_types);
396         RNA_def_property_enum_default(prop, ACHANNEL_SETFLAG_ADD);
397                 /* setting to set */
398         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
399         RNA_def_property_enum_items(prop, prop_animchannel_settings_types);
400 }
401
402 void ANIM_OT_channels_disable_setting (wmOperatorType *ot)
403 {
404         PropertyRNA *prop;
405         
406         /* identifiers */
407         ot->name= "Disable Channel Setting";
408         ot->idname= "ANIM_OT_channels_disable_setting";
409         
410         /* api callbacks */
411         ot->invoke= WM_menu_invoke;
412         ot->exec= animchannels_setflag_exec;
413         ot->poll= ED_operator_areaactive;
414         
415         /* flags */
416         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
417         
418         /* props */
419                 /* flag-setting mode */
420         prop= RNA_def_property(ot->srna, "mode", PROP_ENUM, PROP_NONE);
421         RNA_def_property_enum_items(prop, prop_animchannel_setflag_types);
422         RNA_def_property_enum_default(prop, ACHANNEL_SETFLAG_CLEAR);
423                 /* setting to set */
424         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
425         RNA_def_property_enum_items(prop, prop_animchannel_settings_types);
426 }
427
428 void ANIM_OT_channels_toggle_setting (wmOperatorType *ot)
429 {
430         PropertyRNA *prop;
431         
432         /* identifiers */
433         ot->name= "Toggle Channel Setting";
434         ot->idname= "ANIM_OT_channels_toggle_setting";
435         
436         /* api callbacks */
437         ot->invoke= WM_menu_invoke;
438         ot->exec= animchannels_setflag_exec;
439         ot->poll= ED_operator_areaactive;
440         
441         /* flags */
442         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
443         
444         /* props */
445                 /* flag-setting mode */
446         prop= RNA_def_property(ot->srna, "mode", PROP_ENUM, PROP_NONE);
447         RNA_def_property_enum_items(prop, prop_animchannel_setflag_types);
448         RNA_def_property_enum_default(prop, ACHANNEL_SETFLAG_TOGGLE);
449                 /* setting to set */
450         prop= RNA_def_property(ot->srna, "type", PROP_ENUM, PROP_NONE);
451         RNA_def_property_enum_items(prop, prop_animchannel_settings_types);
452 }
453
454 /* ********************** Select All Operator *********************** */
455
456 static int animchannels_deselectall_exec(bContext *C, wmOperator *op)
457 {
458         bAnimContext ac;
459         
460         /* get editor data */
461         if (ANIM_animdata_get_context(C, &ac) == 0)
462                 return OPERATOR_CANCELLED;
463                 
464         /* 'standard' behaviour - check if selected, then apply relevant selection */
465         if (RNA_boolean_get(op->ptr, "invert"))
466                 ANIM_deselect_anim_channels(ac.data, ac.datatype, 0, ACHANNEL_SETFLAG_TOGGLE);
467         else
468                 ANIM_deselect_anim_channels(ac.data, ac.datatype, 1, ACHANNEL_SETFLAG_ADD);
469         
470         /* set notifier tha things have changed */
471         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
472         
473         return OPERATOR_FINISHED;
474 }
475  
476 void ANIM_OT_channels_deselectall (wmOperatorType *ot)
477 {
478         /* identifiers */
479         ot->name= "Select All";
480         ot->idname= "ANIM_OT_channels_deselectall";
481         
482         /* api callbacks */
483         ot->exec= animchannels_deselectall_exec;
484         ot->poll= ED_operator_areaactive;
485         
486         /* flags */
487         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
488         
489         /* props */
490         RNA_def_property(ot->srna, "invert", PROP_BOOLEAN, PROP_NONE);
491 }
492
493 /* ******************** Borderselect Operator *********************** */
494
495 // XXX do we need to set some extra thingsfor each channel selected?
496 static void borderselect_anim_channels (bAnimContext *ac, rcti *rect, short selectmode)
497 {
498         ListBase anim_data = {NULL, NULL};
499         bAnimListElem *ale;
500         int filter;
501         
502         View2D *v2d= &ac->ar->v2d;
503         rctf rectf;
504         float ymin=0, ymax=(float)(-ACHANNEL_HEIGHT);
505         
506         /* convert border-region to view coordinates */
507         UI_view2d_region_to_view(v2d, rect->xmin, rect->ymin+2, &rectf.xmin, &rectf.ymin);
508         UI_view2d_region_to_view(v2d, rect->xmax, rect->ymax-2, &rectf.xmax, &rectf.ymax);
509         
510         /* filter data */
511         filter= (ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
512         ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
513         
514         /* loop over data, doing border select */
515         for (ale= anim_data.first; ale; ale= ale->next) {
516                 ymin= ymax - ACHANNEL_STEP;
517                 
518                 /* if channel is within border-select region, alter it */
519                 if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
520                         /* only the following types can be selected */
521                         switch (ale->type) {
522                                 case ANIMTYPE_OBJECT: /* object */
523                                 {
524                                         Base *base= (Base *)ale->data;
525                                         Object *ob= base->object;
526                                         
527                                         ACHANNEL_SET_FLAG(base, selectmode, SELECT);
528                                         ACHANNEL_SET_FLAG(ob, selectmode, SELECT);
529                                 }
530                                         break;
531                                 case ANIMTYPE_GROUP: /* action group */
532                                 {
533                                         bActionGroup *agrp= (bActionGroup *)ale->data;
534                                         
535                                         ACHANNEL_SET_FLAG(agrp, selectmode, AGRP_SELECTED);
536                                 }
537                                         break;
538                                 case ANIMTYPE_ACHAN: /* action channel */
539                                 case ANIMTYPE_FILLIPO: /* expand ipo curves = action channel */
540                                 case ANIMTYPE_FILLCON: /* expand constraint channels = action channel */
541                                 {
542                                         bActionChannel *achan= (bActionChannel *)ale->data;
543                                         
544                                         ACHANNEL_SET_FLAG(achan, selectmode, ACHAN_SELECTED);
545                                         
546                                         /* messy... set active bone */
547                                         //select_poseelement_by_name(achan->name, selectmode);
548                                 }
549                                         break;
550                                 case ANIMTYPE_CONCHAN: /* constraint channel */
551                                 {
552                                         bConstraintChannel *conchan = (bConstraintChannel *)ale->data;
553                                         
554                                         ACHANNEL_SET_FLAG(conchan, selectmode, CONSTRAINT_CHANNEL_SELECT);
555                                 }
556                                         break;
557                                 case ANIMTYPE_ICU: /* ipo-curve channel */
558                                 {
559                                         IpoCurve *icu = (IpoCurve *)ale->data;
560                                         
561                                         ACHANNEL_SET_FLAG(icu, selectmode, IPO_SELECT);
562                                 }
563                                         break;
564                                 case ANIMTYPE_GPLAYER: /* grease-pencil layer */
565                                 {
566                                         bGPDlayer *gpl = (bGPDlayer *)ale->data;
567                                         
568                                         ACHANNEL_SET_FLAG(gpl, selectmode, GP_LAYER_SELECT);
569                                 }
570                                         break;
571                         }
572                         
573                         /* select action-channel 'owner' */
574                         if ((ale->owner) && (ale->ownertype == ANIMTYPE_ACHAN)) {
575                                 //bActionChannel *achano= (bActionChannel *)ale->owner;
576                                 
577                                 /* messy... set active bone */
578                                 //select_poseelement_by_name(achano->name, selectmode);
579                         }
580                 }
581                 
582                 /* set minimum extent to be the maximum of the next channel */
583                 ymax= ymin;
584         }
585         
586         /* cleanup */
587         BLI_freelistN(&anim_data);
588 }
589
590 /* ------------------- */
591
592 static int animchannels_borderselect_exec(bContext *C, wmOperator *op)
593 {
594         bAnimContext ac;
595         rcti rect;
596         short selectmode=0;
597         int event;
598         
599         /* get editor data */
600         if (ANIM_animdata_get_context(C, &ac) == 0)
601                 return OPERATOR_CANCELLED;
602         
603         /* get settings from operator */
604         rect.xmin= RNA_int_get(op->ptr, "xmin");
605         rect.ymin= RNA_int_get(op->ptr, "ymin");
606         rect.xmax= RNA_int_get(op->ptr, "xmax");
607         rect.ymax= RNA_int_get(op->ptr, "ymax");
608                 
609         event= RNA_int_get(op->ptr, "event_type");
610         if (event == LEFTMOUSE) // FIXME... hardcoded
611                 selectmode = ACHANNEL_SETFLAG_ADD;
612         else
613                 selectmode = ACHANNEL_SETFLAG_CLEAR;
614         
615         /* apply borderselect animation channels */
616         borderselect_anim_channels(&ac, &rect, selectmode);
617         
618         return OPERATOR_FINISHED;
619
620
621 void ANIM_OT_channels_borderselect(wmOperatorType *ot)
622 {
623         /* identifiers */
624         ot->name= "Border Select";
625         ot->idname= "ANIM_OT_channels_borderselect";
626         
627         /* api callbacks */
628         ot->invoke= WM_border_select_invoke;
629         ot->exec= animchannels_borderselect_exec;
630         ot->modal= WM_border_select_modal;
631         
632         ot->poll= ED_operator_areaactive;
633         
634         /* flags */
635         // XXX er...
636         ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
637         
638         /* rna */
639         RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
640         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
641         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
642         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
643         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
644 }
645
646 /* ******************** Mouse-Click Operator *********************** */
647 /* Depending on the channel that was clicked on, the mouse click will activate whichever
648  * part of the channel is relevant.
649  *
650  * NOTE: eventually, this should probably be phased out when many of these things are replaced with buttons
651  */
652
653 static void mouse_anim_channels (bAnimContext *ac, float x, int channel_index, short selectmode)
654 {
655         ListBase anim_data = {NULL, NULL};
656         bAnimListElem *ale;
657         int filter;
658         
659         /* get the channel that was clicked on */
660                 /* filter channels */
661         filter= (ANIMFILTER_FORDRAWING | ANIMFILTER_VISIBLE | ANIMFILTER_CHANNELS);
662         filter= ANIM_animdata_filter(&anim_data, filter, ac->data, ac->datatype);
663         
664                 /* get channel from index */
665         ale= BLI_findlink(&anim_data, channel_index);
666         if (ale == NULL) {
667                 /* channel not found */
668                 printf("Error: animation channel not found in mouse_anim_channels() \n");
669                         // XXX remove me..
670                 printf("\t channel index = %d, channels = %d\n", channel_index, filter);
671                 
672                 BLI_freelistN(&anim_data);
673                 return;
674         }
675         
676         /* action to take depends on what channel we've got */
677         switch (ale->type) {
678                 case ANIMTYPE_OBJECT:
679                         {
680                                 bDopeSheet *ads= (bDopeSheet *)ac->data;
681                                 Scene *sce= (Scene *)ads->source;
682                                 Base *base= (Base *)ale->data;
683                                 Object *ob= base->object;
684                                 
685                                 if (x < 16) {
686                                         /* toggle expand */
687                                         ob->nlaflag ^= OB_ADS_COLLAPSED;
688                                 }
689                                 else {
690                                         /* set selection status */
691                                         // FIXME: this needs to use the new stuff...
692                                         if (selectmode == SELECT_INVERT) {
693                                                 /* swap select */
694                                                 base->flag ^= SELECT;
695                                                 ob->flag= base->flag;
696                                         }
697                                         else {
698                                                 Base *b;
699                                                 
700                                                 /* deleselect all */
701                                                 for (b= sce->base.first; b; b= b->next) {
702                                                         b->flag &= ~SELECT;
703                                                         b->object->flag= b->flag;
704                                                 }
705                                                 
706                                                 /* select object now */
707                                                 base->flag |= SELECT;
708                                                 ob->flag |= SELECT;
709                                         }
710                                         
711                                         //set_active_base(base);        /* editview.c */
712                                 }
713                         }
714                                 break;
715                 case ANIMTYPE_FILLIPOD:
716                         {
717                                 Object *ob= (Object *)ale->data;
718                                 ob->nlaflag ^= OB_ADS_SHOWIPO;
719                         }
720                                 break;
721                 case ANIMTYPE_FILLACTD:
722                         {
723                                 bAction *act= (bAction *)ale->data;
724                                 act->flag ^= ACTC_EXPANDED;
725                         }
726                                 break;
727                 case ANIMTYPE_FILLCOND:
728                         {
729                                 Object *ob= (Object *)ale->data;
730                                 ob->nlaflag ^= OB_ADS_SHOWCONS;
731                         }
732                                 break;
733                 case ANIMTYPE_FILLMATD:
734                         {
735                                 Object *ob= (Object *)ale->data;
736                                 ob->nlaflag ^= OB_ADS_SHOWMATS;
737                         }
738                                 break;
739                                 
740                 case ANIMTYPE_DSMAT:
741                         {
742                                 Material *ma= (Material *)ale->data;
743                                 ma->flag ^= MA_DS_EXPAND;
744                         }
745                                 break;
746                 case ANIMTYPE_DSLAM:
747                         {
748                                 Lamp *la= (Lamp *)ale->data;
749                                 la->flag ^= LA_DS_EXPAND;
750                         }
751                                 break;
752                 case ANIMTYPE_DSCAM:
753                         {
754                                 Camera *ca= (Camera *)ale->data;
755                                 ca->flag ^= CAM_DS_EXPAND;
756                         }
757                                 break;
758                 case ANIMTYPE_DSCUR:
759                         {
760                                 Curve *cu= (Curve *)ale->data;
761                                 cu->flag ^= CU_DS_EXPAND;
762                         }
763                                 break;
764                 case ANIMTYPE_DSSKEY:
765                         {
766                                 Key *key= (Key *)ale->data;
767                                 key->flag ^= KEYBLOCK_DS_EXPAND;
768                         }
769                                 break;
770                         
771                 case ANIMTYPE_GROUP: 
772                         {
773                                 bActionGroup *agrp= (bActionGroup *)ale->data;
774                                 short offset= (ac->datatype == ANIMCONT_DOPESHEET)? 21 : 0;
775                                 
776                                 if ((x < (offset+17)) && (agrp->channels.first)) {
777                                         /* toggle expand */
778                                         agrp->flag ^= AGRP_EXPANDED;
779                                 }
780                                 else if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
781                                         /* toggle protection/locking */
782                                         agrp->flag ^= AGRP_PROTECTED;
783                                 }
784                                 else {
785                                         /* select/deselect group */
786                                         if (selectmode == SELECT_INVERT) {
787                                                 /* inverse selection status of group */
788                                                 //select_action_group(act, agrp, SELECT_INVERT);
789                                         }
790                                         else if (/*G.qual == (LR_CTRLKEY|LR_SHIFTKEY)*/selectmode == -1) {
791                                                 // FIXME: need a special case for this!
792                                                 /* select all in group (and deselect everthing else) */ 
793                                                 //select_action_group_channels(act, agrp);
794                                                 //select_action_group(act, agrp, SELECT_ADD);
795                                         }
796                                         else {
797                                                 /* select group by itself */
798                                                 ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
799                                                 //select_action_group(act, agrp, SELECT_ADD);
800                                         }
801                                         
802                                         // XXX
803                                         agrp->flag ^= AGRP_SELECTED;
804                                 }
805                         }
806                         break;
807                 case ANIMTYPE_ACHAN:
808                         {
809                                 bActionChannel *achan= (bActionChannel *)ale->data;
810                                 short offset= (ac->datatype == ANIMCONT_DOPESHEET)? 21 : 0;
811                                 
812                                 if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
813                                         /* toggle protect */
814                                         achan->flag ^= ACHAN_PROTECTED;
815                                 }
816                                 else if ((x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) && (achan->ipo)) {
817                                         /* toggle mute */
818                                         achan->ipo->muteipo = (achan->ipo->muteipo)? 0: 1;
819                                 }
820                                 else if (x <= (offset+17)) {
821                                         /* toggle expand */
822                                         achan->flag ^= ACHAN_EXPANDED;
823                                 }                               
824                                 else {
825                                         /* select/deselect achan */             
826                                         if (selectmode == SELECT_INVERT) {
827                                                 //select_channel(act, achan, SELECT_INVERT);
828                                         }
829                                         else {
830                                                 ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
831                                                 //select_channel(act, achan, SELECT_ADD);
832                                         }
833                                         
834                                         /* messy... set active bone */
835                                         //select_poseelement_by_name(achan->name, 2);
836                                         
837                                         // XXX for now only
838                                         achan->flag ^= ACHAN_SELECTED;
839                                 }
840                         }
841                                 break;
842                 case ANIMTYPE_FILLIPO:
843                         {
844                                 bActionChannel *achan= (bActionChannel *)ale->data;
845                                 
846                                 achan->flag ^= ACHAN_SHOWIPO;
847                                 
848                                 if ((x > 24) && (achan->flag & ACHAN_SHOWIPO)) {
849                                         /* select+make active achan */          
850                                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
851                                         //select_channel(act, achan, SELECT_ADD);
852                                         
853                                         /* messy... set active bone */
854                                         //select_poseelement_by_name(achan->name, 2);
855                                         
856                                         // XXX for now only
857                                         achan->flag ^= ACHAN_SELECTED;
858                                 }       
859                         }
860                         break;
861                 case ANIMTYPE_FILLCON:
862                         {
863                                 bActionChannel *achan= (bActionChannel *)ale->data;
864                                 
865                                 achan->flag ^= ACHAN_SHOWCONS;
866                                 
867                                 if ((x > 24) && (achan->flag & ACHAN_SHOWCONS)) {
868                                         /* select+make active achan */  
869                                         ANIM_deselect_anim_channels(ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
870                                         //select_channel(act, achan, SELECT_ADD);
871                                         
872                                         /* messy... set active bone */
873                                         //select_poseelement_by_name(achan->name, 2);
874                                         
875                                         // XXX for now only
876                                         achan->flag ^= ACHAN_SELECTED;
877                                 }       
878                         }
879                         break;
880                 case ANIMTYPE_ICU: 
881                         {
882                                 IpoCurve *icu= (IpoCurve *)ale->data;
883                                 
884                                 if (x >= (ACHANNEL_NAMEWIDTH-ACHANNEL_BUTTON_WIDTH)) {
885                                         /* toggle protection */
886                                         icu->flag ^= IPO_PROTECT;
887                                 }
888                                 else if (x >= (ACHANNEL_NAMEWIDTH-2*ACHANNEL_BUTTON_WIDTH)) {
889                                         /* toggle mute */
890                                         icu->flag ^= IPO_MUTE;
891                                 }
892                                 else {
893                                         /* select/deselect */
894                                         //select_icu_channel(act, icu, SELECT_INVERT);
895                                         
896                                         // XXX for now only
897                                         icu->flag ^= IPO_SELECT;
898                                 }
899                         }
900                         break;
901                 case ANIMTYPE_CONCHAN:
902                         {
903                                 bConstraintChannel *conchan= (bConstraintChannel *)ale->data;
904                                 
905                                 if (x >= (ACHANNEL_NAMEWIDTH-16)) {
906                                         /* toggle protection */
907                                         conchan->flag ^= CONSTRAINT_CHANNEL_PROTECTED;
908                                 }
909                                 else if ((x >= (ACHANNEL_NAMEWIDTH-32)) && (conchan->ipo)) {
910                                         /* toggle mute */
911                                         conchan->ipo->muteipo = (conchan->ipo->muteipo)? 0: 1;
912                                 }
913                                 else {
914                                         /* select/deselect */
915                                         //select_constraint_channel(act, conchan, SELECT_INVERT);
916                                         
917                                         // XXX for now only
918                                         conchan->flag ^= CONSTRAINT_CHANNEL_SELECT;
919                                 }
920                         }
921                                 break;
922                 case ANIMTYPE_GPDATABLOCK:
923                         {
924                                 bGPdata *gpd= (bGPdata *)ale->data;
925                                 
926                                 /* toggle expand */
927                                 gpd->flag ^= GP_DATA_EXPAND;
928                         }
929                                 break;
930                 case ANIMTYPE_GPLAYER:
931                         {
932 #if 0 // XXX future of this is unclear
933                                 bGPdata *gpd= (bGPdata *)ale->owner;
934                                 bGPDlayer *gpl= (bGPDlayer *)ale->data;
935                                 
936                                 if (x >= (ACHANNEL_NAMEWIDTH-16)) {
937                                         /* toggle lock */
938                                         gpl->flag ^= GP_LAYER_LOCKED;
939                                 }
940                                 else if (x >= (ACHANNEL_NAMEWIDTH-32)) {
941                                         /* toggle hide */
942                                         gpl->flag ^= GP_LAYER_HIDE;
943                                 }
944                                 else {
945                                         /* select/deselect */
946                                         //if (G.qual & LR_SHIFTKEY) {
947                                                 //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
948                                         //}
949                                         //else {
950                                                 //deselect_gpencil_layers(data, 0);
951                                                 //select_gplayer_channel(gpd, gpl, SELECT_INVERT);
952                                         //}
953                                 }
954 #endif // XXX future of this is unclear
955                         }
956                                 break;
957                 case ANIMTYPE_SHAPEKEY:
958                         /* TODO: shapekey channels cannot be selected atm... */
959                         break;
960                 default:
961                         printf("Error: Invalid channel type in mouse_anim_channels() \n");
962         }
963         
964         /* free channels */
965         BLI_freelistN(&anim_data);
966 }
967
968 /* ------------------- */
969
970 /* handle clicking */
971 static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, wmEvent *event)
972 {
973         bAnimContext ac;
974         Scene *scene;
975         ARegion *ar;
976         View2D *v2d;
977         int mval[2], channel_index;
978         short selectmode;
979         float x, y;
980         
981         
982         /* get editor data */
983         if (ANIM_animdata_get_context(C, &ac) == 0)
984                 return OPERATOR_CANCELLED;
985                 
986         /* get useful pointers from animation context data */
987         scene= ac.scene;
988         ar= ac.ar;
989         v2d= &ar->v2d;
990         
991         /* get mouse coordinates (in region coordinates) */
992         mval[0]= (event->x - ar->winrct.xmin);
993         mval[1]= (event->y - ar->winrct.ymin);
994         
995         /* select mode is either replace (deselect all, then add) or add/extend */
996         if (RNA_boolean_get(op->ptr, "extend_select"))
997                 selectmode= SELECT_INVERT;
998         else
999                 selectmode= SELECT_REPLACE;
1000         
1001         /* figure out which channel user clicked in 
1002          * Note: although channels technically start at y= ACHANNEL_FIRST, we need to adjust by half a channel's height
1003          *              so that the tops of channels get caught ok. Since ACHANNEL_FIRST is really ACHANNEL_HEIGHT, we simply use
1004          *              ACHANNEL_HEIGHT_HALF.
1005          */
1006         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
1007         UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index);
1008         
1009         /* handle mouse-click in the relevant channel then */
1010         mouse_anim_channels(&ac, x, channel_index, selectmode);
1011         
1012         /* set notifier tha things have changed */
1013         ED_area_tag_redraw(CTX_wm_area(C)); // FIXME... should be updating 'keyframes' data context or so instead!
1014         
1015         return OPERATOR_FINISHED;
1016 }
1017  
1018 void ANIM_OT_channels_mouseclick (wmOperatorType *ot)
1019 {
1020         /* identifiers */
1021         ot->name= "Mouse Click on Channels";
1022         ot->idname= "ANIM_OT_channels_mouseclick";
1023         
1024         /* api callbacks */
1025         ot->invoke= animchannels_mouseclick_invoke;
1026         ot->poll= ED_operator_areaactive;
1027         
1028         /* id-props */
1029         RNA_def_property(ot->srna, "extend_select", PROP_BOOLEAN, PROP_NONE); // SHIFTKEY
1030 }
1031
1032 /* ************************************************************************** */
1033 /* Operator Registration */
1034
1035 void ED_operatortypes_animchannels(void)
1036 {
1037         WM_operatortype_append(ANIM_OT_channels_deselectall);
1038         WM_operatortype_append(ANIM_OT_channels_borderselect);
1039         WM_operatortype_append(ANIM_OT_channels_mouseclick);
1040         
1041         WM_operatortype_append(ANIM_OT_channels_enable_setting);
1042         WM_operatortype_append(ANIM_OT_channels_disable_setting);
1043         WM_operatortype_append(ANIM_OT_channels_toggle_setting);
1044 }
1045
1046 void ED_keymap_animchannels(wmWindowManager *wm)
1047 {
1048         ListBase *keymap = WM_keymap_listbase(wm, "Animation_Channels", 0, 0);
1049         
1050         /* selection */
1051                 /* click-select */
1052                 // XXX for now, only leftmouse.... 
1053         WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, 0, 0);
1054         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_mouseclick", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend_select", 1);
1055         
1056                 /* deselect all */
1057         WM_keymap_add_item(keymap, "ANIM_OT_channels_deselectall", AKEY, KM_PRESS, 0, 0);
1058         RNA_boolean_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_deselectall", IKEY, KM_PRESS, KM_CTRL, 0)->ptr, "invert", 1);
1059         
1060                 /* borderselect */
1061         WM_keymap_add_item(keymap, "ANIM_OT_channels_borderselect", BKEY, KM_PRESS, 0, 0);
1062         
1063         /* settings */
1064         RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_toggle_setting", WKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "mode", ACHANNEL_SETFLAG_TOGGLE);
1065         RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_enable_setting", WKEY, KM_PRESS, KM_CTRL|KM_SHIFT, 0)->ptr, "mode", ACHANNEL_SETFLAG_ADD);
1066         RNA_enum_set(WM_keymap_add_item(keymap, "ANIM_OT_channels_disable_setting", WKEY, KM_PRESS, KM_ALT, 0)->ptr, "mode", ACHANNEL_SETFLAG_CLEAR);
1067 }
1068
1069 /* ************************************************************************** */