Blender V2.61 - r43446

sequencer_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) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Blender Foundation, 2003-2009, Campbell Barton
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00031 #include <stdlib.h>
00032 #include <math.h>
00033 #include <string.h>
00034 
00035 #ifndef WIN32
00036 #include <unistd.h>
00037 #else
00038 #include <io.h>
00039 #endif
00040 #include <sys/types.h>
00041 
00042 #include "BLI_blenlib.h"
00043 #include "BLI_math.h"
00044 #include "BLI_utildefines.h"
00045 
00046 #include "DNA_scene_types.h"
00047 
00048 #include "BKE_context.h"
00049 #include "BKE_report.h"
00050 #include "BKE_sequencer.h"
00051 
00052 #include "WM_api.h"
00053 #include "WM_types.h"
00054 
00055 #include "RNA_define.h"
00056 
00057 /* for menu/popup icons etc etc*/
00058 
00059 #include "ED_types.h"
00060 #include "ED_screen.h"
00061 
00062 #include "UI_view2d.h"
00063 
00064 /* own include */
00065 #include "sequencer_intern.h"
00066 static void *find_nearest_marker(int UNUSED(d1), int UNUSED(d2)) {return NULL;}
00067     
00068 static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */
00069 {
00070     Sequence *neighbor;
00071     
00072     neighbor=find_neighboring_sequence(scene, test, SEQ_SIDE_LEFT, -1);
00073     if (neighbor) {
00074         neighbor->flag |= SELECT;
00075         recurs_sel_seq(neighbor);
00076         neighbor->flag |= SEQ_RIGHTSEL;
00077     }
00078     neighbor=find_neighboring_sequence(scene, test, SEQ_SIDE_RIGHT, -1);
00079     if (neighbor) {
00080         neighbor->flag |= SELECT;
00081         recurs_sel_seq(neighbor);
00082         neighbor->flag |= SEQ_LEFTSEL;
00083     }
00084     test->flag |= SELECT;
00085 }
00086 
00087 /* used for mouse selection and for SEQUENCER_OT_select_active_side() */
00088 static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame)
00089 {
00090     Sequence *seq;
00091 
00092     for(seq= seqbase->first; seq; seq=seq->next) {
00093         if(channel==seq->machine) {
00094             switch(sel_side) {
00095             case SEQ_SIDE_LEFT:
00096                 if (frame > (seq->startdisp)) {
00097                     seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL);
00098                     seq->flag |= SELECT;
00099                 }
00100                 break;
00101             case SEQ_SIDE_RIGHT:
00102                 if (frame < (seq->startdisp)) {
00103                     seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL);
00104                     seq->flag |= SELECT;
00105                 }
00106                 break;
00107             case SEQ_SIDE_BOTH:
00108                 seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL);
00109                 break;
00110             }
00111         }
00112     }
00113 }
00114 
00115 /* used for mouse selection and for SEQUENCER_OT_select_active_side() */
00116 static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
00117 {
00118     Sequence *seq;
00119 
00120     for(seq= seqbase->first; seq; seq=seq->next) {
00121         if(seq_link->machine != seq->machine) {
00122             int left_match = (seq->startdisp == seq_link->startdisp) ? 1:0;
00123             int right_match = (seq->enddisp == seq_link->enddisp) ? 1:0;
00124 
00125             if(left_match && right_match) {
00126                 /* a direct match, copy the selection settinhs */
00127                 seq->flag &= ~(SELECT|SEQ_LEFTSEL|SEQ_RIGHTSEL);
00128                 seq->flag |= seq_link->flag & (SELECT|SEQ_LEFTSEL|SEQ_RIGHTSEL);
00129 
00130                 recurs_sel_seq(seq);
00131             }
00132             else if(seq_link->flag & SELECT && (left_match || right_match)) {
00133 
00134                 /* clear for reselection */
00135                 seq->flag &= ~(SEQ_LEFTSEL|SEQ_RIGHTSEL);
00136 
00137                 if(left_match && seq_link->flag & SEQ_LEFTSEL)
00138                     seq->flag |= SELECT|SEQ_LEFTSEL;
00139 
00140                 if(right_match && seq_link->flag & SEQ_RIGHTSEL)
00141                     seq->flag |= SELECT|SEQ_RIGHTSEL;
00142 
00143                 recurs_sel_seq(seq);
00144             }
00145         }
00146     }
00147 }
00148 
00149 #if 0 // BRING BACK
00150 void select_surround_from_last(Scene *scene)
00151 {
00152     Sequence *seq=get_last_seq(scene);
00153     
00154     if (seq==NULL)
00155         return;
00156     
00157     select_surrounding_handles(scene, seq);
00158 }
00159 #endif
00160 
00161 
00162 static void UNUSED_FUNCTION(select_single_seq)(Scene *scene, Sequence *seq, int deselect_all) /* BRING BACK */
00163 {
00164     Editing *ed= seq_give_editing(scene, FALSE);
00165     
00166     if(deselect_all)
00167         deselect_all_seq(scene);
00168     seq_active_set(scene, seq);
00169 
00170     if((seq->type==SEQ_IMAGE) || (seq->type==SEQ_MOVIE)) {
00171         if(seq->strip)
00172             BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
00173     }
00174     else if(seq->type==SEQ_SOUND) {
00175         if(seq->strip)
00176             BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
00177     }
00178     seq->flag|= SELECT;
00179     recurs_sel_seq(seq);
00180 }
00181 
00182 #if 0
00183 static void select_neighbor_from_last(Scene *scene, int lr)
00184 {
00185     Sequence *seq= seq_active_get(scene);
00186     Sequence *neighbor;
00187     int change = 0;
00188     if (seq) {
00189         neighbor=find_neighboring_sequence(scene, seq, lr, -1);
00190         if (neighbor) {
00191             switch (lr) {
00192             case SEQ_SIDE_LEFT:
00193                 neighbor->flag |= SELECT;
00194                 recurs_sel_seq(neighbor);
00195                 neighbor->flag |= SEQ_RIGHTSEL;
00196                 seq->flag |= SEQ_LEFTSEL;
00197                 break;
00198             case SEQ_SIDE_RIGHT:
00199                 neighbor->flag |= SELECT;
00200                 recurs_sel_seq(neighbor);
00201                 neighbor->flag |= SEQ_LEFTSEL;
00202                 seq->flag |= SEQ_RIGHTSEL;
00203                 break;
00204             }
00205         seq->flag |= SELECT;
00206         change = 1;
00207         }
00208     }
00209     if (change) {
00210     }
00211 }
00212 #endif
00213 
00214 /* (de)select operator */
00215 static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
00216 {
00217     int action = RNA_enum_get(op->ptr, "action");
00218 
00219     Scene *scene = CTX_data_scene(C);
00220     Editing *ed = seq_give_editing(scene, FALSE);
00221     Sequence *seq;
00222 
00223     if (action == SEL_TOGGLE) {
00224         action = SEL_SELECT;
00225         for (seq = ed->seqbasep->first; seq; seq = seq->next) {
00226             if (seq->flag & SEQ_ALLSEL) {
00227                 action = SEL_DESELECT;
00228                 break;
00229             }
00230         }
00231     }
00232 
00233     for (seq = ed->seqbasep->first; seq; seq = seq->next) {
00234         switch (action) {
00235             case SEL_SELECT:
00236                 seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
00237                 seq->flag |= SELECT;
00238                 break;
00239             case SEL_DESELECT:
00240                 seq->flag &= ~SEQ_ALLSEL;
00241                 break;
00242             case SEL_INVERT:
00243                 if (seq->flag & SEQ_ALLSEL) {
00244                     seq->flag &= ~SEQ_ALLSEL;
00245                 }
00246                 else {
00247                     seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
00248                     seq->flag |= SELECT;
00249                 }
00250                 break;
00251         }
00252     }
00253 
00254     WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
00255 
00256     return OPERATOR_FINISHED;
00257 }
00258 
00259 void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
00260 {
00261     /* identifiers */
00262     ot->name= "Select or Deselect All";
00263     ot->idname= "SEQUENCER_OT_select_all";
00264     ot->description="Select or deselect all strips";
00265     
00266     /* api callbacks */
00267     ot->exec= sequencer_de_select_all_exec;
00268     ot->poll= sequencer_edit_poll;
00269     
00270     /* flags */
00271     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00272 
00273     WM_operator_properties_select_all(ot);
00274 }
00275 
00276 
00277 /* (de)select operator */
00278 static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
00279 {
00280     Scene *scene= CTX_data_scene(C);
00281     Editing *ed= seq_give_editing(scene, FALSE);
00282     Sequence *seq;
00283 
00284     for(seq= ed->seqbasep->first; seq; seq=seq->next) {
00285         if (seq->flag & SELECT) {
00286             seq->flag &= ~SEQ_ALLSEL;
00287         }
00288         else {
00289             seq->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
00290             seq->flag |= SELECT;
00291         }
00292     }
00293 
00294     WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
00295     
00296     return OPERATOR_FINISHED;
00297 }
00298 
00299 void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
00300 {
00301     /* identifiers */
00302     ot->name= "Select Inverse";
00303     ot->idname= "SEQUENCER_OT_select_inverse";
00304     ot->description="Select unselected strips";
00305     
00306     /* api callbacks */
00307     ot->exec= sequencer_select_inverse_exec;
00308     ot->poll= sequencer_edit_poll;
00309     
00310     /* flags */
00311     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00312 }
00313 
00314 static int sequencer_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
00315 {
00316     View2D *v2d= UI_view2d_fromcontext(C);
00317     Scene *scene= CTX_data_scene(C);
00318     Editing *ed= seq_give_editing(scene, FALSE);
00319     short extend= RNA_boolean_get(op->ptr, "extend");
00320     short linked_handle= RNA_boolean_get(op->ptr, "linked_handle");
00321     short left_right= RNA_boolean_get(op->ptr, "left_right");
00322     short linked_time= RNA_boolean_get(op->ptr, "linked_time");
00323     
00324     Sequence *seq,*neighbor, *act_orig;
00325     int hand,sel_side;
00326     TimeMarker *marker;
00327 
00328     if(ed==NULL)
00329         return OPERATOR_CANCELLED;
00330     
00331     marker=find_nearest_marker(SCE_MARKERS, 1); //XXX - dummy function for now
00332     
00333     seq= find_nearest_seq(scene, v2d, &hand, event->mval);
00334 
00335     // XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip
00336     if(seq && linked_time && left_right)
00337         left_right= FALSE;
00338 
00339 
00340     if (marker) {
00341         int oldflag;
00342         /* select timeline marker */
00343         if (extend) {
00344             oldflag= marker->flag;
00345             if (oldflag & SELECT)
00346                 marker->flag &= ~SELECT;
00347             else
00348                 marker->flag |= SELECT;
00349         }
00350         else {
00351             /* deselect_markers(0, 0); */ /* XXX, in 2.4x, seq selection used to deselect all, need to re-thnik this for 2.5 */
00352             marker->flag |= SELECT;             
00353         }
00354         
00355     } else if (left_right) {
00356         /* use different logic for this */
00357         float x;
00358         deselect_all_seq(scene);
00359         UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, NULL);
00360 
00361         SEQP_BEGIN(ed, seq) {
00362             if (x < CFRA) {
00363                 if(seq->enddisp < CFRA) {
00364                     seq->flag |= SELECT;
00365                     recurs_sel_seq(seq);
00366                 }
00367             }
00368             else {
00369                 if(seq->startdisp > CFRA) {
00370                     seq->flag |= SELECT;
00371                     recurs_sel_seq(seq);
00372                 }
00373             }
00374         }
00375         SEQ_END
00376         
00377         {
00378             SpaceSeq *sseq= CTX_wm_space_seq(C);
00379             if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
00380                 TimeMarker *tmarker;
00381 
00382                 for (tmarker= scene->markers.first; tmarker; tmarker= tmarker->next) {
00383                     if( ((x < CFRA) && tmarker->frame < CFRA) ||
00384                         ((x >= CFRA) && tmarker->frame >= CFRA)
00385                     ) {
00386                         tmarker->flag |= SELECT;
00387                     }
00388                     else {
00389                         tmarker->flag &= ~SELECT;
00390                     }
00391                 }
00392             }
00393         }
00394     } else {
00395         // seq= find_nearest_seq(scene, v2d, &hand, mval);
00396 
00397         act_orig= ed->act_seq;
00398 
00399         if(extend == 0 && linked_handle==0)
00400             deselect_all_seq(scene);
00401     
00402         if(seq) {
00403             seq_active_set(scene, seq);
00404     
00405             if ((seq->type == SEQ_IMAGE) || (seq->type == SEQ_MOVIE)) {
00406                 if(seq->strip) {
00407                     BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
00408                 }
00409             } else
00410             if (seq->type == SEQ_SOUND) {
00411                 if(seq->strip) {
00412                     BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
00413                 }
00414             }
00415     
00416             if(extend && (seq->flag & SELECT) && ed->act_seq == act_orig ) {
00417                 switch(hand) {
00418                 case SEQ_SIDE_NONE:
00419                     if (linked_handle==0)
00420                         seq->flag &= ~SEQ_ALLSEL;
00421                     break;
00422                 case SEQ_SIDE_LEFT:
00423                     seq->flag ^= SEQ_LEFTSEL;
00424                     break;
00425                 case SEQ_SIDE_RIGHT:
00426                     seq->flag ^= SEQ_RIGHTSEL;
00427                     break;
00428                 }
00429             }
00430             else {
00431                 seq->flag |= SELECT;
00432                 if(hand==SEQ_SIDE_LEFT)     seq->flag |= SEQ_LEFTSEL;
00433                 if(hand==SEQ_SIDE_RIGHT)    seq->flag |= SEQ_RIGHTSEL;
00434             }
00435             
00436             /* On Alt selection, select the strip and bordering handles */
00437             if (linked_handle && !ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
00438                 if(extend==0) deselect_all_seq(scene);
00439                 seq->flag |= SELECT;
00440                 select_surrounding_handles(scene, seq);
00441             }
00442             else if (linked_handle && ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT) && (seq->flag & SELECT)) {
00443                 /*
00444                  * First click selects adjacent handles on that side.
00445                  * Second click selects all strips in that direction.
00446                  * If there are no adjacent strips, it just selects all in that direction.
00447                  */
00448                 sel_side= hand;
00449                 neighbor=find_neighboring_sequence(scene, seq, sel_side, -1);
00450                 if (neighbor) {
00451                     switch (sel_side) {
00452                     case SEQ_SIDE_LEFT:
00453                         if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
00454                             if(extend==0) deselect_all_seq(scene);
00455                             seq->flag |= SELECT;
00456                             
00457                             select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
00458                         } else {
00459                             if(extend==0) deselect_all_seq(scene);
00460                             seq->flag |= SELECT;
00461 
00462                             neighbor->flag |= SELECT;
00463                             recurs_sel_seq(neighbor);
00464                             neighbor->flag |= SEQ_RIGHTSEL;
00465                             seq->flag |= SEQ_LEFTSEL;
00466                         }
00467                         break;
00468                     case SEQ_SIDE_RIGHT:
00469                         if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
00470                             if(extend==0) deselect_all_seq(scene);
00471                             seq->flag |= SELECT;
00472 
00473                             select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
00474                         } else {
00475                             if(extend==0) deselect_all_seq(scene);
00476                             seq->flag |= SELECT;
00477 
00478                             neighbor->flag |= SELECT;
00479                             recurs_sel_seq(neighbor);
00480                             neighbor->flag |= SEQ_LEFTSEL;
00481                             seq->flag |= SEQ_RIGHTSEL;
00482                         }
00483                         break;
00484                     }
00485                 } else {
00486                     if(extend==0) deselect_all_seq(scene);
00487                     select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
00488                 }
00489             }
00490             recurs_sel_seq(seq);
00491 
00492             if(linked_time) {
00493                 select_linked_time(ed->seqbasep, seq);
00494             }
00495         }
00496     }
00497     
00498     /* marker transform */
00499 #if 0 // XXX probably need to redo this differently for 2.5
00500     if (marker) {
00501         int mval[2], xo, yo;
00502 //      getmouseco_areawin(mval);
00503         xo= mval[0]; 
00504         yo= mval[1];
00505         
00506         while(get_mbut()) {     
00507 //          getmouseco_areawin(mval);
00508             if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) {
00509                 transform_markers('g', 0);
00510                 return;
00511             }
00512         }
00513     }
00514 #endif
00515     
00516     WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
00517 
00518     /* allowing tweaks */
00519     return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
00520 }
00521 
00522 void SEQUENCER_OT_select(wmOperatorType *ot)
00523 {
00524     /* identifiers */
00525     ot->name= "Activate/Select";
00526     ot->idname= "SEQUENCER_OT_select";
00527     ot->description="Select a strip (last selected becomes the \"active strip\")";
00528     
00529     /* api callbacks */
00530     ot->invoke= sequencer_select_invoke;
00531     ot->poll= ED_operator_sequencer_active;
00532     
00533     /* flags */
00534     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00535     
00536     /* properties */
00537     RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
00538     RNA_def_boolean(ot->srna, "linked_handle", 0, "Linked Handle", "Select handles next to the active strip");
00539     /* for animation this is an enum but atm having an enum isnt useful for us */
00540     RNA_def_boolean(ot->srna, "left_right", 0, "Left/Right", "Select based on the current frame side the cursor is on");
00541     RNA_def_boolean(ot->srna, "linked_time", 0, "Linked Time", "Select other strips at the same time");
00542 }
00543 
00544 
00545 
00546 
00547 /* run recursively to select linked */
00548 static int select_more_less_seq__internal(Scene *scene, int sel, int linked)
00549 {
00550     Editing *ed= seq_give_editing(scene, FALSE);
00551     Sequence *seq, *neighbor;
00552     int change=0;
00553     int isel;
00554     
00555     if(ed==NULL) return 0;
00556     
00557     if (sel) {
00558         sel = SELECT;
00559         isel = 0;
00560     } else {
00561         sel = 0;
00562         isel = SELECT;
00563     }
00564     
00565     if (!linked) {
00566         /* if not linked we only want to touch each seq once, newseq */
00567         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
00568             seq->tmp = NULL;
00569         }
00570     }
00571     
00572     for(seq= ed->seqbasep->first; seq; seq= seq->next) {
00573         if((int)(seq->flag & SELECT) == sel) {
00574             if ((linked==0 && seq->tmp)==0) {
00575                 /* only get unselected nabours */
00576                 neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, isel);
00577                 if (neighbor) {
00578                     if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);}
00579                     else        neighbor->flag &= ~SELECT;
00580                     if (linked==0) neighbor->tmp = (Sequence *)1;
00581                     change = 1;
00582                 }
00583                 neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, isel);
00584                 if (neighbor) {
00585                     if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);}
00586                     else        neighbor->flag &= ~SELECT;
00587                     if (linked==0) neighbor->tmp = (void *)1;
00588                     change = 1;
00589                 }
00590             }
00591         }
00592     }
00593     
00594     return change;
00595 }
00596 
00597 
00598 
00599 /* select more operator */
00600 static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
00601 {
00602     Scene *scene= CTX_data_scene(C);
00603     
00604     if(!select_more_less_seq__internal(scene, 0, 0))
00605         return OPERATOR_CANCELLED;
00606 
00607     WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
00608     
00609     return OPERATOR_FINISHED;
00610 }
00611 
00612 void SEQUENCER_OT_select_more(wmOperatorType *ot)
00613 {
00614     /* identifiers */
00615     ot->name= "Select More";
00616     ot->idname= "SEQUENCER_OT_select_more";
00617     ot->description="Select more strips adjacent to the current selection";
00618     
00619     /* api callbacks */
00620     ot->exec= sequencer_select_more_exec;
00621     ot->poll= sequencer_edit_poll;
00622     
00623     /* flags */
00624     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00625     
00626     /* properties */
00627 }
00628 
00629 
00630 /* select less operator */
00631 static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
00632 {
00633     Scene *scene= CTX_data_scene(C);
00634     
00635     if(!select_more_less_seq__internal(scene, 1, 0))
00636         return OPERATOR_CANCELLED;
00637  
00638     WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
00639     
00640     return OPERATOR_FINISHED;
00641 }
00642 
00643 void SEQUENCER_OT_select_less(wmOperatorType *ot)
00644 {
00645     /* identifiers */
00646     ot->name= "Select Less";
00647     ot->idname= "SEQUENCER_OT_select_less";
00648     ot->description="Shrink the current selection of adjacent selected strips";
00649     
00650     /* api callbacks */
00651     ot->exec= sequencer_select_less_exec;
00652     ot->poll= sequencer_edit_poll;
00653     
00654     /* flags */
00655     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00656     
00657     /* properties */
00658 }
00659 
00660 
00661 /* select pick linked operator (uses the mouse) */
00662 static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
00663 {
00664     Scene *scene= CTX_data_scene(C);
00665     View2D *v2d= UI_view2d_fromcontext(C);
00666     
00667     short extend= RNA_boolean_get(op->ptr, "extend");
00668     
00669     Sequence *mouse_seq;
00670     int selected, hand;
00671 
00672     /* this works like UV, not mesh */
00673     mouse_seq= find_nearest_seq(scene, v2d, &hand, event->mval);
00674     if (!mouse_seq)
00675         return OPERATOR_FINISHED; /* user error as with mesh?? */
00676     
00677     if (extend==0)
00678         deselect_all_seq(scene);
00679     
00680     mouse_seq->flag |= SELECT;
00681     recurs_sel_seq(mouse_seq);
00682     
00683     selected = 1;
00684     while (selected) {
00685         selected = select_more_less_seq__internal(scene, 1, 1);
00686     }
00687     
00688     WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
00689     
00690     return OPERATOR_FINISHED;
00691 }
00692 
00693 void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot)
00694 {
00695     /* identifiers */
00696     ot->name= "Select pick linked";
00697     ot->idname= "SEQUENCER_OT_select_linked_pick";
00698     ot->description="Select a chain of linked strips nearest to the mouse pointer";
00699     
00700     /* api callbacks */
00701     ot->invoke= sequencer_select_linked_pick_invoke;
00702     ot->poll= ED_operator_sequencer_active;
00703     
00704     /* flags */
00705     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00706     
00707     /* properties */
00708     RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection");
00709 }
00710 
00711 
00712 /* select linked operator */
00713 static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
00714 {
00715     Scene *scene= CTX_data_scene(C);
00716     int selected;
00717 
00718     selected = 1;
00719     while (selected) {
00720         selected = select_more_less_seq__internal(scene, 1, 1);
00721     }
00722 
00723     WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
00724 
00725     return OPERATOR_FINISHED;
00726 }
00727 
00728 void SEQUENCER_OT_select_linked(wmOperatorType *ot)
00729 {
00730     /* identifiers */
00731     ot->name= "Select linked";
00732     ot->idname= "SEQUENCER_OT_select_linked";
00733     ot->description="Select all strips adjacent to the current selection";
00734     
00735     /* api callbacks */
00736     ot->exec= sequencer_select_linked_exec;
00737     ot->poll= sequencer_edit_poll;
00738     
00739     /* flags */
00740     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00741     
00742     /* properties */
00743 }
00744 
00745 
00746 /* select handles operator */
00747 static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
00748 {
00749     Scene *scene= CTX_data_scene(C);
00750     Editing *ed= seq_give_editing(scene, 0);
00751     Sequence *seq;
00752     int sel_side= RNA_enum_get(op->ptr, "side");
00753 
00754 
00755     for(seq= ed->seqbasep->first; seq; seq=seq->next) {
00756         if (seq->flag & SELECT) {
00757             switch(sel_side) {
00758             case SEQ_SIDE_LEFT:
00759                 seq->flag &= ~SEQ_RIGHTSEL;
00760                 seq->flag |= SEQ_LEFTSEL;
00761                 break;
00762             case SEQ_SIDE_RIGHT:
00763                 seq->flag &= ~SEQ_LEFTSEL;
00764                 seq->flag |= SEQ_RIGHTSEL;
00765                 break;
00766             case SEQ_SIDE_BOTH:
00767                 seq->flag |= SEQ_LEFTSEL+SEQ_RIGHTSEL;
00768                 break;
00769             }
00770         }
00771     }
00772 
00773     WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
00774 
00775     return OPERATOR_FINISHED;
00776 }
00777 
00778 void SEQUENCER_OT_select_handles(wmOperatorType *ot)
00779 {
00780     /* identifiers */
00781     ot->name= "Select Handles";
00782     ot->idname= "SEQUENCER_OT_select_handles";
00783     ot->description="Select manipulator handles on the sides of the selected strip";
00784     
00785     /* api callbacks */
00786     ot->exec= sequencer_select_handles_exec;
00787     ot->poll= sequencer_edit_poll;
00788     
00789     /* flags */
00790     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00791     
00792     /* properties */
00793     RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected");
00794 }
00795 
00796 /* select side operator */
00797 static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
00798 {
00799     Scene *scene= CTX_data_scene(C);
00800     Editing *ed= seq_give_editing(scene, 0);
00801     Sequence *seq_act= seq_active_get(scene);
00802 
00803     if (ed==NULL || seq_act==NULL)
00804         return OPERATOR_CANCELLED;
00805 
00806     seq_act->flag |= SELECT;
00807 
00808     select_active_side(ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp);
00809 
00810     WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
00811 
00812     return OPERATOR_FINISHED;
00813 }
00814 
00815 void SEQUENCER_OT_select_active_side(wmOperatorType *ot)
00816 {
00817     /* identifiers */
00818     ot->name= "Select Active Side";
00819     ot->idname= "SEQUENCER_OT_select_active_side";
00820     ot->description="Select strips on the nominated side of the active strip";
00821     
00822     /* api callbacks */
00823     ot->exec= sequencer_select_active_side_exec;
00824     ot->poll= sequencer_edit_poll;
00825 
00826     /* flags */
00827     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00828 
00829     /* properties */
00830     RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected");
00831 }
00832 
00833 
00834 /* borderselect operator */
00835 static int sequencer_borderselect_exec(bContext *C, wmOperator *op)
00836 {
00837     Scene *scene= CTX_data_scene(C);
00838     Editing *ed= seq_give_editing(scene, FALSE);
00839     View2D *v2d= UI_view2d_fromcontext(C);
00840     
00841     Sequence *seq;
00842     rcti rect;
00843     rctf rectf, rq;
00844     short selecting = (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT);
00845     int extend = RNA_boolean_get(op->ptr, "extend");
00846     int mval[2];
00847 
00848     if(ed==NULL)
00849         return OPERATOR_CANCELLED;
00850 
00851     rect.xmin= RNA_int_get(op->ptr, "xmin");
00852     rect.ymin= RNA_int_get(op->ptr, "ymin");
00853     rect.xmax= RNA_int_get(op->ptr, "xmax");
00854     rect.ymax= RNA_int_get(op->ptr, "ymax");
00855     
00856     mval[0]= rect.xmin;
00857     mval[1]= rect.ymin;
00858     UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmin, &rectf.ymin);
00859     mval[0]= rect.xmax;
00860     mval[1]= rect.ymax;
00861     UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmax, &rectf.ymax);
00862 
00863     for(seq= ed->seqbasep->first; seq; seq= seq->next) {
00864         seq_rectf(seq, &rq);
00865         
00866         if(BLI_isect_rctf(&rq, &rectf, NULL)) {
00867             if(selecting)       seq->flag |= SELECT;
00868             else                seq->flag &= ~SEQ_ALLSEL;
00869             recurs_sel_seq(seq);
00870         }
00871         else if(!extend) {
00872             seq->flag &= ~SEQ_ALLSEL;
00873             recurs_sel_seq(seq);
00874         }
00875     }
00876 
00877     WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
00878 
00879     return OPERATOR_FINISHED;
00880 } 
00881 
00882 
00883 /* ****** Border Select ****** */
00884 void SEQUENCER_OT_select_border(wmOperatorType *ot)
00885 {
00886     /* identifiers */
00887     ot->name= "Border Select";
00888     ot->idname= "SEQUENCER_OT_select_border";
00889     ot->description="Enable border select mode";
00890     
00891     /* api callbacks */
00892     ot->invoke= WM_border_select_invoke;
00893     ot->exec= sequencer_borderselect_exec;
00894     ot->modal= WM_border_select_modal;
00895     ot->cancel= WM_border_select_cancel;
00896     
00897     ot->poll= ED_operator_sequencer_active;
00898     
00899     /* flags */
00900     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00901     
00902     /* rna */
00903     WM_operator_properties_gesture_border(ot, TRUE);
00904 }
00905 
00906 /* ****** Selected Grouped ****** */
00907 
00908 static EnumPropertyItem sequencer_prop_select_grouped_types[] = {
00909     {1, "TYPE", 0, "Type", "Shared strip type"},
00910     {2, "TYPE_BASIC", 0, "Global Type", "All strips of same basic type (Graphical or Sound)"},
00911     {3, "TYPE_EFFECT", 0, "Effect Type",
00912         "Shared strip effect type (if active strip is not an effect one, select all non-effect strips)"},
00913     {4, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"},
00914     {5, "EFFECT", 0, "Effect", "Shared effects"},
00915     {6, "EFFECT_LINK", 0, "Effect/Linked",
00916         "Other strips affected by the active one (sharing some time, and below or effect-assigned)"},
00917     {7, "OVERLAP", 0, "Overlap", "Overlapping time"},
00918     {0, NULL, 0, NULL, NULL}
00919 };
00920 
00921 #define SEQ_IS_SOUND(_seq) ((_seq->type & SEQ_SOUND) && !(_seq->type & SEQ_EFFECT))
00922 
00923 #define SEQ_IS_EFFECT(_seq) (_seq->type & SEQ_EFFECT)
00924 
00925 #define SEQ_USE_DATA(_seq) (_seq->type == SEQ_SCENE || SEQ_HAS_PATH(_seq))
00926 
00927 static short select_grouped_type(Editing *ed, Sequence *actseq)
00928 {
00929     Sequence *seq;
00930     short changed = FALSE;
00931 
00932     SEQP_BEGIN(ed, seq) {
00933         if (seq->type == actseq->type) {
00934             seq->flag |= SELECT;
00935             changed = TRUE;
00936         }
00937     }
00938     SEQ_END;
00939 
00940     return changed;
00941 }
00942 
00943 static short select_grouped_type_basic(Editing *ed, Sequence *actseq)
00944 {
00945     Sequence *seq;
00946     short changed = FALSE;
00947     short is_sound = SEQ_IS_SOUND(actseq);
00948 
00949     SEQP_BEGIN(ed, seq) {
00950         if (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq)) {
00951             seq->flag |= SELECT;
00952             changed = TRUE;
00953         }
00954     }
00955     SEQ_END;
00956 
00957     return changed;
00958 }
00959 
00960 static short select_grouped_type_effect(Editing *ed, Sequence *actseq)
00961 {
00962     Sequence *seq;
00963     short changed = FALSE;
00964     short is_effect = SEQ_IS_EFFECT(actseq);
00965 
00966     SEQP_BEGIN(ed, seq) {
00967         if (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq)) {
00968             seq->flag |= SELECT;
00969             changed = TRUE;
00970         }
00971     }
00972     SEQ_END;
00973 
00974     return changed;
00975 }
00976 
00977 static short select_grouped_data(Editing *ed, Sequence *actseq)
00978 {
00979     Sequence *seq;
00980     short changed = FALSE;
00981     Scene *sce = actseq->scene;
00982     char *dir = actseq->strip ? actseq->strip->dir : NULL;
00983 
00984     if (!SEQ_USE_DATA(actseq))
00985         return changed;
00986 
00987     if (SEQ_HAS_PATH(actseq) && dir) {
00988         SEQP_BEGIN(ed, seq) {
00989             if (SEQ_HAS_PATH(seq) && seq->strip && strcmp(seq->strip->dir, dir) == 0) {
00990                 seq->flag |= SELECT;
00991                 changed = TRUE;
00992             }
00993         }
00994         SEQ_END;
00995     }
00996     else {
00997         SEQP_BEGIN(ed, seq) {
00998             if (seq->type == SEQ_SCENE && seq->scene == sce) {
00999                 seq->flag |= SELECT;
01000                 changed = TRUE;
01001             }
01002         }
01003         SEQ_END;
01004     }
01005 
01006     return changed;
01007 }
01008 
01009 static short select_grouped_effect(Editing *ed, Sequence *actseq)
01010 {
01011     Sequence *seq;
01012     short changed = FALSE;
01013     short effects[SEQ_EFFECT_MAX+1];
01014     int i;
01015 
01016     for (i = 0; i <= SEQ_EFFECT_MAX; i++)
01017         effects[i] = FALSE;
01018 
01019     SEQP_BEGIN(ed, seq) {
01020         if (ELEM3(actseq, seq->seq1, seq->seq2, seq->seq3)) {
01021             effects[seq->type] = TRUE;
01022         }
01023     }
01024     SEQ_END;
01025 
01026     SEQP_BEGIN(ed, seq) {
01027         if (effects[seq->type]) {
01028             if(seq->seq1) seq->seq1->flag |= SELECT;
01029             if(seq->seq2) seq->seq2->flag |= SELECT;
01030             if(seq->seq3) seq->seq3->flag |= SELECT;
01031             changed = TRUE;
01032         }
01033     }
01034     SEQ_END;
01035 
01036     return changed;
01037 }
01038 
01039 static short select_grouped_time_overlap(Editing *ed, Sequence *actseq)
01040 {
01041     Sequence *seq;
01042     short changed = FALSE;
01043 
01044     SEQP_BEGIN(ed, seq) {
01045         if (!((seq->startdisp >= actseq->enddisp) || (seq->enddisp < actseq->startdisp))) {
01046             seq->flag |= SELECT;
01047             changed = TRUE;
01048         }
01049     }
01050     SEQ_END;
01051 
01052     return changed;
01053 }
01054 
01055 static short select_grouped_effect_link(Editing *ed, Sequence *actseq)
01056 {
01057     Sequence *seq = NULL;
01058     short changed = FALSE;
01059     short is_audio = ((actseq->type == SEQ_META) || SEQ_IS_SOUND(actseq));
01060     int startdisp = actseq->startdisp;
01061     int enddisp   = actseq->enddisp;
01062     int machine   = actseq->machine;
01063     SeqIterator iter;
01064 
01065     SEQP_BEGIN(ed, seq) {
01066         seq->tmp= NULL;
01067     }
01068     SEQ_END;
01069 
01070     actseq->tmp= SET_INT_IN_POINTER(TRUE);
01071 
01072     for(seq_begin(ed, &iter, 1); iter.valid; seq_next(&iter)) {
01073         seq = iter.seq;
01074 
01075         /* Ignore all seqs already selected! */
01076         /* Ignore all seqs not sharing some time with active one. */
01077         /* Ignore all seqs of incompatible types (audio vs video). */
01078         if ((seq->flag & SELECT) || (seq->startdisp >= enddisp) || (seq->enddisp < startdisp)
01079             || (!is_audio && SEQ_IS_SOUND(seq))
01080             || (is_audio && !((seq->type == SEQ_META) || SEQ_IS_SOUND(seq))))
01081             continue;
01082 
01083         /* If the seq is an effect one, we need extra cheking! */
01084         if (SEQ_IS_EFFECT(seq) && ((seq->seq1 && seq->seq1->tmp) ||
01085                                    (seq->seq2 && seq->seq2->tmp) ||
01086                                    (seq->seq3 && seq->seq3->tmp)))
01087         {
01088             if (startdisp > seq->startdisp) startdisp = seq->startdisp;
01089             if (enddisp < seq->enddisp) enddisp = seq->enddisp;
01090             if (machine < seq->machine) machine = seq->machine;
01091 
01092             seq->tmp= SET_INT_IN_POINTER(TRUE);
01093 
01094             seq->flag |= SELECT;
01095             changed = TRUE;
01096 
01097             /* Unfortunately, we must restart checks from the begining. */
01098             seq_end(&iter);
01099             seq_begin(ed, &iter, 1);
01100         }
01101 
01102         /* Video strips bellow active one, or any strip for audio (order do no matters here!). */
01103         else if (seq->machine < machine || is_audio) {
01104             seq->flag |= SELECT;
01105             changed = TRUE;
01106         }
01107     }
01108     seq_end(&iter);
01109 
01110     return changed;
01111 }
01112 
01113 static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
01114 {
01115     Scene *scene  = CTX_data_scene(C);
01116     Editing *ed   = seq_give_editing(scene, 0);
01117     Sequence *seq, *actseq = seq_active_get(scene);
01118     int type = RNA_enum_get(op->ptr, "type");
01119     short changed = 0, extend;
01120 
01121     extend = RNA_boolean_get(op->ptr, "extend");
01122 
01123     if (actseq == NULL) {
01124         BKE_report(op->reports, RPT_ERROR, "No Active Sequence!");
01125         return OPERATOR_CANCELLED;
01126     }
01127 
01128     if (extend == 0) {
01129         SEQP_BEGIN(ed, seq) {
01130             seq->flag &= ~SELECT;
01131             changed = TRUE;
01132         }
01133         SEQ_END;
01134     }
01135 
01136     if(type==1)      changed |= select_grouped_type(ed, actseq);
01137     else if(type==2) changed |= select_grouped_type_basic(ed, actseq);
01138     else if(type==3) changed |= select_grouped_type_effect(ed, actseq);
01139     else if(type==4) changed |= select_grouped_data(ed, actseq);
01140     else if(type==5) changed |= select_grouped_effect(ed, actseq);
01141     else if(type==6) changed |= select_grouped_effect_link(ed, actseq);
01142     else if(type==7) changed |= select_grouped_time_overlap(ed, actseq);
01143 
01144     if (changed) {
01145         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
01146         return OPERATOR_FINISHED;
01147     }
01148 
01149     return OPERATOR_CANCELLED;
01150 }
01151 
01152 void SEQUENCER_OT_select_grouped(wmOperatorType *ot)
01153 {
01154     /* identifiers */
01155     ot->name = "Select Grouped";
01156     ot->description = "Select all strips grouped by various properties";
01157     ot->idname = "SEQUENCER_OT_select_grouped";
01158     
01159     /* api callbacks */
01160     ot->invoke = WM_menu_invoke;
01161     ot->exec = sequencer_select_grouped_exec;
01162     ot->poll = sequencer_edit_poll;
01163     
01164     /* flags */
01165     ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
01166     
01167     /* properties */
01168     RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
01169     ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_select_grouped_types, 0, "Type", "");
01170 }
01171