Blender V2.61 - r43446

anim_markers.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) 2008 Blender Foundation.
00019  * All rights reserved.
00020  *
00021  * 
00022  * Contributor(s): Blender Foundation
00023  *
00024  * ***** END GPL LICENSE BLOCK *****
00025  */
00026 
00032 #include <math.h>
00033 
00034 #include "MEM_guardedalloc.h"
00035 
00036 #include "DNA_scene_types.h"
00037 #include "DNA_object_types.h"
00038 
00039 #include "RNA_access.h"
00040 #include "RNA_define.h"
00041 #include "RNA_enum_types.h"
00042 
00043 #include "BLI_blenlib.h"
00044 #include "BLI_utildefines.h"
00045 
00046 #include "BKE_context.h"
00047 #include "BKE_fcurve.h"
00048 #include "BKE_main.h"
00049 #include "BKE_report.h"
00050 #include "BKE_scene.h"
00051 #include "BKE_screen.h"
00052 
00053 #include "WM_api.h"
00054 #include "WM_types.h"
00055 
00056 #include "BIF_gl.h"
00057 #include "BIF_glutil.h"
00058 
00059 #include "UI_interface.h"
00060 #include "UI_interface_icons.h"
00061 #include "UI_view2d.h"
00062 #include "UI_resources.h"
00063 
00064 #include "ED_anim_api.h"
00065 #include "ED_markers.h"
00066 #include "ED_screen.h"
00067 #include "ED_util.h"
00068 #include "ED_numinput.h"
00069 #include "ED_object.h"
00070 #include "ED_transform.h"
00071 #include "ED_types.h"
00072 
00073 /* ************* Marker API **************** */
00074 
00075 /* helper function for getting the list of markers to work on */
00076 static ListBase *context_get_markers(Scene *scene, ScrArea *sa)
00077 {
00078     /* local marker sets... */
00079     if (sa) {
00080         if (sa->spacetype == SPACE_ACTION) {
00081             SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
00082             
00083             /* local markers can only be shown when there's only a single active action to grab them from 
00084              *  - flag only takes effect when there's an action, otherwise it can get too confusing?
00085              */
00086             if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) && (saction->action)) 
00087             {
00088                 if (saction->flag & SACTION_POSEMARKERS_SHOW)
00089                     return &saction->action->markers;
00090             }
00091         }
00092     }
00093     
00094     /* default to using the scene's markers */
00095     return &scene->markers;
00096 }
00097 
00098 /* ............. */
00099 
00100 /* public API for getting markers from context */
00101 ListBase *ED_context_get_markers(const bContext *C)
00102 {
00103     return context_get_markers(CTX_data_scene(C), CTX_wm_area(C));
00104 }
00105 
00106 /* public API for getting markers from "animation" context */
00107 ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
00108 {
00109     if (ac)
00110         return context_get_markers(ac->scene, ac->sa);
00111     else
00112         return NULL;
00113 }
00114 
00115 /* --------------------------------- */
00116 
00117 /* Apply some transformation to markers after the fact 
00118  * < markers: list of markers to affect - this may or may not be the scene markers list, so don't assume anything
00119  * < scene: current scene (for getting current frame)
00120  * < mode: (TfmMode) transform mode that this transform is for
00121  * < value: from the transform code, this is t->vec[0] (which is delta transform for grab/extend, and scale factor for scale)
00122  * < side: (B/L/R) for 'extend' functionality, which side of current frame to use
00123  */
00124 int ED_markers_post_apply_transform (ListBase *markers, Scene *scene, int mode, float value, char side)
00125 {
00126     TimeMarker *marker;
00127     float cfra = (float)CFRA;
00128     int changed = 0;
00129     
00130     /* sanity check */
00131     if (markers == NULL)
00132         return changed;
00133     
00134     /* affect selected markers - it's unlikely that we will want to affect all in this way? */
00135     for (marker = markers->first; marker; marker = marker->next) {
00136         if (marker->flag & SELECT) {
00137             switch (mode) {
00138                 case TFM_TIME_TRANSLATE:
00139                 case TFM_TIME_EXTEND:
00140                 {
00141                     /* apply delta if marker is on the right side of the current frame */
00142                     if ((side=='B') ||
00143                         (side=='L' && marker->frame < cfra) || 
00144                         (side=='R' && marker->frame >= cfra))
00145                     {
00146                         marker->frame += (int)floorf(value + 0.5f);
00147                         changed++;
00148                     }
00149                 }
00150                     break;
00151                     
00152                 case TFM_TIME_SCALE:
00153                 {   
00154                     /* rescale the distance between the marker and the current frame */
00155                     marker->frame= cfra + (int)floorf(((float)(marker->frame - cfra) * value) + 0.5f);
00156                     changed++;
00157                 }
00158                     break;
00159             }
00160         }
00161     }
00162     
00163     return changed;
00164 }
00165 
00166 /* --------------------------------- */
00167 
00168 /* Get the marker that is closest to this point */
00169 /* XXX for select, the min_dist should be small */
00170 TimeMarker *ED_markers_find_nearest_marker (ListBase *markers, float x) 
00171 {
00172     TimeMarker *marker, *nearest=NULL;
00173     float dist, min_dist= 1000000;
00174     
00175     if (markers) {
00176         for (marker= markers->first; marker; marker= marker->next) {
00177             dist = ABS((float)marker->frame - x);
00178             
00179             if (dist < min_dist) {
00180                 min_dist= dist;
00181                 nearest= marker;
00182             }
00183         }
00184     }
00185     
00186     return nearest;
00187 }
00188 
00189 /* Return the time of the marker that occurs on a frame closest to the given time */
00190 int ED_markers_find_nearest_marker_time (ListBase *markers, float x)
00191 {
00192     TimeMarker *nearest= ED_markers_find_nearest_marker(markers, x);
00193     return (nearest) ? (nearest->frame) : (int)floor(x + 0.5f);
00194 }
00195 
00196 
00197 void ED_markers_get_minmax (ListBase *markers, short sel, float *first, float *last)
00198 {
00199     TimeMarker *marker;
00200     float min, max;
00201     int selcount = 0;
00202     
00203     /* sanity check */
00204     //printf("markers = %p -  %p, %p \n", markers, markers->first, markers->last);
00205     if (markers == NULL) {
00206         *first = 0.0f;
00207         *last = 0.0f;
00208         return;
00209     }
00210     
00211     if (markers->first && markers->last) {
00212         TimeMarker *fm= markers->first;
00213         TimeMarker *lm= markers->last;
00214         
00215         min= (float)fm->frame;
00216         max= (float)lm->frame;
00217     }
00218     else {
00219         *first = 0.0f;
00220         *last = 0.0f;
00221         return;
00222     }
00223     
00224     /* count how many markers are usable - see later */
00225     if (sel) {
00226         for (marker= markers->first; marker; marker= marker->next) {
00227             if (marker->flag & SELECT)
00228                 selcount++;
00229         }
00230     }
00231     else
00232         selcount= BLI_countlist(markers);
00233     
00234     /* if only selected are to be considered, only consider the selected ones
00235      * (optimisation for not searching list) 
00236      */
00237     if (selcount > 1) {
00238         for (marker= markers->first; marker; marker= marker->next) {
00239             if (sel) {
00240                 if (marker->flag & SELECT) {
00241                     if (marker->frame < min)
00242                         min= (float)marker->frame;
00243                     if (marker->frame > max)
00244                         max= (float)marker->frame;
00245                 }
00246             }
00247             else {
00248                 if (marker->frame < min)
00249                     min= (float)marker->frame;
00250                 if (marker->frame > max)
00251                     max= (float)marker->frame;
00252             }   
00253         }
00254     }
00255     
00256     /* set the min/max values */
00257     *first= min;
00258     *last= max;
00259 }
00260 
00261 /* --------------------------------- */
00262 
00263 /* Adds a marker to list of cfra elems */
00264 static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel)
00265 {
00266     CfraElem *ce, *cen;
00267     
00268     /* should this one only be considered if it is selected? */
00269     if ((only_sel) && ((marker->flag & SELECT)==0))
00270         return;
00271     
00272     /* insertion sort - try to find a previous cfra elem */
00273     for (ce= lb->first; ce; ce= ce->next) {
00274         if (ce->cfra == marker->frame) {
00275             /* do because of double keys */
00276             if (marker->flag & SELECT) 
00277                 ce->sel= marker->flag;
00278             return;
00279         }
00280         else if (ce->cfra > marker->frame) break;
00281     }   
00282     
00283     cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem"); 
00284     if (ce) BLI_insertlinkbefore(lb, ce, cen);
00285     else BLI_addtail(lb, cen);
00286 
00287     cen->cfra= marker->frame;
00288     cen->sel= marker->flag;
00289 }
00290 
00291 /* This function makes a list of all the markers. The only_sel
00292  * argument is used to specify whether only the selected markers
00293  * are added.
00294  */
00295 void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
00296 {
00297     TimeMarker *marker;
00298     
00299     if (markers == NULL)
00300         return;
00301     
00302     for (marker= markers->first; marker; marker= marker->next)
00303         add_marker_to_cfra_elem(lb, marker, only_sel);
00304 }
00305 
00306 /* --------------------------------- */
00307 
00308 /* Get the first selected marker */
00309 TimeMarker *ED_markers_get_first_selected(ListBase *markers)
00310 {
00311     TimeMarker *marker;
00312     
00313     if (markers) {
00314         for (marker = markers->first; marker; marker = marker->next) {
00315             if (marker->flag & SELECT)
00316                 return marker;
00317         }
00318     }
00319     
00320     return NULL;
00321 }
00322 
00323 /* --------------------------------- */
00324 
00325 /* Print debugging prints of list of markers 
00326  * BSI's: do NOT make static or put in if-defs as "unused code". That's too much trouble when we need to use for quick debuggging!
00327  */
00328 void debug_markers_print_list(ListBase *markers)
00329 {
00330     TimeMarker *marker;
00331     
00332     if (markers == NULL) {
00333         printf("No markers list to print debug for\n");
00334         return;
00335     }
00336     
00337     printf("List of markers follows: -----\n");
00338     
00339     for (marker = markers->first; marker; marker = marker->next) {
00340         printf("\t'%s' on %d at %p with %u\n", marker->name, marker->frame, (void *)marker, marker->flag);
00341     }
00342     
00343     printf("End of list ------------------\n");
00344 }
00345 
00346 /* ************* Marker Drawing ************ */
00347 
00348 /* function to draw markers */
00349 static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
00350 {
00351     float xpos, ypixels, xscale, yscale;
00352     int icon_id= 0;
00353     
00354     xpos = marker->frame;
00355     
00356     /* no time correction for framelen! space is drawn with old values */
00357     ypixels= v2d->mask.ymax-v2d->mask.ymin;
00358     UI_view2d_getscale(v2d, &xscale, &yscale);
00359     
00360     glScalef(1.0f/xscale, 1.0f, 1.0f);
00361     
00362     glEnable(GL_BLEND);
00363     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);          
00364     
00365     /* vertical line - dotted */
00366 #ifdef DURIAN_CAMERA_SWITCH
00367     if ((marker->camera) || (flag & DRAW_MARKERS_LINES))
00368 #else
00369     if (flag & DRAW_MARKERS_LINES)
00370 #endif
00371     {
00372         setlinestyle(3);
00373         
00374         if (marker->flag & SELECT)
00375             glColor4ub(255, 255, 255, 96);
00376         else
00377             glColor4ub(0, 0, 0, 96);
00378         
00379         glBegin(GL_LINES);
00380             glVertex2f((xpos*xscale)+0.5f, 12.0f);
00381             glVertex2f((xpos*xscale)+0.5f, (v2d->cur.ymax+12.0f)*yscale);
00382         glEnd();
00383         
00384         setlinestyle(0);
00385     }
00386     
00387     /* 5 px to offset icon to align properly, space / pixels corrects for zoom */
00388     if (flag & DRAW_MARKERS_LOCAL) {
00389         icon_id= (marker->flag & ACTIVE) ? ICON_PMARKER_ACT : 
00390         (marker->flag & SELECT) ? ICON_PMARKER_SEL : 
00391         ICON_PMARKER;
00392     }
00393     else {
00394         icon_id= (marker->flag & SELECT) ? ICON_MARKER_HLT : 
00395         ICON_MARKER;
00396     }
00397     
00398     UI_icon_draw(xpos*xscale-5.0f, 16.0f, icon_id);
00399     
00400     glDisable(GL_BLEND);
00401     
00402     /* and the marker name too, shifted slightly to the top-right */
00403     if (marker->name && marker->name[0]) {
00404         float x, y;
00405         
00406         if (marker->flag & SELECT) {
00407             UI_ThemeColor(TH_TEXT_HI);
00408             x= xpos*xscale + 4.0f;
00409             y= (ypixels <= 39.0f)? (ypixels-10.0f) : 29.0f;
00410         }
00411         else {
00412             UI_ThemeColor(TH_TEXT);
00413             if((marker->frame <= cfra) && (marker->frame+5 > cfra)) {
00414                 x= xpos*xscale + 4.0f;
00415                 y= (ypixels <= 39.0f)? (ypixels - 10.0f) : 29.0f;
00416             }
00417             else {
00418                 x= xpos*xscale + 4.0f;
00419                 y= 17.0f;
00420             }
00421         }
00422 
00423 #ifdef DURIAN_CAMERA_SWITCH
00424         if(marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) {
00425             float col[4];
00426             glGetFloatv(GL_CURRENT_COLOR, col);
00427             col[3]= 0.4;
00428             glColor4fv(col);
00429         }
00430 #endif
00431 
00432         UI_DrawString(x, y, marker->name);
00433     }
00434     
00435     glScalef(xscale, 1.0f, 1.0f);
00436 }
00437 
00438 /* Draw Scene-Markers in time window */
00439 void draw_markers_time(const bContext *C, int flag)
00440 {
00441     ListBase *markers= ED_context_get_markers(C);
00442     View2D *v2d= UI_view2d_fromcontext(C);
00443     TimeMarker *marker;
00444     
00445     if (markers == NULL)
00446         return;
00447     
00448     /* unselected markers are drawn at the first time */
00449     for (marker= markers->first; marker; marker= marker->next) {
00450         if ((marker->flag & SELECT) == 0) 
00451             draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
00452     }
00453     
00454     /* selected markers are drawn later */
00455     for (marker= markers->first; marker; marker= marker->next) {
00456         if (marker->flag & SELECT) 
00457             draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
00458     }
00459 }
00460 
00461 /* ************************ Marker Wrappers API ********************* */
00462 /* These wrappers allow marker operators to function within the confines 
00463  * of standard animation editors, such that they can coexist with the 
00464  * primary operations of those editors.
00465  */
00466 
00467 /* ------------------------ */
00468 
00469 /* special poll() which checks if there are selected markers first */
00470 static int ed_markers_poll_selected_markers(bContext *C)
00471 {
00472     ListBase *markers = ED_context_get_markers(C);
00473     
00474     /* first things first: markers can only exist in timeline views */
00475     if (ED_operator_animview_active(C) == 0)
00476         return 0;
00477         
00478     /* check if some marker is selected */
00479     return ED_markers_get_first_selected(markers) != NULL;
00480 }
00481 
00482 /* special poll() which checks if there are any markers at all first */
00483 static int ed_markers_poll_markers_exist(bContext *C)
00484 {
00485     ListBase *markers = ED_context_get_markers(C);
00486     
00487     /* first things first: markers can only exist in timeline views */
00488     if (ED_operator_animview_active(C) == 0)
00489         return 0;
00490         
00491     /* list of markers must exist, as well as some markers in it! */
00492     return (markers && markers->first);
00493 }
00494  
00495 /* ------------------------ */ 
00496 
00497 /* Second-tier invoke() callback that performs context validation before running the  
00498  * "custom"/third-tier invoke() callback supplied as the last arg (which would normally
00499  * be the operator's invoke() callback elsewhere)
00500  *
00501  * < invoke_func: (fn(bContext*, wmOperator*, wmEvent*)=int) "standard" invoke function 
00502  *          that operator would otherwise have used. If NULL, the operator's standard
00503  *          exec() callback will be called instead in the appropriate places.
00504  */
00505 static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent *evt, 
00506         int (*invoke_func)(bContext*,wmOperator*,wmEvent*))
00507 {
00508     ScrArea *sa = CTX_wm_area(C);
00509     int retval = OPERATOR_PASS_THROUGH;
00510     
00511     /* removed check for Y coord of event, keymap has bounbox now */
00512     
00513     /* allow operator to run now */
00514     if (invoke_func)
00515         retval = invoke_func(C, op, evt);
00516     else if (op->type->exec)
00517         retval = op->type->exec(C, op);
00518     else
00519         BKE_report(op->reports, RPT_ERROR, "Programming error: operator doesn't actually have code to do anything!");
00520         
00521     /* return status modifications - for now, make this spacetype dependent as above */
00522     if (sa->spacetype != SPACE_TIME) {
00523         /* unless successful, must add "pass-through" to let normal operator's have a chance at tackling this event */
00524         if (retval != OPERATOR_FINISHED)
00525             retval |= OPERATOR_PASS_THROUGH;
00526     }
00527     
00528     return retval;
00529 }
00530 
00531 /* standard wrapper - first-tier invoke() callback to be directly assigned to operator typedata
00532  * for operators which don't need any special invoke calls. Any operators with special invoke calls
00533  * though will need to implement their own wrapper which calls the second-tier callback themselves
00534  * (passing through the custom invoke function they use)
00535  */
00536 static int ed_markers_opwrap_invoke(bContext *C, wmOperator *op, wmEvent *evt)
00537 {
00538     return ed_markers_opwrap_invoke_custom(C, op, evt, NULL);
00539 }
00540 
00541 /* ************************** add markers *************************** */
00542 
00543 /* add TimeMarker at curent frame */
00544 static int ed_marker_add(bContext *C, wmOperator *UNUSED(op))
00545 {
00546     ListBase *markers= ED_context_get_markers(C);
00547     TimeMarker *marker;
00548     int frame= CTX_data_scene(C)->r.cfra;
00549     
00550     if (markers == NULL)
00551         return OPERATOR_CANCELLED;
00552     
00553     /* two markers can't be at the same place */
00554     for (marker= markers->first; marker; marker= marker->next) {
00555         if (marker->frame == frame) 
00556             return OPERATOR_CANCELLED;
00557     }
00558     
00559     /* deselect all */
00560     for (marker= markers->first; marker; marker= marker->next)
00561         marker->flag &= ~SELECT;
00562     
00563     marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
00564     marker->flag= SELECT;
00565     marker->frame= frame;
00566     BLI_snprintf(marker->name, sizeof(marker->name), "F_%02d", frame); // XXX - temp code only
00567     BLI_addtail(markers, marker);
00568     
00569     WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
00570     WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
00571     
00572     return OPERATOR_FINISHED;
00573 }
00574 
00575 static void MARKER_OT_add(wmOperatorType *ot)
00576 {
00577     /* identifiers */
00578     ot->name= "Add Time Marker";
00579     ot->description= "Add a new time marker";
00580     ot->idname= "MARKER_OT_add";
00581     
00582     /* api callbacks */
00583     ot->exec= ed_marker_add;
00584     ot->invoke = ed_markers_opwrap_invoke;
00585     ot->poll= ED_operator_animview_active;
00586     
00587     /* flags */
00588     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00589 }
00590 
00591 /* ************************** transform markers *************************** */
00592 
00593 
00594 /* operator state vars used:  
00595     frs: delta movement
00596 
00597 functions:
00598 
00599     init()   check selection, add customdata with old values and some lookups
00600 
00601     apply()  do the actual movement
00602 
00603     exit()  cleanup, send notifier
00604 
00605     cancel() to escape from modal
00606 
00607 callbacks:
00608 
00609     exec()  calls init, apply, exit 
00610 
00611     invoke() calls init, adds modal handler
00612 
00613     modal() accept modal events while doing it, ends with apply and exit, or cancel
00614 
00615 */
00616 
00617 typedef struct MarkerMove {
00618     SpaceLink *slink;
00619     ListBase *markers;
00620     int event_type;     /* store invoke-event, to verify */
00621     int *oldframe, evtx, firstx;
00622     NumInput num;
00623 } MarkerMove;
00624 
00625 /* copy selection to temp buffer */
00626 /* return 0 if not OK */
00627 static int ed_marker_move_init(bContext *C, wmOperator *op)
00628 {
00629     ListBase *markers= ED_context_get_markers(C);
00630     MarkerMove *mm;
00631     TimeMarker *marker;
00632     int totmark=0;
00633     int a;
00634 
00635     if(markers == NULL) return 0;
00636     
00637     for (marker= markers->first; marker; marker= marker->next)
00638         if (marker->flag & SELECT) totmark++;
00639     
00640     if (totmark==0) return 0;
00641     
00642     op->customdata= mm= MEM_callocN(sizeof(MarkerMove), "Markermove");
00643     mm->slink= CTX_wm_space_data(C);
00644     mm->markers= markers;
00645     mm->oldframe= MEM_callocN(totmark*sizeof(int), "MarkerMove oldframe");
00646 
00647     initNumInput(&mm->num);
00648     mm->num.idx_max = 0; /* one axis */
00649     mm->num.flag |= NUM_NO_FRACTION;
00650     mm->num.increment = 1.0f;
00651     
00652     for (a=0, marker= markers->first; marker; marker= marker->next) {
00653         if (marker->flag & SELECT) {
00654             mm->oldframe[a]= marker->frame;
00655             a++;
00656         }
00657     }
00658     
00659     return 1;
00660 }
00661 
00662 /* free stuff */
00663 static void ed_marker_move_exit(bContext *C, wmOperator *op)
00664 {
00665     MarkerMove *mm= op->customdata;
00666     
00667     /* free data */
00668     MEM_freeN(mm->oldframe);
00669     MEM_freeN(op->customdata);
00670     op->customdata= NULL;
00671     
00672     /* clear custom header prints */
00673     ED_area_headerprint(CTX_wm_area(C), NULL);
00674 }
00675 
00676 static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
00677 {
00678     if(ed_marker_move_init(C, op)) {
00679         MarkerMove *mm= op->customdata;
00680         
00681         mm->evtx= evt->x;
00682         mm->firstx= evt->x;
00683         mm->event_type= evt->type;
00684         
00685         /* add temp handler */
00686         WM_event_add_modal_handler(C, op);
00687         
00688         /* reset frs delta */
00689         RNA_int_set(op->ptr, "frames", 0);
00690         
00691         return OPERATOR_RUNNING_MODAL;
00692     }
00693     
00694     return OPERATOR_CANCELLED;
00695 }
00696 
00697 static int ed_marker_move_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
00698 {
00699     return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_move_invoke);
00700 }
00701 
00702 /* note, init has to be called succesfully */
00703 static void ed_marker_move_apply(wmOperator *op)
00704 {
00705     MarkerMove *mm= op->customdata;
00706     TimeMarker *marker;
00707     int a, offs;
00708     
00709     offs= RNA_int_get(op->ptr, "frames");
00710     for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
00711         if (marker->flag & SELECT) {
00712             marker->frame= mm->oldframe[a] + offs;
00713             a++;
00714         }
00715     }
00716 }
00717 
00718 /* only for modal */
00719 static int ed_marker_move_cancel(bContext *C, wmOperator *op)
00720 {
00721     RNA_int_set(op->ptr, "frames", 0);
00722     ed_marker_move_apply(op);
00723     ed_marker_move_exit(C, op); 
00724     
00725     WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
00726     WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
00727 
00728     return OPERATOR_CANCELLED;
00729 }
00730 
00731 
00732 
00733 static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
00734 {
00735     Scene *scene= CTX_data_scene(C);
00736     MarkerMove *mm= op->customdata;
00737     View2D *v2d= UI_view2d_fromcontext(C);
00738     TimeMarker *marker, *selmarker=NULL;
00739     float dx, fac;
00740     char str[256];
00741         
00742     switch(evt->type) {
00743         case ESCKEY:
00744             ed_marker_move_cancel(C, op);
00745             return OPERATOR_CANCELLED;
00746         
00747         case RIGHTMOUSE:
00748             /* press = user manually demands transform to be cancelled */
00749             if (evt->val == KM_PRESS) {
00750                 ed_marker_move_cancel(C, op);
00751                 return OPERATOR_CANCELLED;
00752             }
00753             /* else continue; <--- see if release event should be caught for tweak-end */
00754         
00755         case RETKEY:
00756         case PADENTER:
00757         case LEFTMOUSE:
00758         case MIDDLEMOUSE:
00759             if (WM_modal_tweak_exit(evt, mm->event_type)) {
00760                 ed_marker_move_exit(C, op);
00761                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
00762                 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
00763                 return OPERATOR_FINISHED;
00764             }
00765             break;
00766         case MOUSEMOVE:
00767             if (hasNumInput(&mm->num))
00768                 break;
00769             
00770             dx= v2d->mask.xmax-v2d->mask.xmin;
00771             dx= (v2d->cur.xmax-v2d->cur.xmin)/dx;
00772             
00773             if (evt->x != mm->evtx) {   /* XXX maybe init for firsttime */
00774                 int a, offs, totmark=0;
00775                 
00776                 mm->evtx= evt->x;
00777                 
00778                 fac= ((float)(evt->x - mm->firstx)*dx);
00779                 
00780                 if (mm->slink->spacetype == SPACE_TIME) 
00781                     apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1*FPS, 0);
00782                 else
00783                     apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
00784                 
00785                 offs= (int)fac;
00786                 RNA_int_set(op->ptr, "frames", offs);
00787                 ed_marker_move_apply(op);
00788                 
00789                 /* cruft below is for header print */
00790                 for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
00791                     if (marker->flag & SELECT) {
00792                         selmarker= marker;
00793                         a++; totmark++;
00794                     }
00795                 }
00796                 
00797                 if (totmark==1) {   
00798                     /* we print current marker value */
00799                     if (mm->slink->spacetype == SPACE_TIME) {
00800                         SpaceTime *stime= (SpaceTime *)mm->slink;
00801                         if (stime->flag & TIME_DRAWFRAMES) 
00802                             BLI_snprintf(str, sizeof(str), "Marker %d offset %d", selmarker->frame, offs);
00803                         else 
00804                             BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
00805                     }
00806                     else if (mm->slink->spacetype == SPACE_ACTION) {
00807                         SpaceAction *saction= (SpaceAction *)mm->slink;
00808                         if (saction->flag & SACTION_DRAWTIME)
00809                             BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
00810                         else
00811                             BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
00812                     }
00813                     else {
00814                         BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
00815                     }
00816                 }
00817                 else {
00818                     /* we only print the offset */
00819                     if (mm->slink->spacetype == SPACE_TIME) { 
00820                         SpaceTime *stime= (SpaceTime *)mm->slink;
00821                         if (stime->flag & TIME_DRAWFRAMES) 
00822                             BLI_snprintf(str, sizeof(str), "Marker offset %d ", offs);
00823                         else 
00824                             BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
00825                     }
00826                     else if (mm->slink->spacetype == SPACE_ACTION) {
00827                         SpaceAction *saction= (SpaceAction *)mm->slink;
00828                         if (saction->flag & SACTION_DRAWTIME)
00829                             BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
00830                         else
00831                             BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
00832                     }
00833                     else {
00834                         BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
00835                     }
00836                 }
00837                 
00838                 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
00839                 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
00840                 ED_area_headerprint(CTX_wm_area(C), str);
00841             }
00842     }
00843 
00844     if (evt->val==KM_PRESS) {
00845         float vec[3];
00846         char str_tx[256];
00847         
00848         if (handleNumInput(&mm->num, evt))
00849         {
00850             applyNumInput(&mm->num, vec);
00851             outputNumInput(&mm->num, str_tx);
00852             
00853             RNA_int_set(op->ptr, "frames", vec[0]);
00854             ed_marker_move_apply(op);
00855             // ed_marker_header_update(C, op, str, (int)vec[0]);
00856             // strcat(str, str_tx);
00857             BLI_snprintf(str, sizeof(str), "Marker offset %s", str_tx);
00858             ED_area_headerprint(CTX_wm_area(C), str);
00859             
00860             WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
00861             WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
00862         }
00863     }
00864 
00865     return OPERATOR_RUNNING_MODAL;
00866 }
00867 
00868 static int ed_marker_move_exec(bContext *C, wmOperator *op)
00869 {
00870     if(ed_marker_move_init(C, op)) {
00871         ed_marker_move_apply(op);
00872         ed_marker_move_exit(C, op);
00873         return OPERATOR_FINISHED;
00874     }
00875     return OPERATOR_PASS_THROUGH;
00876 }
00877 
00878 static void MARKER_OT_move(wmOperatorType *ot)
00879 {
00880     /* identifiers */
00881     ot->name= "Move Time Marker";
00882     ot->description= "Move selected time marker(s)";
00883     ot->idname= "MARKER_OT_move";
00884     
00885     /* api callbacks */
00886     ot->exec= ed_marker_move_exec;
00887     ot->invoke= ed_marker_move_invoke_wrapper;
00888     ot->modal= ed_marker_move_modal;
00889     ot->poll= ed_markers_poll_selected_markers;
00890     ot->cancel= ed_marker_move_cancel;
00891     
00892     /* flags */
00893     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
00894     
00895     /* rna storage */
00896     RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
00897 }
00898 
00899 /* ************************** duplicate markers *************************** */
00900 
00901 /* operator state vars used:  
00902     frs: delta movement
00903 
00904 functions:
00905 
00906     apply()  do the actual duplicate
00907 
00908 callbacks:
00909 
00910     exec()  calls apply, move_exec
00911 
00912     invoke() calls apply, move_invoke
00913 
00914     modal() uses move_modal
00915 
00916 */
00917 
00918 
00919 /* duplicate selected TimeMarkers */
00920 static void ed_marker_duplicate_apply(bContext *C)
00921 {
00922     ListBase *markers= ED_context_get_markers(C);
00923     TimeMarker *marker, *newmarker;
00924     
00925     if (markers == NULL) 
00926         return;
00927 
00928     /* go through the list of markers, duplicate selected markers and add duplicated copies
00929      * to the begining of the list (unselect original markers) 
00930      */
00931     for (marker= markers->first; marker; marker= marker->next) {
00932         if (marker->flag & SELECT) {
00933             /* unselect selected marker */
00934             marker->flag &= ~SELECT;
00935             
00936             /* create and set up new marker */
00937             newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
00938             newmarker->flag= SELECT;
00939             newmarker->frame= marker->frame;
00940             BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
00941             
00942 #ifdef DURIAN_CAMERA_SWITCH
00943             newmarker->camera= marker->camera;
00944 #endif
00945 
00946             /* new marker is added to the begining of list */
00947             // FIXME: bad ordering!
00948             BLI_addhead(markers, newmarker);
00949         }
00950     }
00951 }
00952 
00953 static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
00954 {
00955     ed_marker_duplicate_apply(C);
00956     ed_marker_move_exec(C, op); /* assumes frs delta set */
00957     
00958     return OPERATOR_FINISHED;
00959     
00960 }
00961 
00962 static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
00963 {
00964     ed_marker_duplicate_apply(C);
00965     return ed_marker_move_invoke(C, op, evt);
00966 }
00967 
00968 static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
00969 {
00970     return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_duplicate_invoke);
00971 }
00972 
00973 static void MARKER_OT_duplicate(wmOperatorType *ot)
00974 {
00975     /* identifiers */
00976     ot->name= "Duplicate Time Marker";
00977     ot->description= "Duplicate selected time marker(s)";
00978     ot->idname= "MARKER_OT_duplicate";
00979     
00980     /* api callbacks */
00981     ot->exec= ed_marker_duplicate_exec;
00982     ot->invoke= ed_marker_duplicate_invoke_wrapper;
00983     ot->modal= ed_marker_move_modal;
00984     ot->poll= ed_markers_poll_selected_markers;
00985     ot->cancel= ed_marker_move_cancel;
00986     
00987     /* flags */
00988     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
00989     
00990     /* rna storage */
00991     RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
00992 }
00993 
00994 /* ************************** selection ************************************/
00995 
00996 /* select/deselect TimeMarker at current frame */
00997 static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned char shift)
00998 {
00999     TimeMarker *marker;
01000     int select=0;
01001     
01002     for (marker= markers->first; marker; marker= marker->next) {
01003         /* if Shift is not set, then deselect Markers */
01004         if (!shift) marker->flag &= ~SELECT;
01005         
01006         /* this way a not-shift select will allways give 1 selected marker */
01007         if ((marker->frame == frame) && (!select)) {
01008             if (marker->flag & SELECT) 
01009                 marker->flag &= ~SELECT;
01010             else
01011                 marker->flag |= SELECT;
01012             select = 1;
01013         }
01014     }
01015 }
01016 
01017 static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
01018 {
01019     ListBase *markers= ED_context_get_markers(C);
01020     View2D *v2d= UI_view2d_fromcontext(C);
01021     float viewx;
01022     int x, y, cfra;
01023     
01024     if (markers == NULL)
01025         return OPERATOR_PASS_THROUGH;
01026 
01027     x= evt->x - CTX_wm_region(C)->winrct.xmin;
01028     y= evt->y - CTX_wm_region(C)->winrct.ymin;
01029     
01030     UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);  
01031     
01032     cfra= ED_markers_find_nearest_marker_time(markers, viewx);
01033     
01034     if (extend)
01035         select_timeline_marker_frame(markers, cfra, 1);
01036     else
01037         select_timeline_marker_frame(markers, cfra, 0);
01038     
01039 #ifdef DURIAN_CAMERA_SWITCH
01040 
01041     if (camera) {
01042         Scene *scene= CTX_data_scene(C);
01043         Base *base;
01044         TimeMarker *marker;
01045         int sel= 0;
01046         
01047         if (!extend)
01048             scene_deselect_all(scene);
01049         
01050         for (marker= markers->first; marker; marker= marker->next) {
01051             if(marker->frame==cfra) {
01052                 sel= (marker->flag & SELECT);
01053                 break;
01054             }
01055         }
01056         
01057         for (marker= markers->first; marker; marker= marker->next) {
01058             if (marker->camera) {
01059                 if (marker->frame==cfra) {
01060                     base= object_in_scene(marker->camera, scene);
01061                     if (base) {
01062                         ED_base_object_select(base, sel);
01063                         if(sel)
01064                             ED_base_object_activate(C, base);
01065                     }
01066                 }
01067             }
01068         }
01069         
01070         WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
01071     }
01072 #else
01073     (void)camera;
01074 #endif
01075 
01076     WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
01077     WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
01078 
01079     /* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */
01080     return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
01081 }
01082 
01083 static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt)
01084 {
01085     short extend= RNA_boolean_get(op->ptr, "extend");
01086     short camera= 0;
01087 #ifdef DURIAN_CAMERA_SWITCH
01088     camera= RNA_boolean_get(op->ptr, "camera");
01089 #endif
01090     return ed_marker_select(C, evt, extend, camera);
01091 }
01092 
01093 static int ed_marker_select_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
01094 {
01095     return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_select_invoke);
01096 }
01097 
01098 static void MARKER_OT_select(wmOperatorType *ot)
01099 {
01100     /* identifiers */
01101     ot->name= "Select Time Marker";
01102     ot->description= "Select time marker(s)";
01103     ot->idname= "MARKER_OT_select";
01104     
01105     /* api callbacks */
01106     ot->invoke= ed_marker_select_invoke_wrapper;
01107     ot->poll= ed_markers_poll_markers_exist;
01108     
01109     /* flags */
01110     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01111 
01112     RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection");
01113 #ifdef DURIAN_CAMERA_SWITCH
01114     RNA_def_boolean(ot->srna, "camera", 0, "Camera", "Select the camera");
01115 #endif
01116 }
01117 
01118 /* *************************** border select markers **************** */
01119 
01120 /* operator state vars used: (added by default WM callbacks)   
01121     xmin, ymin     
01122     xmax, ymax     
01123 
01124 customdata: the wmGesture pointer, with subwindow
01125 
01126 callbacks:
01127 
01128     exec()  has to be filled in by user
01129 
01130     invoke() default WM function
01131             adds modal handler
01132 
01133     modal() default WM function 
01134             accept modal events while doing it, calls exec(), handles ESC and border drawing
01135 
01136     poll()  has to be filled in by user for context
01137 */
01138 
01139 static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
01140 {
01141     View2D *v2d= UI_view2d_fromcontext(C);
01142     ListBase *markers= ED_context_get_markers(C);
01143     TimeMarker *marker;
01144     float xminf, xmaxf, yminf, ymaxf;
01145     int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
01146     int xmin= RNA_int_get(op->ptr, "xmin");
01147     int xmax= RNA_int_get(op->ptr, "xmax");
01148     int ymin= RNA_int_get(op->ptr, "ymin");
01149     int ymax= RNA_int_get(op->ptr, "ymax");
01150     int extend= RNA_boolean_get(op->ptr, "extend");
01151     
01152     UI_view2d_region_to_view(v2d, xmin, ymin, &xminf, &yminf);  
01153     UI_view2d_region_to_view(v2d, xmax, ymax, &xmaxf, &ymaxf);  
01154     
01155     if (markers == NULL)
01156         return 0;
01157     
01158     /* XXX marker context */
01159     for (marker= markers->first; marker; marker= marker->next) {
01160         if ((marker->frame > xminf) && (marker->frame <= xmaxf)) {
01161             switch (gesture_mode) {
01162                 case GESTURE_MODAL_SELECT:
01163                     marker->flag |= SELECT;
01164                     break;
01165                 case GESTURE_MODAL_DESELECT:
01166                     marker->flag &= ~SELECT;
01167                     break;
01168             }
01169         }
01170         else if (!extend) {
01171             marker->flag &= ~SELECT;
01172         }
01173     }
01174     
01175     WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
01176     WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
01177 
01178     return 1;
01179 }
01180 
01181 static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
01182 {
01183     return ed_markers_opwrap_invoke_custom(C, op, evt, WM_border_select_invoke);
01184 }
01185 
01186 static void MARKER_OT_select_border(wmOperatorType *ot)
01187 {
01188     /* identifiers */
01189     ot->name= "Marker Border select";
01190     ot->description= "Select all time markers using border selection";
01191     ot->idname= "MARKER_OT_select_border";
01192     
01193     /* api callbacks */
01194     ot->exec= ed_marker_border_select_exec;
01195     ot->invoke= ed_marker_select_border_invoke_wrapper;
01196     ot->modal= WM_border_select_modal;
01197     ot->cancel= WM_border_select_cancel;
01198     
01199     ot->poll= ed_markers_poll_markers_exist;
01200     
01201     /* flags */
01202     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01203     
01204     /* rna */
01205     WM_operator_properties_gesture_border(ot, TRUE);
01206 }
01207 
01208 /* *********************** (de)select all ***************** */
01209 
01210 static int ed_marker_select_all_exec(bContext *C, wmOperator *op)
01211 {
01212     ListBase *markers= ED_context_get_markers(C);
01213     TimeMarker *marker;
01214     int action = RNA_enum_get(op->ptr, "action");
01215 
01216     if (markers == NULL)
01217         return OPERATOR_CANCELLED;
01218 
01219     if (action == SEL_TOGGLE) {
01220         action = (ED_markers_get_first_selected(markers) != NULL) ? SEL_DESELECT : SEL_SELECT;
01221     }
01222     
01223     for(marker= markers->first; marker; marker= marker->next) {
01224         switch (action) {
01225         case SEL_SELECT:
01226             marker->flag |= SELECT;
01227             break;
01228         case SEL_DESELECT:
01229             marker->flag &= ~SELECT;
01230             break;
01231         case SEL_INVERT:
01232             marker->flag ^= SELECT;
01233             break;
01234         }
01235     }
01236     
01237     WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
01238     WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
01239 
01240     return OPERATOR_FINISHED;
01241 }
01242 
01243 static void MARKER_OT_select_all(wmOperatorType *ot)
01244 {
01245     /* identifiers */
01246     ot->name= "(De)select all markers";
01247     ot->description= "Change selection of all time markers";
01248     ot->idname= "MARKER_OT_select_all";
01249     
01250     /* api callbacks */
01251     ot->exec= ed_marker_select_all_exec;
01252     ot->invoke = ed_markers_opwrap_invoke;
01253     ot->poll= ed_markers_poll_markers_exist;
01254     
01255     /* flags */
01256     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01257     
01258     /* rna */
01259     WM_operator_properties_select_all(ot);
01260 }
01261 
01262 /* ***************** remove marker *********************** */
01263 
01264 /* remove selected TimeMarkers */
01265 static int ed_marker_delete_exec(bContext *C, wmOperator *UNUSED(op))
01266 {
01267     ListBase *markers= ED_context_get_markers(C);
01268     TimeMarker *marker, *nmarker;
01269     short changed= 0;
01270     
01271     if (markers == NULL)
01272         return OPERATOR_CANCELLED;
01273     
01274     for (marker= markers->first; marker; marker= nmarker) {
01275         nmarker= marker->next;
01276         if (marker->flag & SELECT) {
01277             BLI_freelinkN(markers, marker);
01278             changed= 1;
01279         }
01280     }
01281     
01282     if (changed) {
01283         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
01284         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
01285     }
01286     
01287     return OPERATOR_FINISHED;
01288 }
01289 
01290 static int ed_marker_delete_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
01291 {
01292     // XXX: must we keep these confirmations?
01293     return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_confirm);
01294 }
01295 
01296 static void MARKER_OT_delete(wmOperatorType *ot)
01297 {
01298     /* identifiers */
01299     ot->name= "Delete Markers";
01300     ot->description= "Delete selected time marker(s)";
01301     ot->idname= "MARKER_OT_delete";
01302     
01303     /* api callbacks */
01304     ot->invoke= ed_marker_delete_invoke_wrapper;
01305     ot->exec= ed_marker_delete_exec;
01306     ot->poll= ed_markers_poll_selected_markers;
01307     
01308     /* flags */
01309     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
01310 }
01311 
01312 
01313 /* **************** rename marker ***************** */
01314 
01315 /* rename first selected TimeMarker */
01316 static int ed_marker_rename_exec(bContext *C, wmOperator *op)
01317 {
01318     TimeMarker *marker= ED_markers_get_first_selected(ED_context_get_markers(C));
01319 
01320     if (marker) {
01321         RNA_string_get(op->ptr, "name", marker->name);
01322         
01323         WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
01324         WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
01325         
01326         return OPERATOR_FINISHED;
01327     }
01328     else {
01329         return OPERATOR_CANCELLED;
01330     }
01331 }
01332 
01333 static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
01334 {
01335     /* must initialise the marker name first if there is a marker selected */
01336     TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C));
01337     if (marker)
01338         RNA_string_set(op->ptr, "name", marker->name);
01339     
01340     /* now see if the operator is usable */
01341     return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_props_popup);
01342 }
01343 
01344 static void MARKER_OT_rename(wmOperatorType *ot)
01345 {
01346     /* identifiers */
01347     ot->name= "Rename Marker";
01348     ot->description= "Rename first selected time marker";
01349     ot->idname= "MARKER_OT_rename";
01350     
01351     /* api callbacks */
01352     ot->invoke= ed_marker_rename_invoke_wrapper;
01353     ot->exec= ed_marker_rename_exec;
01354     ot->poll= ed_markers_poll_selected_markers;
01355     
01356     /* flags */
01357     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;  
01358     
01359     /* properties */
01360     ot->prop = RNA_def_string(ot->srna, "name", "RenamedMarker", sizeof(((TimeMarker *)NULL)->name), "Name", "New name for marker");
01361     //RNA_def_boolean(ot->srna, "ensure_unique", 0, "Ensure Unique", "Ensure that new name is unique within collection of markers");
01362 }
01363 
01364 /* **************** make links to scene ***************** */
01365 
01366 static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
01367 {
01368     ListBase *markers= ED_context_get_markers(C);
01369     Scene *scene_to= BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene"));
01370     TimeMarker *marker, *marker_new;
01371 
01372     if (scene_to==NULL) {
01373         BKE_report(op->reports, RPT_ERROR, "Scene not found");
01374         return OPERATOR_CANCELLED;
01375     }
01376 
01377     if (scene_to == CTX_data_scene(C)) {
01378         BKE_report(op->reports, RPT_ERROR, "Can't re-link markers into the same scene");
01379         return OPERATOR_CANCELLED;
01380     }
01381 
01382     /* copy markers */
01383     for (marker= markers->first; marker; marker= marker->next) {
01384         if (marker->flag & SELECT) {
01385             marker_new= MEM_dupallocN(marker);
01386             marker_new->prev= marker_new->next = NULL;
01387             
01388             BLI_addtail(&scene_to->markers, marker_new);
01389         }
01390     }
01391 
01392     return OPERATOR_FINISHED;
01393 }
01394 
01395 static void MARKER_OT_make_links_scene(wmOperatorType *ot)
01396 {
01397     PropertyRNA *prop;
01398 
01399     /* identifiers */
01400     ot->name= "Make Links to Scene";
01401     ot->description= "Copy selected markers to another scene";
01402     ot->idname= "MARKER_OT_make_links_scene";
01403 
01404     /* api callbacks */
01405     ot->exec= ed_marker_make_links_scene_exec;
01406     ot->invoke = ed_markers_opwrap_invoke;
01407     ot->poll= ed_markers_poll_selected_markers;
01408 
01409     /* flags */
01410     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01411 
01412     /* properties */
01413     prop= RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", "");
01414     RNA_def_enum_funcs(prop, RNA_scene_itemf);
01415     ot->prop= prop;
01416 
01417 }
01418 
01419 #ifdef DURIAN_CAMERA_SWITCH
01420 /* ******************************* camera bind marker ***************** */
01421 
01422 static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
01423 {
01424     bScreen *sc= CTX_wm_screen(C);
01425     Scene *scene= CTX_data_scene(C);
01426     Object *ob = CTX_data_active_object(C);
01427     ListBase *markers= ED_context_get_markers(C);
01428     TimeMarker *marker;
01429 
01430     marker= ED_markers_get_first_selected(markers);
01431     if(marker == NULL)
01432         return OPERATOR_CANCELLED;
01433 
01434     marker->camera= ob;
01435 
01436     /* camera may have changes */
01437     scene_camera_switch_update(scene);
01438     BKE_screen_view3d_scene_sync(sc);
01439 
01440     WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
01441     WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
01442     WM_event_add_notifier(C, NC_SCENE|NA_EDITED, scene); /* so we get view3d redraws */
01443 
01444     return OPERATOR_FINISHED;
01445 }
01446 
01447 static void MARKER_OT_camera_bind(wmOperatorType *ot)
01448 {
01449     /* identifiers */
01450     ot->name= "Bind Camera to Markers";
01451     ot->description= "Bind the active camera to selected markers(s)";
01452     ot->idname= "MARKER_OT_camera_bind";
01453 
01454     /* api callbacks */
01455     ot->exec= ed_marker_camera_bind_exec;
01456     ot->invoke = ed_markers_opwrap_invoke;
01457     ot->poll= ed_markers_poll_selected_markers;
01458 
01459     /* flags */
01460     ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
01461 }
01462 #endif
01463 
01464 /* ************************** registration **********************************/
01465 
01466 /* called in screen_ops.c:ED_operatortypes_screen() */
01467 void ED_operatortypes_marker(void)
01468 {
01469     WM_operatortype_append(MARKER_OT_add);
01470     WM_operatortype_append(MARKER_OT_move);
01471     WM_operatortype_append(MARKER_OT_duplicate);
01472     WM_operatortype_append(MARKER_OT_select);
01473     WM_operatortype_append(MARKER_OT_select_border);
01474     WM_operatortype_append(MARKER_OT_select_all);
01475     WM_operatortype_append(MARKER_OT_delete);
01476     WM_operatortype_append(MARKER_OT_rename);
01477     WM_operatortype_append(MARKER_OT_make_links_scene);
01478 #ifdef DURIAN_CAMERA_SWITCH
01479     WM_operatortype_append(MARKER_OT_camera_bind);
01480 #endif
01481 }
01482 
01483 /* called in screen_ops.c:ED_keymap_screen() */
01484 void ED_marker_keymap(wmKeyConfig *keyconf)
01485 {
01486     wmKeyMap *keymap= WM_keymap_find(keyconf, "Markers", 0, 0);
01487     wmKeyMapItem *kmi;
01488     
01489     WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
01490     WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0);
01491     WM_keymap_verify_item(keymap, "MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
01492     WM_keymap_verify_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
01493     kmi = WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0);
01494     RNA_boolean_set(kmi->ptr, "extend", TRUE);
01495 
01496 #ifdef DURIAN_CAMERA_SWITCH
01497     kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
01498     RNA_boolean_set(kmi->ptr, "extend", FALSE);
01499     RNA_boolean_set(kmi->ptr, "camera", TRUE);
01500 
01501     kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
01502     RNA_boolean_set(kmi->ptr, "extend", TRUE);
01503     RNA_boolean_set(kmi->ptr, "camera", TRUE);
01504 #else
01505     (void)kmi;
01506 #endif
01507     
01508     WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
01509     WM_keymap_verify_item(keymap, "MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
01510     WM_keymap_verify_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
01511     WM_keymap_verify_item(keymap, "MARKER_OT_delete", DELKEY, KM_PRESS, 0, 0);
01512     WM_keymap_verify_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
01513     
01514     WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
01515 #ifdef DURIAN_CAMERA_SWITCH
01516     WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);
01517 #endif
01518 }
01519 
01520 /* to be called from animation editor keymaps, see note below */
01521 void ED_marker_keymap_animedit_conflictfree(wmKeyMap *keymap)
01522 {
01523     /* duplicate of some marker-hotkeys but without the bounds checking
01524      * since these are handy to be able to do unrestricted and won't conflict
01525      * with primary function hotkeys (Usability tweak [#27469])
01526      */
01527     WM_keymap_add_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
01528     WM_keymap_add_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
01529 }