2.5:
[blender.git] / source / blender / editors / animation / anim_ops.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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. 
10  *
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.
15  *
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation, Joshua Leung
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <stdlib.h>
30 #include <math.h>
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_action_types.h"
35 #include "DNA_scene_types.h"
36 #include "DNA_screen_types.h"
37 #include "DNA_space_types.h"
38 #include "DNA_windowmanager_types.h"
39
40 #include "BLI_blenlib.h"
41
42 #include "BKE_context.h"
43 #include "BKE_utildefines.h"
44
45 #include "UI_interface.h"
46 #include "UI_view2d.h"
47
48 #include "RNA_access.h"
49 #include "RNA_define.h"
50
51 #include "WM_api.h"
52 #include "WM_types.h"
53
54 #include "ED_anim_api.h"
55 #include "ED_markers.h"
56 #include "ED_screen.h"
57
58 /* ********************** frame change operator ***************************/
59
60 /* Set any flags that are necessary to indicate modal time-changing operation */
61 static int change_frame_init(bContext *C, wmOperator *op)
62 {
63         ScrArea *curarea= CTX_wm_area(C);
64         
65         if (curarea == NULL)
66                 return 0;
67         
68         if (curarea->spacetype == SPACE_TIME) {
69                 SpaceTime *stime= (SpaceTime*)CTX_wm_space_data(C);
70                 
71                 /* timeline displays frame number only when dragging indicator */
72                 // XXX make this more in line with other anim editors?
73                 stime->flag |= TIME_CFRA_NUM;
74         }
75         
76         return 1;
77 }
78
79 /* Set the new frame number */
80 static void change_frame_apply(bContext *C, wmOperator *op)
81 {
82         Scene *scene= CTX_data_scene(C);
83         int cfra;
84         
85         /* get frame, and clamp to MINFRAME */
86         cfra= RNA_int_get(op->ptr, "frame");
87         
88         if (cfra < MINFRAME) cfra= MINFRAME;
89         CFRA= cfra;
90         
91         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
92 }
93
94 /* Clear any temp flags */
95 static void change_frame_exit(bContext *C, wmOperator *op)
96 {
97         ScrArea *curarea= CTX_wm_area(C);
98         
99         if (curarea == NULL)
100                 return;
101         
102         if (curarea->spacetype == SPACE_TIME) {
103                 SpaceTime *stime= (SpaceTime*)CTX_wm_space_data(C);
104                 
105                 /* timeline displays frame number only when dragging indicator */
106                 // XXX make this more in line with other anim editors?
107                 stime->flag &= ~TIME_CFRA_NUM;
108         }
109 }
110
111 /* ---- */
112
113 /* Non-modal callback for running operator without user input */
114 static int change_frame_exec(bContext *C, wmOperator *op)
115 {
116         if (!change_frame_init(C, op))
117                 return OPERATOR_CANCELLED;
118         
119         change_frame_apply(C, op);
120         change_frame_exit(C, op);
121         return OPERATOR_FINISHED;
122 }
123
124 /* ---- */
125
126 /* Get frame from mouse coordinates */
127 static int frame_from_event(bContext *C, wmEvent *event)
128 {
129         ARegion *region= CTX_wm_region(C);
130         float viewx;
131         int x, y;
132         
133         /* convert screen coordinates to region coordinates */
134         x= event->x - region->winrct.xmin;
135         y= event->y - region->winrct.ymin;
136         
137         /* convert from region coordinates to View2D 'tot' space */
138         UI_view2d_region_to_view(&region->v2d, x, y, &viewx, NULL);
139         
140         /* round result to nearest int (frames are ints!) */
141         return (int)floor(viewx+0.5f);
142 }
143
144 /* Modal Operator init */
145 static int change_frame_invoke(bContext *C, wmOperator *op, wmEvent *event)
146 {
147         /* Change to frame that mouse is over before adding modal handler,
148          * as user could click on a single frame (jump to frame) as well as
149          * click-dragging over a range (modal scrubbing).
150          */
151         RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
152         
153         change_frame_init(C, op);
154         change_frame_apply(C, op);
155         
156         /* add temp handler */
157         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
158
159         return OPERATOR_RUNNING_MODAL;
160 }
161
162 /* In case modal operator is cancelled */
163 static int change_frame_cancel(bContext *C, wmOperator *op)
164 {
165         change_frame_exit(C, op);
166         return OPERATOR_CANCELLED;
167 }
168
169 /* Modal event handling of frame changing */
170 static int change_frame_modal(bContext *C, wmOperator *op, wmEvent *event)
171 {
172         /* execute the events */
173         switch (event->type) {
174                 case MOUSEMOVE:
175                         RNA_int_set(op->ptr, "frame", frame_from_event(C, event));
176                         change_frame_apply(C, op);
177                         break;
178                         
179                 case LEFTMOUSE:
180                         if (event->val==0) {
181                                 change_frame_exit(C, op);
182                                 return OPERATOR_FINISHED;
183                         }
184                         break;
185         }
186
187         return OPERATOR_RUNNING_MODAL;
188 }
189
190 void ANIM_OT_change_frame(wmOperatorType *ot)
191 {
192         PropertyRNA *prop;
193
194         /* identifiers */
195         ot->name= "Change frame";
196         ot->idname= "ANIM_OT_change_frame";
197         
198         /* api callbacks */
199         ot->exec= change_frame_exec;
200         ot->invoke= change_frame_invoke;
201         ot->cancel= change_frame_cancel;
202         ot->modal= change_frame_modal;
203
204         /* rna */
205         prop= RNA_def_property(ot->srna, "frame", PROP_INT, PROP_NONE);
206 }
207
208 /* ****************** set preview range operator ****************************/
209
210 static int previewrange_define_exec(bContext *C, wmOperator *op)
211 {
212         Scene *scene= CTX_data_scene(C);
213         ARegion *ar= CTX_wm_region(C);
214         float sfra, efra;
215         int xmin, xmax;
216         
217         /* get min/max values from border select rect (already in region coordinates, not screen) */
218         xmin= RNA_int_get(op->ptr, "xmin");
219         xmax= RNA_int_get(op->ptr, "xmax");
220         
221         /* convert min/max values to frames (i.e. region to 'tot' rect) */
222         UI_view2d_region_to_view(&ar->v2d, xmin, 0, &sfra, NULL);
223         UI_view2d_region_to_view(&ar->v2d, xmax, 0, &efra, NULL);
224         
225         /* set start/end frames for preview-range 
226          *      - must clamp within allowable limits
227          *      - end must not be before start (though this won't occur most of the time)
228          */
229         if (sfra < 1) sfra = 1.0f;
230         if (efra < 1) efra = 1.0f;
231         if (efra < sfra) efra= sfra;
232         
233         scene->r.psfra= (int)floor(sfra + 0.5f);
234         scene->r.pefra= (int)floor(efra + 0.5f);
235         
236         return OPERATOR_FINISHED;
237
238
239 void ANIM_OT_previewrange_define(wmOperatorType *ot)
240 {
241         /* identifiers */
242         ot->name= "Set Preview Range";
243         ot->idname= "ANIM_OT_previewrange_define";
244         
245         /* api callbacks */
246         ot->invoke= WM_border_select_invoke;
247         ot->exec= previewrange_define_exec;
248         ot->modal= WM_border_select_modal;
249         
250         ot->poll= ED_operator_areaactive;
251         
252         /* rna */
253                 /* used to define frame range */
254         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
255         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
256                 /* these are not used, but are needed by borderselect gesture operator stuff */
257         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
258         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
259 }
260
261 /* ****************** clear preview range operator ****************************/
262
263 static int previewrange_clear_exec(bContext *C, wmOperator *op)
264 {
265         Scene *scene= CTX_data_scene(C);
266         ScrArea *curarea= CTX_wm_area(C);
267         
268         /* sanity checks */
269         if (ELEM(NULL, scene, curarea))
270                 return OPERATOR_CANCELLED;
271         
272         /* simply clear values */
273         scene->r.psfra= 0;
274         scene->r.pefra= 0;
275         
276         ED_area_tag_redraw(curarea);
277         
278         //BIF_undo_push("Clear Preview Range");
279         
280         return OPERATOR_FINISHED;
281
282
283 void ANIM_OT_previewrange_clear(wmOperatorType *ot)
284 {
285         /* identifiers */
286         ot->name= "Clear Preview Range";
287         ot->idname= "ANIM_OT_previewrange_clear";
288         
289         /* api callbacks */
290         ot->exec= previewrange_clear_exec;
291 }
292
293 /* ****************** time display toggle operator ****************************/
294
295 static int toggle_time_exec(bContext *C, wmOperator *op)
296 {
297         ScrArea *curarea= CTX_wm_area(C);
298         
299         if (curarea == NULL)
300                 return OPERATOR_CANCELLED;
301         
302         /* simply toggle draw frames flag in applicable spaces */
303         // XXX or should relevant spaces define their own version of this?
304         switch (curarea->spacetype) {
305                 case SPACE_TIME: /* TimeLine */
306                 {
307                         SpaceTime *stime= (SpaceTime *)CTX_wm_space_data(C);
308                         stime->flag ^= TIME_DRAWFRAMES;
309                 }
310                         break;
311                 case SPACE_ACTION: /* Action Editor */
312                 {
313                         SpaceAction *saction= (SpaceAction *)CTX_wm_space_data(C);
314                         saction->flag ^= SACTION_DRAWTIME;
315                 }
316                         break;
317                 case SPACE_IPO: /* IPO Editor */
318                 {
319                         SpaceIpo *sipo= (SpaceIpo *)CTX_wm_space_data(C);
320                         sipo->flag ^= SIPO_DRAWTIME;
321                 }
322                         break;
323                 case SPACE_NLA: /* NLA Editor */
324                 {
325                         SpaceNla *snla= (SpaceNla *)CTX_wm_space_data(C);
326                         snla->flag ^= SNLA_DRAWTIME;
327                 }
328                         break;
329                 case SPACE_SEQ: /* Sequencer */
330                 {
331                         SpaceSeq *sseq= (SpaceSeq *)CTX_wm_space_data(C);
332                         sseq->flag ^= SEQ_DRAWFRAMES;
333                 }
334                         break;
335                         
336                 default: /* editor doesn't show frames */
337                         return OPERATOR_CANCELLED; // XXX or should we pass through instead?
338         }
339         
340         ED_area_tag_redraw(curarea);
341         
342         return OPERATOR_FINISHED;
343 }
344
345 void ANIM_OT_toggle_time(wmOperatorType *ot)
346 {
347         /* identifiers */
348         ot->name= "Toggle Frames/Seconds";
349         ot->idname= "ANIM_OT_toggle_time";
350         
351         /* api callbacks */
352         ot->exec= toggle_time_exec;
353 }
354
355 /* ************************** registration **********************************/
356
357 void ED_operatortypes_anim(void)
358 {
359         WM_operatortype_append(ANIM_OT_change_frame);
360         WM_operatortype_append(ANIM_OT_toggle_time);
361         
362         WM_operatortype_append(ANIM_OT_previewrange_define);
363         WM_operatortype_append(ANIM_OT_previewrange_clear);
364 }
365
366 void ED_keymap_anim(wmWindowManager *wm)
367 {
368         ListBase *keymap= WM_keymap_listbase(wm, "Animation", 0, 0);
369         
370                 /* frame management */
371         WM_keymap_verify_item(keymap, "ANIM_OT_change_frame", LEFTMOUSE, KM_PRESS, 0, 0);
372         WM_keymap_verify_item(keymap, "ANIM_OT_toggle_time", TKEY, KM_PRESS, KM_CTRL, 0);
373         
374                 /* preview range */
375         WM_keymap_verify_item(keymap, "ANIM_OT_previewrange_define", PKEY, KM_PRESS, KM_CTRL, 0);
376         WM_keymap_verify_item(keymap, "ANIM_OT_previewrange_clear", PKEY, KM_PRESS, KM_ALT, 0);
377 }