4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
24 * Contributor(s): Blender Foundation
26 * ***** END GPL LICENSE BLOCK *****
29 /** \file blender/editors/animation/anim_markers.c
30 * \ingroup edanimation
36 #include "MEM_guardedalloc.h"
38 #include "DNA_scene_types.h"
39 #include "DNA_object_types.h"
41 #include "RNA_access.h"
42 #include "RNA_define.h"
43 #include "RNA_enum_types.h"
45 #include "BLI_blenlib.h"
46 #include "BLI_utildefines.h"
48 #include "BKE_context.h"
49 #include "BKE_fcurve.h"
51 #include "BKE_report.h"
52 #include "BKE_scene.h"
53 #include "BKE_screen.h"
59 #include "BIF_glutil.h"
61 #include "UI_interface.h"
62 #include "UI_interface_icons.h"
63 #include "UI_view2d.h"
64 #include "UI_resources.h"
66 #include "ED_anim_api.h"
67 #include "ED_markers.h"
68 #include "ED_screen.h"
70 #include "ED_numinput.h"
71 #include "ED_object.h"
72 #include "ED_transform.h"
75 /* ************* Marker API **************** */
77 /* helper function for getting the list of markers to work on */
78 static ListBase *context_get_markers(Scene *scene, ScrArea *sa)
80 /* local marker sets... */
82 if (sa->spacetype == SPACE_ACTION) {
83 SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
85 /* local markers can only be shown when there's only a single active action to grab them from
86 * - flag only takes effect when there's an action, otherwise it can get too confusing?
88 if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) && (saction->action))
90 if (saction->flag & SACTION_POSEMARKERS_SHOW)
91 return &saction->action->markers;
96 /* default to using the scene's markers */
97 return &scene->markers;
102 /* public API for getting markers from context */
103 ListBase *ED_context_get_markers(const bContext *C)
105 return context_get_markers(CTX_data_scene(C), CTX_wm_area(C));
108 /* public API for getting markers from "animation" context */
109 ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
112 return context_get_markers(ac->scene, ac->sa);
117 /* --------------------------------- */
119 /* Apply some transformation to markers after the fact
120 * < markers: list of markers to affect - this may or may not be the scene markers list, so don't assume anything
121 * < scene: current scene (for getting current frame)
122 * < mode: (TfmMode) transform mode that this transform is for
123 * < value: from the transform code, this is t->vec[0] (which is delta transform for grab/extend, and scale factor for scale)
124 * < side: (B/L/R) for 'extend' functionality, which side of current frame to use
126 int ED_markers_post_apply_transform (ListBase *markers, Scene *scene, int mode, float value, char side)
129 float cfra = (float)CFRA;
136 /* affect selected markers - it's unlikely that we will want to affect all in this way? */
137 for (marker = markers->first; marker; marker = marker->next) {
138 if (marker->flag & SELECT) {
140 case TFM_TIME_TRANSLATE:
141 case TFM_TIME_EXTEND:
143 /* apply delta if marker is on the right side of the current frame */
145 (side=='L' && marker->frame < cfra) ||
146 (side=='R' && marker->frame >= cfra))
148 marker->frame += (int)floorf(value + 0.5f);
156 /* rescale the distance between the marker and the current frame */
157 marker->frame= cfra + (int)floorf(((float)(marker->frame - cfra) * value) + 0.5f);
168 /* --------------------------------- */
170 /* Get the marker that is closest to this point */
171 /* XXX for select, the min_dist should be small */
172 TimeMarker *ED_markers_find_nearest_marker (ListBase *markers, float x)
174 TimeMarker *marker, *nearest=NULL;
175 float dist, min_dist= 1000000;
178 for (marker= markers->first; marker; marker= marker->next) {
179 dist = ABS((float)marker->frame - x);
181 if (dist < min_dist) {
191 /* Return the time of the marker that occurs on a frame closest to the given time */
192 int ED_markers_find_nearest_marker_time (ListBase *markers, float x)
194 TimeMarker *nearest= ED_markers_find_nearest_marker(markers, x);
195 return (nearest) ? (nearest->frame) : (int)floor(x + 0.5f);
199 void ED_markers_get_minmax (ListBase *markers, short sel, float *first, float *last)
206 //printf("markers = %p - %p, %p \n", markers, markers->first, markers->last);
207 if (markers == NULL) {
213 if (markers->first && markers->last) {
214 TimeMarker *fm= markers->first;
215 TimeMarker *lm= markers->last;
217 min= (float)fm->frame;
218 max= (float)lm->frame;
226 /* count how many markers are usable - see later */
228 for (marker= markers->first; marker; marker= marker->next) {
229 if (marker->flag & SELECT)
234 selcount= BLI_countlist(markers);
236 /* if only selected are to be considered, only consider the selected ones
237 * (optimisation for not searching list)
240 for (marker= markers->first; marker; marker= marker->next) {
242 if (marker->flag & SELECT) {
243 if (marker->frame < min)
244 min= (float)marker->frame;
245 if (marker->frame > max)
246 max= (float)marker->frame;
250 if (marker->frame < min)
251 min= (float)marker->frame;
252 if (marker->frame > max)
253 max= (float)marker->frame;
258 /* set the min/max values */
263 /* --------------------------------- */
265 /* Adds a marker to list of cfra elems */
266 static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel)
270 /* should this one only be considered if it is selected? */
271 if ((only_sel) && ((marker->flag & SELECT)==0))
274 /* insertion sort - try to find a previous cfra elem */
275 for (ce= lb->first; ce; ce= ce->next) {
276 if (ce->cfra == marker->frame) {
277 /* do because of double keys */
278 if (marker->flag & SELECT)
279 ce->sel= marker->flag;
282 else if (ce->cfra > marker->frame) break;
285 cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem");
286 if (ce) BLI_insertlinkbefore(lb, ce, cen);
287 else BLI_addtail(lb, cen);
289 cen->cfra= marker->frame;
290 cen->sel= marker->flag;
293 /* This function makes a list of all the markers. The only_sel
294 * argument is used to specify whether only the selected markers
297 void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
304 for (marker= markers->first; marker; marker= marker->next)
305 add_marker_to_cfra_elem(lb, marker, only_sel);
308 /* --------------------------------- */
310 /* Get the first selected marker */
311 TimeMarker *ED_markers_get_first_selected(ListBase *markers)
316 for (marker = markers->first; marker; marker = marker->next) {
317 if (marker->flag & SELECT)
325 /* --------------------------------- */
327 /* Print debugging prints of list of markers
328 * 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!
330 void debug_markers_print_list(ListBase *markers)
334 if (markers == NULL) {
335 printf("No markers list to print debug for\n");
339 printf("List of markers follows: -----\n");
341 for (marker = markers->first; marker; marker = marker->next) {
342 printf("\t'%s' on %d at %p with %d\n", marker->name, marker->frame, (void *)marker, marker->flag);
345 printf("End of list ------------------\n");
348 /* ************* Marker Drawing ************ */
350 /* function to draw markers */
351 static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
353 float xpos, ypixels, xscale, yscale;
356 xpos = marker->frame;
358 /* no time correction for framelen! space is drawn with old values */
359 ypixels= v2d->mask.ymax-v2d->mask.ymin;
360 UI_view2d_getscale(v2d, &xscale, &yscale);
362 glScalef(1.0f/xscale, 1.0f, 1.0f);
365 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
367 /* vertical line - dotted */
368 #ifdef DURIAN_CAMERA_SWITCH
369 if ((marker->camera) || (flag & DRAW_MARKERS_LINES))
371 if (flag & DRAW_MARKERS_LINES)
376 if (marker->flag & SELECT)
377 glColor4ub(255, 255, 255, 96);
379 glColor4ub(0, 0, 0, 96);
382 glVertex2f((xpos*xscale)+0.5f, 12.0f);
383 glVertex2f((xpos*xscale)+0.5f, (v2d->cur.ymax+12.0f)*yscale);
389 /* 5 px to offset icon to align properly, space / pixels corrects for zoom */
390 if (flag & DRAW_MARKERS_LOCAL) {
391 icon_id= (marker->flag & ACTIVE) ? ICON_PMARKER_ACT :
392 (marker->flag & SELECT) ? ICON_PMARKER_SEL :
396 icon_id= (marker->flag & SELECT) ? ICON_MARKER_HLT :
400 UI_icon_draw(xpos*xscale-5.0f, 16.0f, icon_id);
404 /* and the marker name too, shifted slightly to the top-right */
405 if (marker->name && marker->name[0]) {
408 if (marker->flag & SELECT) {
409 UI_ThemeColor(TH_TEXT_HI);
410 x= xpos*xscale + 4.0f;
411 y= (ypixels <= 39.0f)? (ypixels-10.0f) : 29.0f;
414 UI_ThemeColor(TH_TEXT);
415 if((marker->frame <= cfra) && (marker->frame+5 > cfra)) {
416 x= xpos*xscale + 4.0f;
417 y= (ypixels <= 39.0f)? (ypixels - 10.0f) : 29.0f;
420 x= xpos*xscale + 4.0f;
425 #ifdef DURIAN_CAMERA_SWITCH
426 if(marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) {
428 glGetFloatv(GL_CURRENT_COLOR, col);
434 UI_DrawString(x, y, marker->name);
437 glScalef(xscale, 1.0f, 1.0f);
440 /* Draw Scene-Markers in time window */
441 void draw_markers_time(const bContext *C, int flag)
443 ListBase *markers= ED_context_get_markers(C);
444 View2D *v2d= UI_view2d_fromcontext(C);
450 /* unselected markers are drawn at the first time */
451 for (marker= markers->first; marker; marker= marker->next) {
452 if ((marker->flag & SELECT) == 0)
453 draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
456 /* selected markers are drawn later */
457 for (marker= markers->first; marker; marker= marker->next) {
458 if (marker->flag & SELECT)
459 draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
463 /* ************************ Marker Wrappers API ********************* */
464 /* These wrappers allow marker operators to function within the confines
465 * of standard animation editors, such that they can coexist with the
466 * primary operations of those editors.
469 /* ------------------------ */
471 /* special poll() which checks if there are selected markers first */
472 static int ed_markers_poll_selected_markers(bContext *C)
474 ListBase *markers = ED_context_get_markers(C);
476 /* first things first: markers can only exist in timeline views */
477 if (ED_operator_animview_active(C) == 0)
480 /* check if some marker is selected */
481 return ED_markers_get_first_selected(markers) != NULL;
484 /* special poll() which checks if there are any markers at all first */
485 static int ed_markers_poll_markers_exist(bContext *C)
487 ListBase *markers = ED_context_get_markers(C);
489 /* first things first: markers can only exist in timeline views */
490 if (ED_operator_animview_active(C) == 0)
493 /* list of markers must exist, as well as some markers in it! */
494 return (markers && markers->first);
497 /* ------------------------ */
499 /* Second-tier invoke() callback that performs context validation before running the
500 * "custom"/third-tier invoke() callback supplied as the last arg (which would normally
501 * be the operator's invoke() callback elsewhere)
503 * < invoke_func: (fn(bContext*, wmOperator*, wmEvent*)=int) "standard" invoke function
504 * that operator would otherwise have used. If NULL, the operator's standard
505 * exec() callback will be called instead in the appropriate places.
507 static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent *evt,
508 int (*invoke_func)(bContext*,wmOperator*,wmEvent*))
510 ScrArea *sa = CTX_wm_area(C);
511 int retval = OPERATOR_PASS_THROUGH;
513 /* removed check for Y coord of event, keymap has bounbox now */
515 /* allow operator to run now */
517 retval = invoke_func(C, op, evt);
518 else if (op->type->exec)
519 retval = op->type->exec(C, op);
521 BKE_report(op->reports, RPT_ERROR, "Programming error: operator doesn't actually have code to do anything!");
523 /* return status modifications - for now, make this spacetype dependent as above */
524 if (sa->spacetype != SPACE_TIME) {
525 /* unless successful, must add "pass-through" to let normal operator's have a chance at tackling this event */
526 if (retval != OPERATOR_FINISHED)
527 retval |= OPERATOR_PASS_THROUGH;
533 /* standard wrapper - first-tier invoke() callback to be directly assigned to operator typedata
534 * for operators which don't need any special invoke calls. Any operators with special invoke calls
535 * though will need to implement their own wrapper which calls the second-tier callback themselves
536 * (passing through the custom invoke function they use)
538 static int ed_markers_opwrap_invoke(bContext *C, wmOperator *op, wmEvent *evt)
540 return ed_markers_opwrap_invoke_custom(C, op, evt, NULL);
543 /* ************************** add markers *************************** */
545 /* add TimeMarker at curent frame */
546 static int ed_marker_add(bContext *C, wmOperator *UNUSED(op))
548 ListBase *markers= ED_context_get_markers(C);
550 int frame= CTX_data_scene(C)->r.cfra;
553 return OPERATOR_CANCELLED;
555 /* two markers can't be at the same place */
556 for (marker= markers->first; marker; marker= marker->next) {
557 if (marker->frame == frame)
558 return OPERATOR_CANCELLED;
562 for (marker= markers->first; marker; marker= marker->next)
563 marker->flag &= ~SELECT;
565 marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
566 marker->flag= SELECT;
567 marker->frame= frame;
568 BLI_snprintf(marker->name, sizeof(marker->name), "F_%02d", frame); // XXX - temp code only
569 BLI_addtail(markers, marker);
571 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
572 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
574 return OPERATOR_FINISHED;
577 static void MARKER_OT_add(wmOperatorType *ot)
580 ot->name= "Add Time Marker";
581 ot->description= "Add a new time marker";
582 ot->idname= "MARKER_OT_add";
585 ot->exec= ed_marker_add;
586 ot->invoke = ed_markers_opwrap_invoke;
587 ot->poll= ED_operator_animview_active;
590 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
593 /* ************************** transform markers *************************** */
596 /* operator state vars used:
601 init() check selection, add customdata with old values and some lookups
603 apply() do the actual movement
605 exit() cleanup, send notifier
607 cancel() to escape from modal
611 exec() calls init, apply, exit
613 invoke() calls init, adds modal handler
615 modal() accept modal events while doing it, ends with apply and exit, or cancel
619 typedef struct MarkerMove {
622 int event_type; /* store invoke-event, to verify */
623 int *oldframe, evtx, firstx;
627 /* copy selection to temp buffer */
628 /* return 0 if not OK */
629 static int ed_marker_move_init(bContext *C, wmOperator *op)
631 ListBase *markers= ED_context_get_markers(C);
637 if(markers == NULL) return 0;
639 for (marker= markers->first; marker; marker= marker->next)
640 if (marker->flag & SELECT) totmark++;
642 if (totmark==0) return 0;
644 op->customdata= mm= MEM_callocN(sizeof(MarkerMove), "Markermove");
645 mm->slink= CTX_wm_space_data(C);
646 mm->markers= markers;
647 mm->oldframe= MEM_callocN(totmark*sizeof(int), "MarkerMove oldframe");
649 initNumInput(&mm->num);
650 mm->num.idx_max = 0; /* one axis */
651 mm->num.flag |= NUM_NO_FRACTION;
652 mm->num.increment = 1.0f;
654 for (a=0, marker= markers->first; marker; marker= marker->next) {
655 if (marker->flag & SELECT) {
656 mm->oldframe[a]= marker->frame;
665 static void ed_marker_move_exit(bContext *C, wmOperator *op)
667 MarkerMove *mm= op->customdata;
670 MEM_freeN(mm->oldframe);
671 MEM_freeN(op->customdata);
672 op->customdata= NULL;
674 /* clear custom header prints */
675 ED_area_headerprint(CTX_wm_area(C), NULL);
678 static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
680 if(ed_marker_move_init(C, op)) {
681 MarkerMove *mm= op->customdata;
685 mm->event_type= evt->type;
687 /* add temp handler */
688 WM_event_add_modal_handler(C, op);
690 /* reset frs delta */
691 RNA_int_set(op->ptr, "frames", 0);
693 return OPERATOR_RUNNING_MODAL;
696 return OPERATOR_CANCELLED;
699 static int ed_marker_move_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
701 return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_move_invoke);
704 /* note, init has to be called succesfully */
705 static void ed_marker_move_apply(wmOperator *op)
707 MarkerMove *mm= op->customdata;
711 offs= RNA_int_get(op->ptr, "frames");
712 for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
713 if (marker->flag & SELECT) {
714 marker->frame= mm->oldframe[a] + offs;
721 static int ed_marker_move_cancel(bContext *C, wmOperator *op)
723 RNA_int_set(op->ptr, "frames", 0);
724 ed_marker_move_apply(op);
725 ed_marker_move_exit(C, op);
727 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
728 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
730 return OPERATOR_CANCELLED;
735 static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
737 Scene *scene= CTX_data_scene(C);
738 MarkerMove *mm= op->customdata;
739 View2D *v2d= UI_view2d_fromcontext(C);
740 TimeMarker *marker, *selmarker=NULL;
746 ed_marker_move_cancel(C, op);
747 return OPERATOR_CANCELLED;
750 /* press = user manually demands transform to be cancelled */
751 if (evt->val == KM_PRESS) {
752 ed_marker_move_cancel(C, op);
753 return OPERATOR_CANCELLED;
755 /* else continue; <--- see if release event should be caught for tweak-end */
761 if (WM_modal_tweak_exit(evt, mm->event_type)) {
762 ed_marker_move_exit(C, op);
763 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
764 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
765 return OPERATOR_FINISHED;
769 if (hasNumInput(&mm->num))
772 dx= v2d->mask.xmax-v2d->mask.xmin;
773 dx= (v2d->cur.xmax-v2d->cur.xmin)/dx;
775 if (evt->x != mm->evtx) { /* XXX maybe init for firsttime */
776 int a, offs, totmark=0;
780 fac= ((float)(evt->x - mm->firstx)*dx);
782 if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND))
783 apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1*FPS, 0);
785 apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
788 RNA_int_set(op->ptr, "frames", offs);
789 ed_marker_move_apply(op);
791 /* cruft below is for header print */
792 for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
793 if (marker->flag & SELECT) {
800 /* we print current marker value */
801 if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) {
802 SpaceTime *stime= (SpaceTime *)mm->slink;
803 if (stime->flag & TIME_DRAWFRAMES)
804 BLI_snprintf(str, sizeof(str), "Marker %d offset %d", selmarker->frame, offs);
806 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
808 else if (mm->slink->spacetype == SPACE_ACTION) {
809 SpaceAction *saction= (SpaceAction *)mm->slink;
810 if (saction->flag & SACTION_DRAWTIME)
811 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
813 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
816 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
820 /* we only print the offset */
821 if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) {
822 SpaceTime *stime= (SpaceTime *)mm->slink;
823 if (stime->flag & TIME_DRAWFRAMES)
824 BLI_snprintf(str, sizeof(str), "Marker offset %d ", offs);
826 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
828 else if (mm->slink->spacetype == SPACE_ACTION) {
829 SpaceAction *saction= (SpaceAction *)mm->slink;
830 if (saction->flag & SACTION_DRAWTIME)
831 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
833 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
836 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
840 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
841 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
842 ED_area_headerprint(CTX_wm_area(C), str);
846 if (evt->val==KM_PRESS) {
850 if (handleNumInput(&mm->num, evt))
852 applyNumInput(&mm->num, vec);
853 outputNumInput(&mm->num, str_tx);
855 RNA_int_set(op->ptr, "frames", vec[0]);
856 ed_marker_move_apply(op);
857 // ed_marker_header_update(C, op, str, (int)vec[0]);
858 // strcat(str, str_tx);
859 BLI_snprintf(str, sizeof(str), "Marker offset %s", str_tx);
860 ED_area_headerprint(CTX_wm_area(C), str);
862 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
863 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
867 return OPERATOR_RUNNING_MODAL;
870 static int ed_marker_move_exec(bContext *C, wmOperator *op)
872 if(ed_marker_move_init(C, op)) {
873 ed_marker_move_apply(op);
874 ed_marker_move_exit(C, op);
875 return OPERATOR_FINISHED;
877 return OPERATOR_PASS_THROUGH;
880 static void MARKER_OT_move(wmOperatorType *ot)
883 ot->name= "Move Time Marker";
884 ot->description= "Move selected time marker(s)";
885 ot->idname= "MARKER_OT_move";
888 ot->exec= ed_marker_move_exec;
889 ot->invoke= ed_marker_move_invoke_wrapper;
890 ot->modal= ed_marker_move_modal;
891 ot->poll= ed_markers_poll_selected_markers;
892 ot->cancel= ed_marker_move_cancel;
895 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
898 RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
901 /* ************************** duplicate markers *************************** */
903 /* operator state vars used:
908 apply() do the actual duplicate
912 exec() calls apply, move_exec
914 invoke() calls apply, move_invoke
916 modal() uses move_modal
921 /* duplicate selected TimeMarkers */
922 static void ed_marker_duplicate_apply(bContext *C)
924 ListBase *markers= ED_context_get_markers(C);
925 TimeMarker *marker, *newmarker;
930 /* go through the list of markers, duplicate selected markers and add duplicated copies
931 * to the begining of the list (unselect original markers)
933 for (marker= markers->first; marker; marker= marker->next) {
934 if (marker->flag & SELECT) {
935 /* unselect selected marker */
936 marker->flag &= ~SELECT;
938 /* create and set up new marker */
939 newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
940 newmarker->flag= SELECT;
941 newmarker->frame= marker->frame;
942 BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
944 #ifdef DURIAN_CAMERA_SWITCH
945 newmarker->camera= marker->camera;
948 /* new marker is added to the begining of list */
949 // FIXME: bad ordering!
950 BLI_addhead(markers, newmarker);
955 static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
957 ed_marker_duplicate_apply(C);
958 ed_marker_move_exec(C, op); /* assumes frs delta set */
960 return OPERATOR_FINISHED;
964 static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
966 ed_marker_duplicate_apply(C);
967 return ed_marker_move_invoke(C, op, evt);
970 static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
972 return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_duplicate_invoke);
975 static void MARKER_OT_duplicate(wmOperatorType *ot)
978 ot->name= "Duplicate Time Marker";
979 ot->description= "Duplicate selected time marker(s)";
980 ot->idname= "MARKER_OT_duplicate";
983 ot->exec= ed_marker_duplicate_exec;
984 ot->invoke= ed_marker_duplicate_invoke_wrapper;
985 ot->modal= ed_marker_move_modal;
986 ot->poll= ed_markers_poll_selected_markers;
987 ot->cancel= ed_marker_move_cancel;
990 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
993 RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
996 /* ************************** selection ************************************/
998 /* select/deselect TimeMarker at current frame */
999 static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned char shift)
1004 for (marker= markers->first; marker; marker= marker->next) {
1005 /* if Shift is not set, then deselect Markers */
1006 if (!shift) marker->flag &= ~SELECT;
1008 /* this way a not-shift select will allways give 1 selected marker */
1009 if ((marker->frame == frame) && (!select)) {
1010 if (marker->flag & SELECT)
1011 marker->flag &= ~SELECT;
1013 marker->flag |= SELECT;
1019 static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
1021 ListBase *markers= ED_context_get_markers(C);
1022 View2D *v2d= UI_view2d_fromcontext(C);
1026 if (markers == NULL)
1027 return OPERATOR_PASS_THROUGH;
1029 x= evt->x - CTX_wm_region(C)->winrct.xmin;
1030 y= evt->y - CTX_wm_region(C)->winrct.ymin;
1032 UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);
1034 cfra= ED_markers_find_nearest_marker_time(markers, viewx);
1037 select_timeline_marker_frame(markers, cfra, 1);
1039 select_timeline_marker_frame(markers, cfra, 0);
1041 #ifdef DURIAN_CAMERA_SWITCH
1044 Scene *scene= CTX_data_scene(C);
1050 scene_deselect_all(scene);
1052 for (marker= markers->first; marker; marker= marker->next) {
1053 if(marker->frame==cfra) {
1054 sel= (marker->flag & SELECT);
1059 for (marker= markers->first; marker; marker= marker->next) {
1060 if (marker->camera) {
1061 if (marker->frame==cfra) {
1062 base= object_in_scene(marker->camera, scene);
1064 ED_base_object_select(base, sel);
1066 ED_base_object_activate(C, base);
1072 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1076 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1077 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1079 /* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */
1080 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1083 static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt)
1085 short extend= RNA_boolean_get(op->ptr, "extend");
1087 #ifdef DURIAN_CAMERA_SWITCH
1088 camera= RNA_boolean_get(op->ptr, "camera");
1090 return ed_marker_select(C, evt, extend, camera);
1093 static int ed_marker_select_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1095 return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_select_invoke);
1098 static void MARKER_OT_select(wmOperatorType *ot)
1101 ot->name= "Select Time Marker";
1102 ot->description= "Select time marker(s)";
1103 ot->idname= "MARKER_OT_select";
1106 ot->invoke= ed_marker_select_invoke_wrapper;
1107 ot->poll= ed_markers_poll_markers_exist;
1110 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1112 RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection");
1113 #ifdef DURIAN_CAMERA_SWITCH
1114 RNA_def_boolean(ot->srna, "camera", 0, "Camera", "Select the camera");
1118 /* *************************** border select markers **************** */
1120 /* operator state vars used: (added by default WM callbacks)
1124 customdata: the wmGesture pointer, with subwindow
1128 exec() has to be filled in by user
1130 invoke() default WM function
1133 modal() default WM function
1134 accept modal events while doing it, calls exec(), handles ESC and border drawing
1136 poll() has to be filled in by user for context
1139 static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
1141 View2D *v2d= UI_view2d_fromcontext(C);
1142 ListBase *markers= ED_context_get_markers(C);
1144 float xminf, xmaxf, yminf, ymaxf;
1145 int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
1146 int xmin= RNA_int_get(op->ptr, "xmin");
1147 int xmax= RNA_int_get(op->ptr, "xmax");
1148 int ymin= RNA_int_get(op->ptr, "ymin");
1149 int ymax= RNA_int_get(op->ptr, "ymax");
1151 UI_view2d_region_to_view(v2d, xmin, ymin, &xminf, &yminf);
1152 UI_view2d_region_to_view(v2d, xmax, ymax, &xmaxf, &ymaxf);
1154 if (markers == NULL)
1157 /* XXX marker context */
1158 for (marker= markers->first; marker; marker= marker->next) {
1159 if ((marker->frame > xminf) && (marker->frame <= xmaxf)) {
1160 switch (gesture_mode) {
1161 case GESTURE_MODAL_SELECT:
1162 marker->flag |= SELECT;
1164 case GESTURE_MODAL_DESELECT:
1165 marker->flag &= ~SELECT;
1171 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1172 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1177 static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1179 return ed_markers_opwrap_invoke_custom(C, op, evt, WM_border_select_invoke);
1182 static void MARKER_OT_select_border(wmOperatorType *ot)
1185 ot->name= "Marker Border select";
1186 ot->description= "Select all time markers using border selection";
1187 ot->idname= "MARKER_OT_select_border";
1190 ot->exec= ed_marker_border_select_exec;
1191 ot->invoke= ed_marker_select_border_invoke_wrapper;
1192 ot->modal= WM_border_select_modal;
1193 ot->cancel= WM_border_select_cancel;
1195 ot->poll= ed_markers_poll_markers_exist;
1198 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1201 WM_operator_properties_gesture_border(ot, FALSE);
1204 /* *********************** (de)select all ***************** */
1206 static int ed_marker_select_all_exec(bContext *C, wmOperator *op)
1208 ListBase *markers= ED_context_get_markers(C);
1210 int action = RNA_enum_get(op->ptr, "action");
1212 if (markers == NULL)
1213 return OPERATOR_CANCELLED;
1215 if (action == SEL_TOGGLE) {
1216 action = (ED_markers_get_first_selected(markers) != NULL) ? SEL_DESELECT : SEL_SELECT;
1219 for(marker= markers->first; marker; marker= marker->next) {
1222 marker->flag |= SELECT;
1225 marker->flag &= ~SELECT;
1228 marker->flag ^= SELECT;
1233 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1234 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1236 return OPERATOR_FINISHED;
1239 static void MARKER_OT_select_all(wmOperatorType *ot)
1242 ot->name= "(De)select all markers";
1243 ot->description= "Change selection of all time markers";
1244 ot->idname= "MARKER_OT_select_all";
1247 ot->exec= ed_marker_select_all_exec;
1248 ot->invoke = ed_markers_opwrap_invoke;
1249 ot->poll= ed_markers_poll_markers_exist;
1252 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1255 WM_operator_properties_select_all(ot);
1258 /* ***************** remove marker *********************** */
1260 /* remove selected TimeMarkers */
1261 static int ed_marker_delete_exec(bContext *C, wmOperator *UNUSED(op))
1263 ListBase *markers= ED_context_get_markers(C);
1264 TimeMarker *marker, *nmarker;
1267 if (markers == NULL)
1268 return OPERATOR_CANCELLED;
1270 for (marker= markers->first; marker; marker= nmarker) {
1271 nmarker= marker->next;
1272 if (marker->flag & SELECT) {
1273 BLI_freelinkN(markers, marker);
1279 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1280 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1283 return OPERATOR_FINISHED;
1286 static int ed_marker_delete_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1288 // XXX: must we keep these confirmations?
1289 return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_confirm);
1292 static void MARKER_OT_delete(wmOperatorType *ot)
1295 ot->name= "Delete Markers";
1296 ot->description= "Delete selected time marker(s)";
1297 ot->idname= "MARKER_OT_delete";
1300 ot->invoke= ed_marker_delete_invoke_wrapper;
1301 ot->exec= ed_marker_delete_exec;
1302 ot->poll= ed_markers_poll_selected_markers;
1305 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1309 /* **************** rename marker ***************** */
1311 /* rename first selected TimeMarker */
1312 static int ed_marker_rename_exec(bContext *C, wmOperator *op)
1314 TimeMarker *marker= ED_markers_get_first_selected(ED_context_get_markers(C));
1317 RNA_string_get(op->ptr, "name", marker->name);
1319 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1320 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1322 return OPERATOR_FINISHED;
1325 return OPERATOR_CANCELLED;
1329 static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1331 /* must initialise the marker name first if there is a marker selected */
1332 TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C));
1334 RNA_string_set(op->ptr, "name", marker->name);
1336 /* now see if the operator is usable */
1337 return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_props_popup);
1340 static void MARKER_OT_rename(wmOperatorType *ot)
1343 ot->name= "Rename Marker";
1344 ot->description= "Rename first selected time marker";
1345 ot->idname= "MARKER_OT_rename";
1348 ot->invoke= ed_marker_rename_invoke_wrapper;
1349 ot->exec= ed_marker_rename_exec;
1350 ot->poll= ed_markers_poll_selected_markers;
1353 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1356 ot->prop = RNA_def_string(ot->srna, "name", "RenamedMarker", sizeof(((TimeMarker *)NULL)->name), "Name", "New name for marker");
1357 //RNA_def_boolean(ot->srna, "ensure_unique", 0, "Ensure Unique", "Ensure that new name is unique within collection of markers");
1360 /* **************** make links to scene ***************** */
1362 static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
1364 ListBase *markers= ED_context_get_markers(C);
1365 Scene *scene_to= BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene"));
1366 TimeMarker *marker, *marker_new;
1368 if (scene_to==NULL) {
1369 BKE_report(op->reports, RPT_ERROR, "Scene not found");
1370 return OPERATOR_CANCELLED;
1373 if (scene_to == CTX_data_scene(C)) {
1374 BKE_report(op->reports, RPT_ERROR, "Can't re-link markers into the same scene");
1375 return OPERATOR_CANCELLED;
1379 for (marker= markers->first; marker; marker= marker->next) {
1380 if (marker->flag & SELECT) {
1381 marker_new= MEM_dupallocN(marker);
1382 marker_new->prev= marker_new->next = NULL;
1384 BLI_addtail(&scene_to->markers, marker_new);
1388 return OPERATOR_FINISHED;
1391 static void MARKER_OT_make_links_scene(wmOperatorType *ot)
1396 ot->name= "Make Links to Scene";
1397 ot->description= "Copy selected markers to another scene";
1398 ot->idname= "MARKER_OT_make_links_scene";
1401 ot->exec= ed_marker_make_links_scene_exec;
1402 ot->invoke = ed_markers_opwrap_invoke;
1403 ot->poll= ed_markers_poll_selected_markers;
1406 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1409 prop= RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", "");
1410 RNA_def_enum_funcs(prop, RNA_scene_itemf);
1415 #ifdef DURIAN_CAMERA_SWITCH
1416 /* ******************************* camera bind marker ***************** */
1418 static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
1420 bScreen *sc= CTX_wm_screen(C);
1421 Scene *scene= CTX_data_scene(C);
1422 Object *ob = CTX_data_active_object(C);
1423 ListBase *markers= ED_context_get_markers(C);
1426 marker= ED_markers_get_first_selected(markers);
1428 return OPERATOR_CANCELLED;
1432 /* camera may have changes */
1433 scene_camera_switch_update(scene);
1434 BKE_screen_view3d_scene_sync(sc);
1436 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1437 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1438 WM_event_add_notifier(C, NC_SCENE|NA_EDITED, scene); /* so we get view3d redraws */
1440 return OPERATOR_FINISHED;
1443 static void MARKER_OT_camera_bind(wmOperatorType *ot)
1446 ot->name= "Bind Camera to Markers";
1447 ot->description= "Bind the active camera to selected markers(s)";
1448 ot->idname= "MARKER_OT_camera_bind";
1451 ot->exec= ed_marker_camera_bind_exec;
1452 ot->invoke = ed_markers_opwrap_invoke;
1453 ot->poll= ed_markers_poll_selected_markers;
1456 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1460 /* ************************** registration **********************************/
1462 /* called in screen_ops.c:ED_operatortypes_screen() */
1463 void ED_operatortypes_marker(void)
1465 WM_operatortype_append(MARKER_OT_add);
1466 WM_operatortype_append(MARKER_OT_move);
1467 WM_operatortype_append(MARKER_OT_duplicate);
1468 WM_operatortype_append(MARKER_OT_select);
1469 WM_operatortype_append(MARKER_OT_select_border);
1470 WM_operatortype_append(MARKER_OT_select_all);
1471 WM_operatortype_append(MARKER_OT_delete);
1472 WM_operatortype_append(MARKER_OT_rename);
1473 WM_operatortype_append(MARKER_OT_make_links_scene);
1474 #ifdef DURIAN_CAMERA_SWITCH
1475 WM_operatortype_append(MARKER_OT_camera_bind);
1479 /* called in screen_ops.c:ED_keymap_screen() */
1480 void ED_marker_keymap(wmKeyConfig *keyconf)
1482 wmKeyMap *keymap= WM_keymap_find(keyconf, "Markers", 0, 0);
1485 WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
1486 WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0);
1487 WM_keymap_verify_item(keymap, "MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
1488 WM_keymap_verify_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
1489 RNA_boolean_set(WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
1491 #ifdef DURIAN_CAMERA_SWITCH
1492 kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
1493 RNA_boolean_set(kmi->ptr, "camera", 1);
1495 kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
1496 RNA_boolean_set(kmi->ptr, "extend", 1);
1497 RNA_boolean_set(kmi->ptr, "camera", 1);
1500 WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
1501 WM_keymap_verify_item(keymap, "MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
1502 WM_keymap_verify_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
1503 WM_keymap_verify_item(keymap, "MARKER_OT_delete", DELKEY, KM_PRESS, 0, 0);
1504 WM_keymap_verify_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
1506 WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
1507 #ifdef DURIAN_CAMERA_SWITCH
1508 WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);