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"
58 #include "BIF_glutil.h"
60 #include "UI_interface.h"
61 #include "UI_interface_icons.h"
62 #include "UI_view2d.h"
63 #include "UI_resources.h"
65 #include "ED_anim_api.h"
66 #include "ED_markers.h"
67 #include "ED_screen.h"
69 #include "ED_numinput.h"
70 #include "ED_object.h"
71 #include "ED_transform.h"
74 /* ************* Marker API **************** */
76 /* helper function for getting the list of markers to work on */
77 static ListBase *context_get_markers(Scene *scene, ScrArea *sa)
79 /* local marker sets... */
81 if (sa->spacetype == SPACE_ACTION) {
82 SpaceAction *saction = (SpaceAction *)sa->spacedata.first;
84 /* local markers can only be shown when there's only a single active action to grab them from
85 * - flag only takes effect when there's an action, otherwise it can get too confusing?
87 if (ELEM(saction->mode, SACTCONT_ACTION, SACTCONT_SHAPEKEY) && (saction->action))
89 if (saction->flag & SACTION_POSEMARKERS_SHOW)
90 return &saction->action->markers;
95 /* default to using the scene's markers */
96 return &scene->markers;
101 /* public API for getting markers from context */
102 ListBase *ED_context_get_markers(const bContext *C)
104 return context_get_markers(CTX_data_scene(C), CTX_wm_area(C));
107 /* public API for getting markers from "animation" context */
108 ListBase *ED_animcontext_get_markers(const bAnimContext *ac)
111 return context_get_markers(ac->scene, ac->sa);
116 /* --------------------------------- */
118 /* Apply some transformation to markers after the fact
119 * < markers: list of markers to affect - this may or may not be the scene markers list, so don't assume anything
120 * < scene: current scene (for getting current frame)
121 * < mode: (TfmMode) transform mode that this transform is for
122 * < value: from the transform code, this is t->vec[0] (which is delta transform for grab/extend, and scale factor for scale)
123 * < side: (B/L/R) for 'extend' functionality, which side of current frame to use
125 int ED_markers_post_apply_transform (ListBase *markers, Scene *scene, int mode, float value, char side)
128 float cfra = (float)CFRA;
135 /* affect selected markers - it's unlikely that we will want to affect all in this way? */
136 for (marker = markers->first; marker; marker = marker->next) {
137 if (marker->flag & SELECT) {
139 case TFM_TIME_TRANSLATE:
140 case TFM_TIME_EXTEND:
142 /* apply delta if marker is on the right side of the current frame */
144 (side=='L' && marker->frame < cfra) ||
145 (side=='R' && marker->frame >= cfra))
147 marker->frame += (int)floorf(value + 0.5f);
155 /* rescale the distance between the marker and the current frame */
156 marker->frame= cfra + (int)floorf(((float)(marker->frame - cfra) * value) + 0.5f);
167 /* --------------------------------- */
169 /* Get the marker that is closest to this point */
170 /* XXX for select, the min_dist should be small */
171 TimeMarker *ED_markers_find_nearest_marker (ListBase *markers, float x)
173 TimeMarker *marker, *nearest=NULL;
174 float dist, min_dist= 1000000;
177 for (marker= markers->first; marker; marker= marker->next) {
178 dist = ABS((float)marker->frame - x);
180 if (dist < min_dist) {
190 /* Return the time of the marker that occurs on a frame closest to the given time */
191 int ED_markers_find_nearest_marker_time (ListBase *markers, float x)
193 TimeMarker *nearest= ED_markers_find_nearest_marker(markers, x);
194 return (nearest) ? (nearest->frame) : (int)floor(x + 0.5f);
198 void ED_markers_get_minmax (ListBase *markers, short sel, float *first, float *last)
205 //printf("markers = %p - %p, %p \n", markers, markers->first, markers->last);
206 if (markers == NULL) {
212 if (markers->first && markers->last) {
213 TimeMarker *fm= markers->first;
214 TimeMarker *lm= markers->last;
216 min= (float)fm->frame;
217 max= (float)lm->frame;
225 /* count how many markers are usable - see later */
227 for (marker= markers->first; marker; marker= marker->next) {
228 if (marker->flag & SELECT)
233 selcount= BLI_countlist(markers);
235 /* if only selected are to be considered, only consider the selected ones
236 * (optimisation for not searching list)
239 for (marker= markers->first; marker; marker= marker->next) {
241 if (marker->flag & SELECT) {
242 if (marker->frame < min)
243 min= (float)marker->frame;
244 if (marker->frame > max)
245 max= (float)marker->frame;
249 if (marker->frame < min)
250 min= (float)marker->frame;
251 if (marker->frame > max)
252 max= (float)marker->frame;
257 /* set the min/max values */
262 /* --------------------------------- */
264 /* Adds a marker to list of cfra elems */
265 static void add_marker_to_cfra_elem(ListBase *lb, TimeMarker *marker, short only_sel)
269 /* should this one only be considered if it is selected? */
270 if ((only_sel) && ((marker->flag & SELECT)==0))
273 /* insertion sort - try to find a previous cfra elem */
274 for (ce= lb->first; ce; ce= ce->next) {
275 if (ce->cfra == marker->frame) {
276 /* do because of double keys */
277 if (marker->flag & SELECT)
278 ce->sel= marker->flag;
281 else if (ce->cfra > marker->frame) break;
284 cen= MEM_callocN(sizeof(CfraElem), "add_to_cfra_elem");
285 if (ce) BLI_insertlinkbefore(lb, ce, cen);
286 else BLI_addtail(lb, cen);
288 cen->cfra= marker->frame;
289 cen->sel= marker->flag;
292 /* This function makes a list of all the markers. The only_sel
293 * argument is used to specify whether only the selected markers
296 void ED_markers_make_cfra_list(ListBase *markers, ListBase *lb, short only_sel)
303 for (marker= markers->first; marker; marker= marker->next)
304 add_marker_to_cfra_elem(lb, marker, only_sel);
307 /* --------------------------------- */
309 /* Get the first selected marker */
310 TimeMarker *ED_markers_get_first_selected(ListBase *markers)
315 for (marker = markers->first; marker; marker = marker->next) {
316 if (marker->flag & SELECT)
324 /* --------------------------------- */
326 /* Print debugging prints of list of markers
327 * 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!
329 void debug_markers_print_list(ListBase *markers)
333 if (markers == NULL) {
334 printf("No markers list to print debug for\n");
338 printf("List of markers follows: -----\n");
340 for (marker = markers->first; marker; marker = marker->next) {
341 printf("\t'%s' on %d at %p with %d\n", marker->name, marker->frame, (void *)marker, marker->flag);
344 printf("End of list ------------------\n");
347 /* ************* Marker Drawing ************ */
349 /* function to draw markers */
350 static void draw_marker(View2D *v2d, TimeMarker *marker, int cfra, int flag)
352 float xpos, ypixels, xscale, yscale;
355 xpos = marker->frame;
357 /* no time correction for framelen! space is drawn with old values */
358 ypixels= v2d->mask.ymax-v2d->mask.ymin;
359 UI_view2d_getscale(v2d, &xscale, &yscale);
361 glScalef(1.0f/xscale, 1.0f, 1.0f);
364 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
366 /* vertical line - dotted */
367 #ifdef DURIAN_CAMERA_SWITCH
368 if ((marker->camera) || (flag & DRAW_MARKERS_LINES))
370 if (flag & DRAW_MARKERS_LINES)
375 if (marker->flag & SELECT)
376 glColor4ub(255, 255, 255, 96);
378 glColor4ub(0, 0, 0, 96);
381 glVertex2f((xpos*xscale)+0.5f, 12.0f);
382 glVertex2f((xpos*xscale)+0.5f, (v2d->cur.ymax+12.0f)*yscale);
388 /* 5 px to offset icon to align properly, space / pixels corrects for zoom */
389 if (flag & DRAW_MARKERS_LOCAL) {
390 icon_id= (marker->flag & ACTIVE) ? ICON_PMARKER_ACT :
391 (marker->flag & SELECT) ? ICON_PMARKER_SEL :
395 icon_id= (marker->flag & SELECT) ? ICON_MARKER_HLT :
399 UI_icon_draw(xpos*xscale-5.0f, 16.0f, icon_id);
403 /* and the marker name too, shifted slightly to the top-right */
404 if (marker->name && marker->name[0]) {
407 if (marker->flag & SELECT) {
408 UI_ThemeColor(TH_TEXT_HI);
409 x= xpos*xscale + 4.0f;
410 y= (ypixels <= 39.0f)? (ypixels-10.0f) : 29.0f;
413 UI_ThemeColor(TH_TEXT);
414 if((marker->frame <= cfra) && (marker->frame+5 > cfra)) {
415 x= xpos*xscale + 4.0f;
416 y= (ypixels <= 39.0f)? (ypixels - 10.0f) : 29.0f;
419 x= xpos*xscale + 4.0f;
424 #ifdef DURIAN_CAMERA_SWITCH
425 if(marker->camera && (marker->camera->restrictflag & OB_RESTRICT_RENDER)) {
427 glGetFloatv(GL_CURRENT_COLOR, col);
433 UI_DrawString(x, y, marker->name);
436 glScalef(xscale, 1.0f, 1.0f);
439 /* Draw Scene-Markers in time window */
440 void draw_markers_time(const bContext *C, int flag)
442 ListBase *markers= ED_context_get_markers(C);
443 View2D *v2d= UI_view2d_fromcontext(C);
449 /* unselected markers are drawn at the first time */
450 for (marker= markers->first; marker; marker= marker->next) {
451 if ((marker->flag & SELECT) == 0)
452 draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
455 /* selected markers are drawn later */
456 for (marker= markers->first; marker; marker= marker->next) {
457 if (marker->flag & SELECT)
458 draw_marker(v2d, marker, CTX_data_scene(C)->r.cfra, flag);
462 /* ************************ Marker Wrappers API ********************* */
463 /* These wrappers allow marker operators to function within the confines
464 * of standard animation editors, such that they can coexist with the
465 * primary operations of those editors.
468 /* ------------------------ */
470 /* special poll() which checks if there are selected markers first */
471 static int ed_markers_poll_selected_markers(bContext *C)
473 ListBase *markers = ED_context_get_markers(C);
475 /* first things first: markers can only exist in timeline views */
476 if (ED_operator_animview_active(C) == 0)
479 /* check if some marker is selected */
480 return ED_markers_get_first_selected(markers) != NULL;
483 /* special poll() which checks if there are any markers at all first */
484 static int ed_markers_poll_markers_exist(bContext *C)
486 ListBase *markers = ED_context_get_markers(C);
488 /* first things first: markers can only exist in timeline views */
489 if (ED_operator_animview_active(C) == 0)
492 /* list of markers must exist, as well as some markers in it! */
493 return (markers && markers->first);
496 /* ------------------------ */
498 /* Second-tier invoke() callback that performs context validation before running the
499 * "custom"/third-tier invoke() callback supplied as the last arg (which would normally
500 * be the operator's invoke() callback elsewhere)
502 * < invoke_func: (fn(bContext*, wmOperator*, wmEvent*)=int) "standard" invoke function
503 * that operator would otherwise have used. If NULL, the operator's standard
504 * exec() callback will be called instead in the appropriate places.
506 static int ed_markers_opwrap_invoke_custom(bContext *C, wmOperator *op, wmEvent *evt,
507 int (*invoke_func)(bContext*,wmOperator*,wmEvent*))
509 ScrArea *sa = CTX_wm_area(C);
510 int retval = OPERATOR_PASS_THROUGH;
512 /* removed check for Y coord of event, keymap has bounbox now */
514 /* allow operator to run now */
516 retval = invoke_func(C, op, evt);
517 else if (op->type->exec)
518 retval = op->type->exec(C, op);
520 BKE_report(op->reports, RPT_ERROR, "Programming error: operator doesn't actually have code to do anything!");
522 /* return status modifications - for now, make this spacetype dependent as above */
523 if (sa->spacetype != SPACE_TIME) {
524 /* unless successful, must add "pass-through" to let normal operator's have a chance at tackling this event */
525 if (retval != OPERATOR_FINISHED)
526 retval |= OPERATOR_PASS_THROUGH;
532 /* standard wrapper - first-tier invoke() callback to be directly assigned to operator typedata
533 * for operators which don't need any special invoke calls. Any operators with special invoke calls
534 * though will need to implement their own wrapper which calls the second-tier callback themselves
535 * (passing through the custom invoke function they use)
537 static int ed_markers_opwrap_invoke(bContext *C, wmOperator *op, wmEvent *evt)
539 return ed_markers_opwrap_invoke_custom(C, op, evt, NULL);
542 /* ************************** add markers *************************** */
544 /* add TimeMarker at curent frame */
545 static int ed_marker_add(bContext *C, wmOperator *UNUSED(op))
547 ListBase *markers= ED_context_get_markers(C);
549 int frame= CTX_data_scene(C)->r.cfra;
552 return OPERATOR_CANCELLED;
554 /* two markers can't be at the same place */
555 for (marker= markers->first; marker; marker= marker->next) {
556 if (marker->frame == frame)
557 return OPERATOR_CANCELLED;
561 for (marker= markers->first; marker; marker= marker->next)
562 marker->flag &= ~SELECT;
564 marker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
565 marker->flag= SELECT;
566 marker->frame= frame;
567 BLI_snprintf(marker->name, sizeof(marker->name), "F_%02d", frame); // XXX - temp code only
568 BLI_addtail(markers, marker);
570 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
571 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
573 return OPERATOR_FINISHED;
576 static void MARKER_OT_add(wmOperatorType *ot)
579 ot->name= "Add Time Marker";
580 ot->description= "Add a new time marker";
581 ot->idname= "MARKER_OT_add";
584 ot->exec= ed_marker_add;
585 ot->invoke = ed_markers_opwrap_invoke;
586 ot->poll= ED_operator_animview_active;
589 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
592 /* ************************** transform markers *************************** */
595 /* operator state vars used:
600 init() check selection, add customdata with old values and some lookups
602 apply() do the actual movement
604 exit() cleanup, send notifier
606 cancel() to escape from modal
610 exec() calls init, apply, exit
612 invoke() calls init, adds modal handler
614 modal() accept modal events while doing it, ends with apply and exit, or cancel
618 typedef struct MarkerMove {
621 int event_type; /* store invoke-event, to verify */
622 int *oldframe, evtx, firstx;
626 /* copy selection to temp buffer */
627 /* return 0 if not OK */
628 static int ed_marker_move_init(bContext *C, wmOperator *op)
630 ListBase *markers= ED_context_get_markers(C);
636 if(markers == NULL) return 0;
638 for (marker= markers->first; marker; marker= marker->next)
639 if (marker->flag & SELECT) totmark++;
641 if (totmark==0) return 0;
643 op->customdata= mm= MEM_callocN(sizeof(MarkerMove), "Markermove");
644 mm->slink= CTX_wm_space_data(C);
645 mm->markers= markers;
646 mm->oldframe= MEM_callocN(totmark*sizeof(int), "MarkerMove oldframe");
648 initNumInput(&mm->num);
649 mm->num.idx_max = 0; /* one axis */
650 mm->num.flag |= NUM_NO_FRACTION;
651 mm->num.increment = 1.0f;
653 for (a=0, marker= markers->first; marker; marker= marker->next) {
654 if (marker->flag & SELECT) {
655 mm->oldframe[a]= marker->frame;
664 static void ed_marker_move_exit(bContext *C, wmOperator *op)
666 MarkerMove *mm= op->customdata;
669 MEM_freeN(mm->oldframe);
670 MEM_freeN(op->customdata);
671 op->customdata= NULL;
673 /* clear custom header prints */
674 ED_area_headerprint(CTX_wm_area(C), NULL);
677 static int ed_marker_move_invoke(bContext *C, wmOperator *op, wmEvent *evt)
679 if(ed_marker_move_init(C, op)) {
680 MarkerMove *mm= op->customdata;
684 mm->event_type= evt->type;
686 /* add temp handler */
687 WM_event_add_modal_handler(C, op);
689 /* reset frs delta */
690 RNA_int_set(op->ptr, "frames", 0);
692 return OPERATOR_RUNNING_MODAL;
695 return OPERATOR_CANCELLED;
698 static int ed_marker_move_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
700 return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_move_invoke);
703 /* note, init has to be called succesfully */
704 static void ed_marker_move_apply(wmOperator *op)
706 MarkerMove *mm= op->customdata;
710 offs= RNA_int_get(op->ptr, "frames");
711 for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
712 if (marker->flag & SELECT) {
713 marker->frame= mm->oldframe[a] + offs;
720 static void ed_marker_move_cancel(bContext *C, wmOperator *op)
722 RNA_int_set(op->ptr, "frames", 0);
723 ed_marker_move_apply(op);
724 ed_marker_move_exit(C, op);
726 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
727 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
732 static int ed_marker_move_modal(bContext *C, wmOperator *op, wmEvent *evt)
734 Scene *scene= CTX_data_scene(C);
735 MarkerMove *mm= op->customdata;
736 View2D *v2d= UI_view2d_fromcontext(C);
737 TimeMarker *marker, *selmarker=NULL;
743 ed_marker_move_cancel(C, op);
744 return OPERATOR_CANCELLED;
747 /* press = user manually demands transform to be cancelled */
748 if (evt->val == KM_PRESS) {
749 ed_marker_move_cancel(C, op);
750 return OPERATOR_CANCELLED;
752 /* else continue; <--- see if release event should be caught for tweak-end */
758 if (WM_modal_tweak_exit(evt, mm->event_type)) {
759 ed_marker_move_exit(C, op);
760 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
761 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
762 return OPERATOR_FINISHED;
766 if (hasNumInput(&mm->num))
769 dx= v2d->mask.xmax-v2d->mask.xmin;
770 dx= (v2d->cur.xmax-v2d->cur.xmin)/dx;
772 if (evt->x != mm->evtx) { /* XXX maybe init for firsttime */
773 int a, offs, totmark=0;
777 fac= ((float)(evt->x - mm->firstx)*dx);
779 if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND))
780 apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, FPS, 0.1*FPS, 0);
782 apply_keyb_grid(evt->shift, evt->ctrl, &fac, 0.0, 1.0, 0.1, 0 /*was: U.flag & USER_AUTOGRABGRID*/);
785 RNA_int_set(op->ptr, "frames", offs);
786 ed_marker_move_apply(op);
788 /* cruft below is for header print */
789 for (a=0, marker= mm->markers->first; marker; marker= marker->next) {
790 if (marker->flag & SELECT) {
797 /* we print current marker value */
798 if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) {
799 SpaceTime *stime= (SpaceTime *)mm->slink;
800 if (stime->flag & TIME_DRAWFRAMES)
801 BLI_snprintf(str, sizeof(str), "Marker %d offset %d", selmarker->frame, offs);
803 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
805 else if (mm->slink->spacetype == SPACE_ACTION) {
806 SpaceAction *saction= (SpaceAction *)mm->slink;
807 if (saction->flag & SACTION_DRAWTIME)
808 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", FRA2TIME(selmarker->frame), FRA2TIME(offs));
810 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
813 BLI_snprintf(str, sizeof(str), "Marker %.2f offset %.2f", (double)(selmarker->frame), (double)(offs));
817 /* we only print the offset */
818 if (ELEM(mm->slink->spacetype, SPACE_TIME, SPACE_SOUND)) {
819 SpaceTime *stime= (SpaceTime *)mm->slink;
820 if (stime->flag & TIME_DRAWFRAMES)
821 BLI_snprintf(str, sizeof(str), "Marker offset %d ", offs);
823 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
825 else if (mm->slink->spacetype == SPACE_ACTION) {
826 SpaceAction *saction= (SpaceAction *)mm->slink;
827 if (saction->flag & SACTION_DRAWTIME)
828 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", FRA2TIME(offs));
830 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
833 BLI_snprintf(str, sizeof(str), "Marker offset %.2f ", (double)(offs));
837 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
838 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
839 ED_area_headerprint(CTX_wm_area(C), str);
843 if (evt->val==KM_PRESS) {
847 if (handleNumInput(&mm->num, evt))
849 applyNumInput(&mm->num, vec);
850 outputNumInput(&mm->num, str_tx);
852 RNA_int_set(op->ptr, "frames", vec[0]);
853 ed_marker_move_apply(op);
854 // ed_marker_header_update(C, op, str, (int)vec[0]);
855 // strcat(str, str_tx);
856 BLI_snprintf(str, sizeof(str), "Marker offset %s", str_tx);
857 ED_area_headerprint(CTX_wm_area(C), str);
859 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
860 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
864 return OPERATOR_RUNNING_MODAL;
867 static int ed_marker_move_exec(bContext *C, wmOperator *op)
869 if(ed_marker_move_init(C, op)) {
870 ed_marker_move_apply(op);
871 ed_marker_move_exit(C, op);
872 return OPERATOR_FINISHED;
874 return OPERATOR_PASS_THROUGH;
877 static void MARKER_OT_move(wmOperatorType *ot)
880 ot->name= "Move Time Marker";
881 ot->description= "Move selected time marker(s)";
882 ot->idname= "MARKER_OT_move";
885 ot->exec= ed_marker_move_exec;
886 ot->invoke= ed_marker_move_invoke_wrapper;
887 ot->modal= ed_marker_move_modal;
888 ot->poll= ed_markers_poll_selected_markers;
891 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING|OPTYPE_GRAB_POINTER;
894 RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
897 /* ************************** duplicate markers *************************** */
899 /* operator state vars used:
904 apply() do the actual duplicate
908 exec() calls apply, move_exec
910 invoke() calls apply, move_invoke
912 modal() uses move_modal
917 /* duplicate selected TimeMarkers */
918 static void ed_marker_duplicate_apply(bContext *C)
920 ListBase *markers= ED_context_get_markers(C);
921 TimeMarker *marker, *newmarker;
926 /* go through the list of markers, duplicate selected markers and add duplicated copies
927 * to the begining of the list (unselect original markers)
929 for (marker= markers->first; marker; marker= marker->next) {
930 if (marker->flag & SELECT) {
931 /* unselect selected marker */
932 marker->flag &= ~SELECT;
934 /* create and set up new marker */
935 newmarker = MEM_callocN(sizeof(TimeMarker), "TimeMarker");
936 newmarker->flag= SELECT;
937 newmarker->frame= marker->frame;
938 BLI_strncpy(newmarker->name, marker->name, sizeof(marker->name));
940 #ifdef DURIAN_CAMERA_SWITCH
941 newmarker->camera= marker->camera;
944 /* new marker is added to the begining of list */
945 // FIXME: bad ordering!
946 BLI_addhead(markers, newmarker);
951 static int ed_marker_duplicate_exec(bContext *C, wmOperator *op)
953 ed_marker_duplicate_apply(C);
954 ed_marker_move_exec(C, op); /* assumes frs delta set */
956 return OPERATOR_FINISHED;
960 static int ed_marker_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *evt)
962 ed_marker_duplicate_apply(C);
963 return ed_marker_move_invoke(C, op, evt);
966 static int ed_marker_duplicate_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
968 return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_duplicate_invoke);
971 static void MARKER_OT_duplicate(wmOperatorType *ot)
974 ot->name= "Duplicate Time Marker";
975 ot->description= "Duplicate selected time marker(s)";
976 ot->idname= "MARKER_OT_duplicate";
979 ot->exec= ed_marker_duplicate_exec;
980 ot->invoke= ed_marker_duplicate_invoke_wrapper;
981 ot->modal= ed_marker_move_modal;
982 ot->poll= ed_markers_poll_selected_markers;
985 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
988 RNA_def_int(ot->srna, "frames", 0, INT_MIN, INT_MAX, "Frames", "", INT_MIN, INT_MAX);
991 /* ************************** selection ************************************/
993 /* select/deselect TimeMarker at current frame */
994 static void select_timeline_marker_frame(ListBase *markers, int frame, unsigned char shift)
999 for (marker= markers->first; marker; marker= marker->next) {
1000 /* if Shift is not set, then deselect Markers */
1001 if (!shift) marker->flag &= ~SELECT;
1003 /* this way a not-shift select will allways give 1 selected marker */
1004 if ((marker->frame == frame) && (!select)) {
1005 if (marker->flag & SELECT)
1006 marker->flag &= ~SELECT;
1008 marker->flag |= SELECT;
1014 static int ed_marker_select(bContext *C, wmEvent *evt, int extend, int camera)
1016 ListBase *markers= ED_context_get_markers(C);
1017 View2D *v2d= UI_view2d_fromcontext(C);
1021 if (markers == NULL)
1022 return OPERATOR_PASS_THROUGH;
1024 x= evt->x - CTX_wm_region(C)->winrct.xmin;
1025 y= evt->y - CTX_wm_region(C)->winrct.ymin;
1027 UI_view2d_region_to_view(v2d, x, y, &viewx, NULL);
1029 cfra= ED_markers_find_nearest_marker_time(markers, viewx);
1032 select_timeline_marker_frame(markers, cfra, 1);
1034 select_timeline_marker_frame(markers, cfra, 0);
1036 #ifdef DURIAN_CAMERA_SWITCH
1039 Scene *scene= CTX_data_scene(C);
1045 scene_deselect_all(scene);
1047 for (marker= markers->first; marker; marker= marker->next) {
1048 if(marker->frame==cfra) {
1049 sel= (marker->flag & SELECT);
1054 for (marker= markers->first; marker; marker= marker->next) {
1055 if (marker->camera) {
1056 if (marker->frame==cfra) {
1057 base= object_in_scene(marker->camera, scene);
1059 ED_base_object_select(base, sel);
1061 ED_base_object_activate(C, base);
1067 WM_event_add_notifier(C, NC_SCENE|ND_OB_SELECT, scene);
1071 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1072 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1074 /* allowing tweaks, but needs OPERATOR_FINISHED, otherwise renaming fails... [#25987] */
1075 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
1078 static int ed_marker_select_invoke(bContext *C, wmOperator *op, wmEvent *evt)
1080 short extend= RNA_boolean_get(op->ptr, "extend");
1082 #ifdef DURIAN_CAMERA_SWITCH
1083 camera= RNA_boolean_get(op->ptr, "camera");
1085 return ed_marker_select(C, evt, extend, camera);
1088 static int ed_marker_select_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1090 return ed_markers_opwrap_invoke_custom(C, op, evt, ed_marker_select_invoke);
1093 static void MARKER_OT_select(wmOperatorType *ot)
1096 ot->name= "Select Time Marker";
1097 ot->description= "Select time marker(s)";
1098 ot->idname= "MARKER_OT_select";
1101 ot->invoke= ed_marker_select_invoke_wrapper;
1102 ot->poll= ed_markers_poll_markers_exist;
1105 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1107 RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection");
1108 #ifdef DURIAN_CAMERA_SWITCH
1109 RNA_def_boolean(ot->srna, "camera", 0, "Camera", "Select the camera");
1113 /* *************************** border select markers **************** */
1115 /* operator state vars used: (added by default WM callbacks)
1119 customdata: the wmGesture pointer, with subwindow
1123 exec() has to be filled in by user
1125 invoke() default WM function
1128 modal() default WM function
1129 accept modal events while doing it, calls exec(), handles ESC and border drawing
1131 poll() has to be filled in by user for context
1134 static int ed_marker_border_select_exec(bContext *C, wmOperator *op)
1136 View2D *v2d= UI_view2d_fromcontext(C);
1137 ListBase *markers= ED_context_get_markers(C);
1139 float xminf, xmaxf, yminf, ymaxf;
1140 int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
1141 int xmin= RNA_int_get(op->ptr, "xmin");
1142 int xmax= RNA_int_get(op->ptr, "xmax");
1143 int ymin= RNA_int_get(op->ptr, "ymin");
1144 int ymax= RNA_int_get(op->ptr, "ymax");
1146 UI_view2d_region_to_view(v2d, xmin, ymin, &xminf, &yminf);
1147 UI_view2d_region_to_view(v2d, xmax, ymax, &xmaxf, &ymaxf);
1149 if (markers == NULL)
1152 /* XXX marker context */
1153 for (marker= markers->first; marker; marker= marker->next) {
1154 if ((marker->frame > xminf) && (marker->frame <= xmaxf)) {
1155 switch (gesture_mode) {
1156 case GESTURE_MODAL_SELECT:
1157 marker->flag |= SELECT;
1159 case GESTURE_MODAL_DESELECT:
1160 marker->flag &= ~SELECT;
1166 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1167 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1172 static int ed_marker_select_border_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1174 return ed_markers_opwrap_invoke_custom(C, op, evt, WM_border_select_invoke);
1177 static void MARKER_OT_select_border(wmOperatorType *ot)
1180 ot->name= "Marker Border select";
1181 ot->description= "Select all time markers using border selection";
1182 ot->idname= "MARKER_OT_select_border";
1185 ot->exec= ed_marker_border_select_exec;
1186 ot->invoke= ed_marker_select_border_invoke_wrapper;
1187 ot->modal= WM_border_select_modal;
1189 ot->poll= ed_markers_poll_markers_exist;
1192 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1195 WM_operator_properties_gesture_border(ot, FALSE);
1198 /* *********************** (de)select all ***************** */
1200 static int ed_marker_select_all_exec(bContext *C, wmOperator *op)
1202 ListBase *markers= ED_context_get_markers(C);
1204 int action = RNA_enum_get(op->ptr, "action");
1206 if (markers == NULL)
1207 return OPERATOR_CANCELLED;
1209 if (action == SEL_TOGGLE) {
1210 action = (ED_markers_get_first_selected(markers) != NULL) ? SEL_DESELECT : SEL_SELECT;
1213 for(marker= markers->first; marker; marker= marker->next) {
1216 marker->flag |= SELECT;
1219 marker->flag &= ~SELECT;
1222 marker->flag ^= SELECT;
1227 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1228 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1230 return OPERATOR_FINISHED;
1233 static void MARKER_OT_select_all(wmOperatorType *ot)
1236 ot->name= "(De)select all markers";
1237 ot->description= "Change selection of all time markers";
1238 ot->idname= "MARKER_OT_select_all";
1241 ot->exec= ed_marker_select_all_exec;
1242 ot->invoke = ed_markers_opwrap_invoke;
1243 ot->poll= ed_markers_poll_markers_exist;
1246 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1249 WM_operator_properties_select_all(ot);
1252 /* ***************** remove marker *********************** */
1254 /* remove selected TimeMarkers */
1255 static int ed_marker_delete_exec(bContext *C, wmOperator *UNUSED(op))
1257 ListBase *markers= ED_context_get_markers(C);
1258 TimeMarker *marker, *nmarker;
1261 if (markers == NULL)
1262 return OPERATOR_CANCELLED;
1264 for (marker= markers->first; marker; marker= nmarker) {
1265 nmarker= marker->next;
1266 if (marker->flag & SELECT) {
1267 BLI_freelinkN(markers, marker);
1273 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1274 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1277 return OPERATOR_FINISHED;
1280 static int ed_marker_delete_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1282 // XXX: must we keep these confirmations?
1283 return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_confirm);
1286 static void MARKER_OT_delete(wmOperatorType *ot)
1289 ot->name= "Delete Markers";
1290 ot->description= "Delete selected time marker(s)";
1291 ot->idname= "MARKER_OT_delete";
1294 ot->invoke= ed_marker_delete_invoke_wrapper;
1295 ot->exec= ed_marker_delete_exec;
1296 ot->poll= ed_markers_poll_selected_markers;
1299 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1303 /* **************** rename marker ***************** */
1305 /* rename first selected TimeMarker */
1306 static int ed_marker_rename_exec(bContext *C, wmOperator *op)
1308 TimeMarker *marker= ED_markers_get_first_selected(ED_context_get_markers(C));
1311 RNA_string_get(op->ptr, "name", marker->name);
1313 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1314 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1316 return OPERATOR_FINISHED;
1319 return OPERATOR_CANCELLED;
1323 static int ed_marker_rename_invoke_wrapper(bContext *C, wmOperator *op, wmEvent *evt)
1325 /* must initialise the marker name first if there is a marker selected */
1326 TimeMarker *marker = ED_markers_get_first_selected(ED_context_get_markers(C));
1328 RNA_string_set(op->ptr, "name", marker->name);
1330 /* now see if the operator is usable */
1331 return ed_markers_opwrap_invoke_custom(C, op, evt, WM_operator_props_popup);
1334 static void MARKER_OT_rename(wmOperatorType *ot)
1337 ot->name= "Rename Marker";
1338 ot->description= "Rename first selected time marker";
1339 ot->idname= "MARKER_OT_rename";
1342 ot->invoke= ed_marker_rename_invoke_wrapper;
1343 ot->exec= ed_marker_rename_exec;
1344 ot->poll= ed_markers_poll_selected_markers;
1347 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1350 ot->prop = RNA_def_string(ot->srna, "name", "RenamedMarker", sizeof(((TimeMarker *)NULL)->name), "Name", "New name for marker");
1351 //RNA_def_boolean(ot->srna, "ensure_unique", 0, "Ensure Unique", "Ensure that new name is unique within collection of markers");
1354 /* **************** make links to scene ***************** */
1356 static int ed_marker_make_links_scene_exec(bContext *C, wmOperator *op)
1358 ListBase *markers= ED_context_get_markers(C);
1359 Scene *scene_to= BLI_findlink(&CTX_data_main(C)->scene, RNA_enum_get(op->ptr, "scene"));
1360 TimeMarker *marker, *marker_new;
1362 if (scene_to==NULL) {
1363 BKE_report(op->reports, RPT_ERROR, "Scene not found");
1364 return OPERATOR_CANCELLED;
1367 if (scene_to == CTX_data_scene(C)) {
1368 BKE_report(op->reports, RPT_ERROR, "Can't re-link markers into the same scene");
1369 return OPERATOR_CANCELLED;
1373 for (marker= markers->first; marker; marker= marker->next) {
1374 if (marker->flag & SELECT) {
1375 marker_new= MEM_dupallocN(marker);
1376 marker_new->prev= marker_new->next = NULL;
1378 BLI_addtail(&scene_to->markers, marker_new);
1382 return OPERATOR_FINISHED;
1385 static void MARKER_OT_make_links_scene(wmOperatorType *ot)
1390 ot->name= "Make Links to Scene";
1391 ot->description= "Copy selected markers to another scene";
1392 ot->idname= "MARKER_OT_make_links_scene";
1395 ot->exec= ed_marker_make_links_scene_exec;
1396 ot->invoke = ed_markers_opwrap_invoke;
1397 ot->poll= ed_markers_poll_selected_markers;
1400 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1403 prop= RNA_def_enum(ot->srna, "scene", DummyRNA_NULL_items, 0, "Scene", "");
1404 RNA_def_enum_funcs(prop, RNA_scene_itemf);
1409 #ifdef DURIAN_CAMERA_SWITCH
1410 /* ******************************* camera bind marker ***************** */
1412 static int ed_marker_camera_bind_exec(bContext *C, wmOperator *UNUSED(op))
1414 Scene *scene= CTX_data_scene(C);
1415 ListBase *markers= ED_context_get_markers(C);
1418 marker= ED_markers_get_first_selected(markers);
1420 return OPERATOR_CANCELLED;
1422 marker->camera= scene->camera;
1424 WM_event_add_notifier(C, NC_SCENE|ND_MARKERS, NULL);
1425 WM_event_add_notifier(C, NC_ANIMATION|ND_MARKERS, NULL);
1427 return OPERATOR_FINISHED;
1430 static void MARKER_OT_camera_bind(wmOperatorType *ot)
1433 ot->name= "Bind Camera to Markers";
1434 ot->description= "Bind the active camera to selected markers(s)";
1435 ot->idname= "MARKER_OT_camera_bind";
1438 ot->exec= ed_marker_camera_bind_exec;
1439 ot->invoke = ed_markers_opwrap_invoke;
1440 ot->poll= ed_markers_poll_selected_markers;
1443 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1447 /* ************************** registration **********************************/
1449 /* called in screen_ops.c:ED_operatortypes_screen() */
1450 void ED_operatortypes_marker(void)
1452 WM_operatortype_append(MARKER_OT_add);
1453 WM_operatortype_append(MARKER_OT_move);
1454 WM_operatortype_append(MARKER_OT_duplicate);
1455 WM_operatortype_append(MARKER_OT_select);
1456 WM_operatortype_append(MARKER_OT_select_border);
1457 WM_operatortype_append(MARKER_OT_select_all);
1458 WM_operatortype_append(MARKER_OT_delete);
1459 WM_operatortype_append(MARKER_OT_rename);
1460 WM_operatortype_append(MARKER_OT_make_links_scene);
1461 #ifdef DURIAN_CAMERA_SWITCH
1462 WM_operatortype_append(MARKER_OT_camera_bind);
1466 /* called in screen_ops.c:ED_keymap_screen() */
1467 void ED_marker_keymap(wmKeyConfig *keyconf)
1469 wmKeyMap *keymap= WM_keymap_find(keyconf, "Markers", 0, 0);
1472 WM_keymap_verify_item(keymap, "MARKER_OT_add", MKEY, KM_PRESS, 0, 0);
1473 WM_keymap_verify_item(keymap, "MARKER_OT_move", EVT_TWEAK_S, KM_ANY, 0, 0);
1474 WM_keymap_verify_item(keymap, "MARKER_OT_duplicate", DKEY, KM_PRESS, KM_SHIFT, 0);
1475 WM_keymap_verify_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
1476 RNA_boolean_set(WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
1478 #ifdef DURIAN_CAMERA_SWITCH
1479 kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_CTRL, 0);
1480 RNA_boolean_set(kmi->ptr, "camera", 1);
1482 kmi= WM_keymap_add_item(keymap, "MARKER_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
1483 RNA_boolean_set(kmi->ptr, "extend", 1);
1484 RNA_boolean_set(kmi->ptr, "camera", 1);
1487 WM_keymap_verify_item(keymap, "MARKER_OT_select_border", BKEY, KM_PRESS, 0, 0);
1488 WM_keymap_verify_item(keymap, "MARKER_OT_select_all", AKEY, KM_PRESS, 0, 0);
1489 WM_keymap_verify_item(keymap, "MARKER_OT_delete", XKEY, KM_PRESS, 0, 0);
1490 WM_keymap_verify_item(keymap, "MARKER_OT_delete", DELKEY, KM_PRESS, 0, 0);
1491 WM_keymap_verify_item(keymap, "MARKER_OT_rename", MKEY, KM_PRESS, KM_CTRL, 0);
1493 WM_keymap_add_item(keymap, "MARKER_OT_move", GKEY, KM_PRESS, 0, 0);
1494 #ifdef DURIAN_CAMERA_SWITCH
1495 WM_keymap_add_item(keymap, "MARKER_OT_camera_bind", BKEY, KM_PRESS, KM_CTRL, 0);