Blender V2.61 - r43446

nla_select.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version. 
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2009 Blender Foundation, Joshua Leung
00019  * All rights reserved.
00020  *
00021  * 
00022  * Contributor(s): Joshua Leung (major recode)
00023  *
00024  * ***** END GPL LICENSE BLOCK *****
00025  */
00026 
00032 #include <string.h>
00033 #include <stdio.h>
00034 
00035 #include "DNA_anim_types.h"
00036 #include "DNA_scene_types.h"
00037 
00038 #include "MEM_guardedalloc.h"
00039 
00040 #include "BLI_blenlib.h"
00041 #include "BLI_math.h"
00042 #include "BLI_rand.h"
00043 
00044 #include "BKE_nla.h"
00045 #include "BKE_context.h"
00046 #include "BKE_screen.h"
00047 
00048 #include "ED_anim_api.h"
00049 #include "ED_keyframes_edit.h"
00050 #include "ED_screen.h"
00051 
00052 #include "RNA_access.h"
00053 #include "RNA_define.h"
00054 
00055 #include "WM_api.h"
00056 #include "WM_types.h"
00057 
00058 #include "UI_view2d.h"
00059 
00060 #include "nla_intern.h" // own include
00061 
00062 /* ******************** Utilities ***************************************** */
00063 
00064 /* Convert SELECT_* flags to ACHANNEL_SETFLAG_* flags */
00065 static short selmodes_to_flagmodes (short sel)
00066 {
00067     /* convert selection modes to selection modes */
00068     switch (sel) {
00069         case SELECT_SUBTRACT:
00070             return ACHANNEL_SETFLAG_CLEAR;
00071             break;
00072             
00073         case SELECT_INVERT:
00074             return ACHANNEL_SETFLAG_INVERT;
00075             break;
00076             
00077         case SELECT_ADD:
00078         default:
00079             return ACHANNEL_SETFLAG_ADD;
00080             break;
00081     }
00082 }
00083 
00084 
00085 /* ******************** Deselect All Operator ***************************** */
00086 /* This operator works in one of three ways:
00087  *  1) (de)select all (AKEY) - test if select all or deselect all
00088  *  2) invert all (CTRL-IKEY) - invert selection of all keyframes
00089  *  3) (de)select all - no testing is done; only for use internal tools as normal function...
00090  */
00091 
00092 enum {
00093     DESELECT_STRIPS_NOTEST = 0,
00094     DESELECT_STRIPS_TEST,
00095     DESELECT_STRIPS_CLEARACTIVE,
00096 } /*eDeselectNlaStrips*/;
00097  
00098 /* Deselects strips in the NLA Editor
00099  *  - This is called by the deselect all operator, as well as other ones!
00100  *
00101  *  - test: check if select or deselect all (1) or clear all active (2)
00102  *  - sel: how to select keyframes 
00103  *      0 = deselect
00104  *      1 = select
00105  *      2 = invert
00106  */
00107 static void deselect_nla_strips (bAnimContext *ac, short test, short sel)
00108 {
00109     ListBase anim_data = {NULL, NULL};
00110     bAnimListElem *ale;
00111     int filter;
00112     short smode;
00113     
00114     /* determine type-based settings */
00115     // FIXME: double check whether ANIMFILTER_LIST_VISIBLE is needed!
00116     filter= (ANIMFILTER_DATA_VISIBLE);
00117     
00118     /* filter data */
00119     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00120     
00121     /* See if we should be selecting or deselecting */
00122     if (test == DESELECT_STRIPS_TEST) {
00123         for (ale= anim_data.first; ale; ale= ale->next) {
00124             NlaTrack *nlt= (NlaTrack *)ale->data;
00125             NlaStrip *strip;
00126             
00127             /* if any strip is selected, break out, since we should now be deselecting */
00128             for (strip= nlt->strips.first; strip; strip= strip->next) {
00129                 if (strip->flag & NLASTRIP_FLAG_SELECT) {
00130                     sel= SELECT_SUBTRACT;
00131                     break;
00132                 }
00133             }
00134             
00135             if (sel == SELECT_SUBTRACT)
00136                 break;
00137         }
00138     }
00139     
00140     /* convert selection modes to selection modes */
00141     smode= selmodes_to_flagmodes(sel);
00142     
00143     /* Now set the flags */
00144     for (ale= anim_data.first; ale; ale= ale->next) {
00145         NlaTrack *nlt= (NlaTrack *)ale->data;
00146         NlaStrip *strip;
00147         
00148         /* apply same selection to all strips */
00149         for (strip= nlt->strips.first; strip; strip= strip->next) {
00150             /* set selection */
00151             if (test != DESELECT_STRIPS_CLEARACTIVE)
00152                 ACHANNEL_SET_FLAG(strip, smode, NLASTRIP_FLAG_SELECT);
00153             
00154             /* clear active flag */
00155             // TODO: for clear active, do we want to limit this to only doing this on a certain set of tracks though?
00156             strip->flag &= ~NLASTRIP_FLAG_ACTIVE;
00157         }
00158     }
00159     
00160     /* Cleanup */
00161     BLI_freelistN(&anim_data);
00162 }
00163 
00164 /* ------------------- */
00165 
00166 static int nlaedit_deselectall_exec(bContext *C, wmOperator *op)
00167 {
00168     bAnimContext ac;
00169     
00170     /* get editor data */
00171     if (ANIM_animdata_get_context(C, &ac) == 0)
00172         return OPERATOR_CANCELLED;
00173         
00174     /* 'standard' behaviour - check if selected, then apply relevant selection */
00175     if (RNA_boolean_get(op->ptr, "invert"))
00176         deselect_nla_strips(&ac, DESELECT_STRIPS_NOTEST, SELECT_INVERT);
00177     else
00178         deselect_nla_strips(&ac, DESELECT_STRIPS_TEST, SELECT_ADD);
00179     
00180     /* set notifier that things have changed */
00181     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_SELECTED, NULL);
00182     
00183     return OPERATOR_FINISHED;
00184 }
00185  
00186 void NLA_OT_select_all_toggle (wmOperatorType *ot)
00187 {
00188     /* identifiers */
00189     ot->name= "Select or Deselect All";
00190     ot->idname= "NLA_OT_select_all_toggle";
00191     ot->description= "(De)Select all NLA-Strips";
00192     
00193     /* api callbacks */
00194     ot->exec= nlaedit_deselectall_exec;
00195     ot->poll= nlaop_poll_tweakmode_off;
00196     
00197     /* flags */
00198     ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
00199     
00200     /* props */
00201     RNA_def_boolean(ot->srna, "invert", 0, "Invert", "");
00202 }
00203 
00204 /* ******************** Border Select Operator **************************** */
00205 /* This operator currently works in one of three ways:
00206  *  -> BKEY     - 1) all strips within region are selected (NLAEDIT_BORDERSEL_ALLSTRIPS)
00207  *  -> ALT-BKEY - depending on which axis of the region was larger...
00208  *      -> 2) x-axis, so select all frames within frame range (NLAEDIT_BORDERSEL_FRAMERANGE)
00209  *      -> 3) y-axis, so select all frames within channels that region included (NLAEDIT_BORDERSEL_CHANNELS)
00210  */
00211 
00212 /* defines for borderselect mode */
00213 enum {
00214     NLA_BORDERSEL_ALLSTRIPS = 0,
00215     NLA_BORDERSEL_FRAMERANGE,
00216     NLA_BORDERSEL_CHANNELS,
00217 } /* eNLAEDIT_BorderSelect_Mode */;
00218 
00219 
00220 static void borderselect_nla_strips (bAnimContext *ac, rcti rect, short mode, short selectmode)
00221 {
00222     ListBase anim_data = {NULL, NULL};
00223     bAnimListElem *ale;
00224     int filter;
00225     
00226     SpaceNla *snla = (SpaceNla *)ac->sl;
00227     View2D *v2d= &ac->ar->v2d;
00228     rctf rectf;
00229     float ymin /* =(float)(-NLACHANNEL_HEIGHT(snla)) */ /* UNUSED */, ymax=0;
00230     
00231     /* convert border-region to view coordinates */
00232     UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin+2, &rectf.xmin, &rectf.ymin);
00233     UI_view2d_region_to_view(v2d, rect.xmax, rect.ymax-2, &rectf.xmax, &rectf.ymax);
00234     
00235     /* filter data */
00236     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
00237     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00238     
00239     /* convert selection modes to selection modes */
00240     selectmode= selmodes_to_flagmodes(selectmode);
00241     
00242     /* loop over data, doing border select */
00243     for (ale= anim_data.first; ale; ale= ale->next) {
00244         ymin= ymax - NLACHANNEL_STEP(snla);
00245         
00246         /* perform vertical suitability check (if applicable) */
00247         if ( (mode == NLA_BORDERSEL_FRAMERANGE) ||
00248             !((ymax < rectf.ymin) || (ymin > rectf.ymax)) ) 
00249         {
00250             /* loop over data selecting (only if NLA-Track) */
00251             if (ale->type == ANIMTYPE_NLATRACK) {
00252                 NlaTrack *nlt= (NlaTrack *)ale->data;
00253                 NlaStrip *strip;
00254                 
00255                 /* only select strips if they fall within the required ranges (if applicable) */
00256                 for (strip= nlt->strips.first; strip; strip= strip->next) {
00257                     if ( (mode == NLA_BORDERSEL_CHANNELS) || 
00258                           BKE_nlastrip_within_bounds(strip, rectf.xmin, rectf.xmax) ) 
00259                     {
00260                         /* set selection */
00261                         ACHANNEL_SET_FLAG(strip, selectmode, NLASTRIP_FLAG_SELECT);
00262                         
00263                         /* clear active flag */
00264                         strip->flag &= ~NLASTRIP_FLAG_ACTIVE;
00265                     }
00266                 }
00267             }
00268         }
00269         
00270         /* set minimum extent to be the maximum of the next channel */
00271         ymax= ymin;
00272     }
00273     
00274     /* cleanup */
00275     BLI_freelistN(&anim_data);
00276 }
00277 
00278 /* ------------------- */
00279 
00280 static int nlaedit_borderselect_exec(bContext *C, wmOperator *op)
00281 {
00282     bAnimContext ac;
00283     rcti rect;
00284     short mode=0, selectmode=0;
00285     int extend;
00286     
00287     /* get editor data */
00288     if (ANIM_animdata_get_context(C, &ac) == 0)
00289         return OPERATOR_CANCELLED;
00290 
00291     /* clear all selection if not extending selection */
00292     extend= RNA_boolean_get(op->ptr, "extend");
00293     if (!extend)
00294         deselect_nla_strips(&ac, DESELECT_STRIPS_TEST, SELECT_SUBTRACT);
00295 
00296     /* get settings from operator */
00297     rect.xmin= RNA_int_get(op->ptr, "xmin");
00298     rect.ymin= RNA_int_get(op->ptr, "ymin");
00299     rect.xmax= RNA_int_get(op->ptr, "xmax");
00300     rect.ymax= RNA_int_get(op->ptr, "ymax");
00301         
00302     if (RNA_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_SELECT)
00303         selectmode = SELECT_ADD;
00304     else
00305         selectmode = SELECT_SUBTRACT;
00306     
00307     /* selection 'mode' depends on whether borderselect region only matters on one axis */
00308     if (RNA_boolean_get(op->ptr, "axis_range")) {
00309         /* mode depends on which axis of the range is larger to determine which axis to use 
00310          *  - checking this in region-space is fine, as it's fundamentally still going to be a different rect size
00311          *  - the frame-range select option is favoured over the channel one (x over y), as frame-range one is often
00312          *    used for tweaking timing when "blocking", while channels is not that useful...
00313          */
00314         if ((rect.xmax - rect.xmin) >= (rect.ymax - rect.ymin))
00315             mode= NLA_BORDERSEL_FRAMERANGE;
00316         else
00317             mode= NLA_BORDERSEL_CHANNELS;
00318     }
00319     else 
00320         mode= NLA_BORDERSEL_ALLSTRIPS;
00321     
00322     /* apply borderselect action */
00323     borderselect_nla_strips(&ac, rect, mode, selectmode);
00324     
00325     /* set notifier that things have changed */
00326     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_SELECTED, NULL);
00327     
00328     return OPERATOR_FINISHED;
00329 } 
00330 
00331 void NLA_OT_select_border(wmOperatorType *ot)
00332 {
00333     /* identifiers */
00334     ot->name= "Border Select";
00335     ot->idname= "NLA_OT_select_border";
00336     ot->description= "Use box selection to grab NLA-Strips";
00337     
00338     /* api callbacks */
00339     ot->invoke= WM_border_select_invoke;
00340     ot->exec= nlaedit_borderselect_exec;
00341     ot->modal= WM_border_select_modal;
00342     ot->cancel= WM_border_select_cancel;
00343     
00344     ot->poll= nlaop_poll_tweakmode_off;
00345     
00346     /* flags */
00347     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00348     
00349     /* rna */
00350     WM_operator_properties_gesture_border(ot, 1);
00351     
00352     RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", "");
00353 }
00354 
00355 /* ******************** Select Left/Right Operator ************************* */
00356 /* Select keyframes left/right of the current frame indicator */
00357 
00358 /* defines for left-right select tool */
00359 static EnumPropertyItem prop_nlaedit_leftright_select_types[] = {
00360     {NLAEDIT_LRSEL_TEST, "CHECK", 0, "Check if Select Left or Right", ""},
00361     {NLAEDIT_LRSEL_LEFT, "LEFT", 0, "Before current frame", ""},
00362     {NLAEDIT_LRSEL_RIGHT, "RIGHT", 0, "After current frame", ""},
00363     {0, NULL, 0, NULL, NULL}
00364 };
00365 
00366 /* ------------------- */
00367 
00368 static void nlaedit_select_leftright (bContext *C, bAnimContext *ac, short leftright, short select_mode)
00369 {
00370     ListBase anim_data = {NULL, NULL};
00371     bAnimListElem *ale;
00372     int filter;
00373     
00374     Scene *scene= ac->scene;
00375     float xmin, xmax;
00376     
00377     /* if currently in tweakmode, exit tweakmode first */
00378     if (scene->flag & SCE_NLA_EDIT_ON)
00379         WM_operator_name_call(C, "NLA_OT_tweakmode_exit", WM_OP_EXEC_DEFAULT, NULL);
00380     
00381     /* if select mode is replace, deselect all keyframes (and channels) first */
00382     if (select_mode==SELECT_REPLACE) {
00383         select_mode= SELECT_ADD;
00384         
00385         /* - deselect all other keyframes, so that just the newly selected remain
00386          * - channels aren't deselected, since we don't re-select any as a consequence
00387          */
00388         deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
00389     }
00390     
00391     /* get range, and get the right flag-setting mode */
00392     if (leftright == NLAEDIT_LRSEL_LEFT) {
00393         xmin = MINAFRAMEF;
00394         xmax = (float)(CFRA + 0.1f);
00395     } 
00396     else {
00397         xmin = (float)(CFRA - 0.1f);
00398         xmax = MAXFRAMEF;
00399     }
00400     
00401     select_mode= selmodes_to_flagmodes(select_mode);
00402     
00403     
00404     /* filter data */
00405     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE);
00406     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00407     
00408     /* select strips on the side where most data occurs */
00409     for (ale= anim_data.first; ale; ale= ale->next) {
00410         NlaTrack *nlt= (NlaTrack *)ale->data;
00411         NlaStrip *strip;
00412         
00413         /* check each strip to see if it is appropriate */
00414         for (strip= nlt->strips.first; strip; strip= strip->next) {
00415             if (BKE_nlastrip_within_bounds(strip, xmin, xmax)) {
00416                 ACHANNEL_SET_FLAG(strip, select_mode, NLASTRIP_FLAG_SELECT);
00417             }
00418         }
00419     }
00420     
00421     /* Cleanup */
00422     BLI_freelistN(&anim_data);
00423 }
00424 
00425 /* ------------------- */
00426 
00427 static int nlaedit_select_leftright_exec (bContext *C, wmOperator *op)
00428 {
00429     bAnimContext ac;
00430     short leftright = RNA_enum_get(op->ptr, "mode");
00431     short selectmode;
00432     
00433     /* get editor data */
00434     if (ANIM_animdata_get_context(C, &ac) == 0)
00435         return OPERATOR_CANCELLED;
00436     
00437     /* select mode is either replace (deselect all, then add) or add/extend */
00438     if (RNA_boolean_get(op->ptr, "extend"))
00439         selectmode= SELECT_INVERT;
00440     else
00441         selectmode= SELECT_REPLACE;
00442         
00443     /* if "test" mode is set, we don't have any info to set this with */
00444     if (leftright == NLAEDIT_LRSEL_TEST)
00445         return OPERATOR_CANCELLED;
00446     
00447     /* do the selecting now */
00448     nlaedit_select_leftright(C, &ac, leftright, selectmode);
00449     
00450     /* set notifier that keyframe selection (and channels too) have changed */
00451     WM_event_add_notifier(C, NC_ANIMATION|ND_KEYFRAME|ND_ANIMCHAN|NA_SELECTED, NULL);
00452     
00453     return OPERATOR_FINISHED;
00454 }
00455 
00456 static int nlaedit_select_leftright_invoke (bContext *C, wmOperator *op, wmEvent *event)
00457 {
00458     bAnimContext ac;
00459     short leftright = RNA_enum_get(op->ptr, "mode");
00460     
00461     /* get editor data */
00462     if (ANIM_animdata_get_context(C, &ac) == 0)
00463         return OPERATOR_CANCELLED;
00464         
00465     /* handle mode-based testing */
00466     if (leftright == NLAEDIT_LRSEL_TEST) {
00467         Scene *scene= ac.scene;
00468         ARegion *ar= ac.ar;
00469         View2D *v2d= &ar->v2d;
00470         float x;
00471         
00472         /* determine which side of the current frame mouse is on */
00473         UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, NULL);
00474         if (x < CFRA)
00475             RNA_int_set(op->ptr, "mode", NLAEDIT_LRSEL_LEFT);
00476         else    
00477             RNA_int_set(op->ptr, "mode", NLAEDIT_LRSEL_RIGHT);
00478     }
00479     
00480     /* perform selection */
00481     return nlaedit_select_leftright_exec(C, op);
00482 }
00483 
00484 void NLA_OT_select_leftright (wmOperatorType *ot)
00485 {
00486     /* identifiers */
00487     ot->name= "Select Left/Right";
00488     ot->idname= "NLA_OT_select_leftright";
00489     ot->description= "Select strips to the left or the right of the current frame";
00490     
00491     /* api callbacks  */
00492     ot->invoke= nlaedit_select_leftright_invoke;
00493     ot->exec= nlaedit_select_leftright_exec;
00494     ot->poll= ED_operator_nla_active;
00495     
00496     /* flags */
00497     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00498     
00499     /* id-props */
00500     ot->prop= RNA_def_enum(ot->srna, "mode", prop_nlaedit_leftright_select_types, NLAEDIT_LRSEL_TEST, "Mode", "");
00501     RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
00502 }
00503 
00504 
00505 /* ******************** Mouse-Click Select Operator *********************** */
00506 
00507 /* select strip directly under mouse */
00508 static void mouse_nla_strips (bContext *C, bAnimContext *ac, const int mval[2], short select_mode)
00509 {
00510     ListBase anim_data = {NULL, NULL};
00511     bAnimListElem *ale = NULL;
00512     int filter;
00513     
00514     SpaceNla *snla = (SpaceNla *)ac->sl;
00515     View2D *v2d= &ac->ar->v2d;
00516     Scene *scene= ac->scene;
00517     NlaStrip *strip = NULL;
00518     int channel_index;
00519     float xmin, xmax, dummy;
00520     float x, y;
00521     
00522     
00523     /* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */
00524     UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
00525     UI_view2d_listview_view_to_cell(v2d, 0, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index);
00526     
00527     /* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click 
00528      * (that is the size of keyframe icons, so user should be expecting similar tolerances) 
00529      */
00530     UI_view2d_region_to_view(v2d, mval[0]-7, mval[1], &xmin, &dummy);
00531     UI_view2d_region_to_view(v2d, mval[0]+7, mval[1], &xmax, &dummy);
00532     
00533     /* filter data */
00534     filter= (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS);
00535     ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype);
00536     
00537     /* try to get channel */
00538     ale= BLI_findlink(&anim_data, channel_index);
00539     if (ale == NULL) {
00540         /* channel not found */
00541         printf("Error: animation channel (index = %d) not found in mouse_nla_strips() \n", channel_index);
00542         BLI_freelistN(&anim_data);
00543         return;
00544     }
00545     else {
00546         /* found some channel - we only really should do somethign when its an Nla-Track */
00547         if (ale->type == ANIMTYPE_NLATRACK) {
00548             NlaTrack *nlt= (NlaTrack *)ale->data;
00549             
00550             /* loop over NLA-strips in this track, trying to find one which occurs in the necessary bounds */
00551             for (strip= nlt->strips.first; strip; strip= strip->next) {
00552                 if (BKE_nlastrip_within_bounds(strip, xmin, xmax))
00553                     break;
00554             }
00555         }
00556         
00557         /* remove active channel from list of channels for separate treatment (since it's needed later on) */
00558         BLI_remlink(&anim_data, ale);
00559         
00560         /* free list of channels, since it's not used anymore */
00561         BLI_freelistN(&anim_data);
00562     }
00563     
00564     /* if currently in tweakmode, exit tweakmode before changing selection states
00565      * now that we've found our target...
00566      */
00567     if (scene->flag & SCE_NLA_EDIT_ON)
00568         WM_operator_name_call(C, "NLA_OT_tweakmode_exit", WM_OP_EXEC_DEFAULT, NULL);
00569     
00570     /* for replacing selection, firstly need to clear existing selection */
00571     if (select_mode == SELECT_REPLACE) {
00572         /* reset selection mode for next steps */
00573         select_mode = SELECT_ADD;
00574         
00575         /* deselect all strips */
00576         deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
00577         
00578         /* deselect all other channels first */
00579         ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, 0, ACHANNEL_SETFLAG_CLEAR);
00580         
00581         /* Highlight NLA-Track */
00582         if (ale->type == ANIMTYPE_NLATRACK) {   
00583             NlaTrack *nlt= (NlaTrack *)ale->data;
00584             
00585             nlt->flag |= NLATRACK_SELECTED;
00586             ANIM_set_active_channel(ac, ac->data, ac->datatype, filter, nlt, ANIMTYPE_NLATRACK);
00587         }
00588     }
00589     
00590     /* only select strip if we clicked on a valid channel and hit something */
00591     if (ale) {
00592         /* select the strip accordingly (if a matching one was found) */
00593         if (strip) {
00594             select_mode= selmodes_to_flagmodes(select_mode);
00595             ACHANNEL_SET_FLAG(strip, select_mode, NLASTRIP_FLAG_SELECT);
00596             
00597             /* if we selected it, we can make it active too
00598              *  - we always need to clear the active strip flag though... 
00599              */
00600             deselect_nla_strips(ac, DESELECT_STRIPS_CLEARACTIVE, 0);
00601             if (strip->flag & NLASTRIP_FLAG_SELECT)
00602                 strip->flag |= NLASTRIP_FLAG_ACTIVE;
00603         }
00604         
00605         /* free this channel */
00606         MEM_freeN(ale);
00607     }
00608 }
00609 
00610 /* ------------------- */
00611 
00612 /* handle clicking */
00613 static int nlaedit_clickselect_invoke(bContext *C, wmOperator *op, wmEvent *event)
00614 {
00615     bAnimContext ac;
00616     /* Scene *scene; */ /* UNUSED */
00617     /* ARegion *ar; */ /* UNUSED */
00618     // View2D *v2d; /*UNUSED*/
00619     short selectmode;
00620 
00621     /* get editor data */
00622     if (ANIM_animdata_get_context(C, &ac) == 0)
00623         return OPERATOR_CANCELLED;
00624         
00625     /* get useful pointers from animation context data */
00626     /* scene= ac.scene; */ /* UNUSED */
00627     /* ar= ac.ar; */ /* UNUSED */
00628     // v2d= &ar->v2d;
00629 
00630     /* select mode is either replace (deselect all, then add) or add/extend */
00631     if (RNA_boolean_get(op->ptr, "extend"))
00632         selectmode= SELECT_INVERT;
00633     else
00634         selectmode= SELECT_REPLACE;
00635         
00636     /* select strips based upon mouse position */
00637     mouse_nla_strips(C, &ac, event->mval, selectmode);
00638     
00639     /* set notifier that things have changed */
00640     WM_event_add_notifier(C, NC_ANIMATION|ND_NLA|NA_SELECTED, NULL);
00641     
00642     /* for tweak grab to work */
00643     return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
00644 }
00645  
00646 void NLA_OT_click_select (wmOperatorType *ot)
00647 {
00648     /* identifiers */
00649     ot->name= "Mouse Select";
00650     ot->idname= "NLA_OT_click_select";
00651     ot->description= "Handle clicks to select NLA Strips";
00652     
00653     /* api callbacks - absolutely no exec() this yet... */
00654     ot->invoke= nlaedit_clickselect_invoke;
00655     ot->poll= ED_operator_nla_active;
00656     
00657     /* flags */
00658     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00659     
00660     /* id-props */
00661     RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", ""); // SHIFTKEY
00662 }
00663 
00664 /* *********************************************** */