Bug fix: cutting a sequencer movie strip with sound could crash in some cases.
[blender.git] / source / blender / editors / screen / screen_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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include <math.h>
28 #include <string.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "BLI_math.h"
33 #include "BLI_blenlib.h"
34 #include "BLI_editVert.h"
35 #include "BLI_dlrbTree.h"
36
37 #include "DNA_armature_types.h"
38 #include "DNA_lattice_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_curve_types.h"
41 #include "DNA_scene_types.h"
42 #include "DNA_meta_types.h"
43
44 #include "BKE_context.h"
45 #include "BKE_customdata.h"
46 #include "BKE_main.h"
47 #include "BKE_mesh.h"
48 #include "BKE_report.h"
49 #include "BKE_scene.h"
50 #include "BKE_screen.h"
51 #include "BKE_sound.h"
52
53 #include "WM_api.h"
54 #include "WM_types.h"
55
56 #include "ED_util.h"
57 #include "ED_screen.h"
58 #include "ED_object.h"
59 #include "ED_armature.h"
60 #include "ED_screen_types.h"
61 #include "ED_keyframes_draw.h"
62
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65
66 #include "UI_interface.h"
67
68 #include "wm_window.h"
69
70 #include "screen_intern.h"      /* own module include */
71
72 #define KM_MODAL_CANCEL         1
73 #define KM_MODAL_APPLY          2
74 #define KM_MODAL_STEP10         3
75 #define KM_MODAL_STEP10_OFF     4
76
77 /* ************** Exported Poll tests ********************** */
78
79 int ED_operator_regionactive(bContext *C)
80 {
81         if(CTX_wm_window(C)==NULL) return 0;
82         if(CTX_wm_screen(C)==NULL) return 0;
83         if(CTX_wm_region(C)==NULL) return 0;
84         return 1;
85 }
86
87 int ED_operator_areaactive(bContext *C)
88 {
89         if(CTX_wm_window(C)==NULL) return 0;
90         if(CTX_wm_screen(C)==NULL) return 0;
91         if(CTX_wm_area(C)==NULL) return 0;
92         return 1;
93 }
94
95 int ED_operator_screenactive(bContext *C)
96 {
97         if(CTX_wm_window(C)==NULL) return 0;
98         if(CTX_wm_screen(C)==NULL) return 0;
99         return 1;
100 }
101
102 /* when mouse is over area-edge */
103 int ED_operator_screen_mainwinactive(bContext *C)
104 {
105         if(CTX_wm_window(C)==NULL) return 0;
106         if(CTX_wm_screen(C)==NULL) return 0;
107         if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
108         return 1;
109 }
110
111 int ED_operator_scene_editable(bContext *C)
112 {
113         Scene *scene= CTX_data_scene(C);
114         if(scene && scene->id.lib==NULL)
115                 return 1;
116         return 0;
117 }
118
119 static int ed_spacetype_test(bContext *C, int type)
120 {
121         if(ED_operator_areaactive(C)) {
122                 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
123                 return sl && (sl->spacetype == type);
124         }
125         return 0;
126 }
127
128 int ED_operator_view3d_active(bContext *C)
129 {
130         return ed_spacetype_test(C, SPACE_VIEW3D);
131 }
132
133 int ED_operator_region_view3d_active(bContext *C)
134 {
135         if(CTX_wm_region_view3d(C))
136                 return TRUE;
137
138         CTX_wm_operator_poll_msg_set(C, "expected a view3d region");
139         return FALSE;   
140 }
141
142 /* generic for any view2d which uses anim_ops */
143 int ED_operator_animview_active(bContext *C)
144 {
145         if(ED_operator_areaactive(C)) {
146                 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
147                 if (sl && (ELEM5(sl->spacetype, SPACE_SEQ, SPACE_SOUND, SPACE_ACTION, SPACE_NLA, SPACE_TIME)))
148                         return TRUE;
149         }
150
151         CTX_wm_operator_poll_msg_set(C, "expected an timeline/animation area to be active");
152         return 0;
153 }
154
155 int ED_operator_timeline_active(bContext *C)
156 {
157         return ed_spacetype_test(C, SPACE_TIME);
158 }
159
160 int ED_operator_outliner_active(bContext *C)
161 {
162         return ed_spacetype_test(C, SPACE_OUTLINER);
163 }
164
165 int ED_operator_outliner_active_no_editobject(bContext *C)
166 {
167         if(ed_spacetype_test(C, SPACE_OUTLINER)) {
168                 Object *ob = ED_object_active_context(C);
169                 Object *obedit= CTX_data_edit_object(C);
170                 if(ob && ob == obedit)
171                         return 0;
172                 else
173                         return 1;
174         }
175         return 0;
176 }
177
178 int ED_operator_file_active(bContext *C)
179 {
180         return ed_spacetype_test(C, SPACE_FILE);
181 }
182
183 int ED_operator_action_active(bContext *C)
184 {
185         return ed_spacetype_test(C, SPACE_ACTION);
186 }
187
188 int ED_operator_buttons_active(bContext *C)
189 {
190         return ed_spacetype_test(C, SPACE_BUTS);
191 }
192
193 int ED_operator_node_active(bContext *C)
194 {
195         SpaceNode *snode= CTX_wm_space_node(C);
196         
197         if(snode && snode->edittree)
198                 return 1;
199         
200         return 0;
201 }
202
203 // XXX rename
204 int ED_operator_ipo_active(bContext *C)
205 {
206         return ed_spacetype_test(C, SPACE_IPO);
207 }
208
209 int ED_operator_sequencer_active(bContext *C)
210 {
211         return ed_spacetype_test(C, SPACE_SEQ);
212 }
213
214 int ED_operator_image_active(bContext *C)
215 {
216         return ed_spacetype_test(C, SPACE_IMAGE);
217 }
218
219 int ED_operator_nla_active(bContext *C)
220 {
221         return ed_spacetype_test(C, SPACE_NLA);
222 }
223
224 int ED_operator_logic_active(bContext *C)
225 {
226         return ed_spacetype_test(C, SPACE_LOGIC);
227 }
228
229 int ED_operator_object_active(bContext *C)
230 {
231         Object *ob = ED_object_active_context(C);
232         return ((ob != NULL) && !(ob->restrictflag & OB_RESTRICT_VIEW));
233 }
234
235 int ED_operator_object_active_editable(bContext *C)
236 {
237         Object *ob = ED_object_active_context(C);
238         return ((ob != NULL) && !(ob->id.lib) && !(ob->restrictflag & OB_RESTRICT_VIEW));
239 }
240
241 int ED_operator_object_active_editable_mesh(bContext *C)
242 {
243         Object *ob = ED_object_active_context(C);
244         return ((ob != NULL) && !(ob->id.lib) && !(ob->restrictflag & OB_RESTRICT_VIEW) && ob->type == OB_MESH);
245 }
246
247 int ED_operator_editmesh(bContext *C)
248 {
249         Object *obedit= CTX_data_edit_object(C);
250         if(obedit && obedit->type==OB_MESH)
251                 return NULL != ((Mesh *)obedit->data)->edit_mesh;
252         return 0;
253 }
254
255 int ED_operator_editmesh_view3d(bContext *C)
256 {
257         return ED_operator_editmesh(C) && ED_operator_view3d_active(C);
258 }
259
260 int ED_operator_editmesh_region_view3d(bContext *C)
261 {
262         if(ED_operator_editmesh(C) && CTX_wm_region_view3d(C))
263                 return 1;
264
265         CTX_wm_operator_poll_msg_set(C, "expected a view3d region & editmesh");
266         return 0;
267 }
268
269 int ED_operator_editarmature(bContext *C)
270 {
271         Object *obedit= CTX_data_edit_object(C);
272         if(obedit && obedit->type==OB_ARMATURE)
273                 return NULL != ((bArmature *)obedit->data)->edbo;
274         return 0;
275 }
276
277 int ED_operator_posemode(bContext *C)
278 {
279         Object *obact= CTX_data_active_object(C);
280
281         if ((obact != CTX_data_edit_object(C))) {
282                 Object *obpose;
283                 if((obpose= ED_object_pose_armature(obact))) {
284                         if((obact == obpose) || (obact->mode & OB_MODE_WEIGHT_PAINT)) {
285                                 return 1;
286                         }
287                 }
288         }
289
290         return 0;
291 }
292
293
294 int ED_operator_uvedit(bContext *C)
295 {
296         Object *obedit= CTX_data_edit_object(C);
297         EditMesh *em= NULL;
298         
299         if(obedit && obedit->type==OB_MESH)
300                 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
301         
302         if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE))) {
303                 BKE_mesh_end_editmesh(obedit->data, em);
304                 return 1;
305         }
306         
307         if(obedit)
308                 BKE_mesh_end_editmesh(obedit->data, em);
309         return 0;
310 }
311
312 int ED_operator_uvmap(bContext *C)
313 {
314         Object *obedit= CTX_data_edit_object(C);
315         EditMesh *em= NULL;
316         
317         if(obedit && obedit->type==OB_MESH)
318                 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
319         
320         if(em && (em->faces.first)) {
321                 BKE_mesh_end_editmesh(obedit->data, em);
322                 return 1;
323         }
324         
325         if(obedit)
326                 BKE_mesh_end_editmesh(obedit->data, em);
327         return 0;
328 }
329
330 int ED_operator_editsurfcurve(bContext *C)
331 {
332         Object *obedit= CTX_data_edit_object(C);
333         if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
334                 return NULL != ((Curve *)obedit->data)->editnurb;
335         return 0;
336 }
337
338
339 int ED_operator_editcurve(bContext *C)
340 {
341         Object *obedit= CTX_data_edit_object(C);
342         if(obedit && obedit->type==OB_CURVE)
343                 return NULL != ((Curve *)obedit->data)->editnurb;
344         return 0;
345 }
346
347 int ED_operator_editsurf(bContext *C)
348 {
349         Object *obedit= CTX_data_edit_object(C);
350         if(obedit && obedit->type==OB_SURF)
351                 return NULL != ((Curve *)obedit->data)->editnurb;
352         return 0;
353 }
354
355 int ED_operator_editfont(bContext *C)
356 {
357         Object *obedit= CTX_data_edit_object(C);
358         if(obedit && obedit->type==OB_FONT)
359                 return NULL != ((Curve *)obedit->data)->editfont;
360         return 0;
361 }
362
363 int ED_operator_editlattice(bContext *C)
364 {
365         Object *obedit= CTX_data_edit_object(C);
366         if(obedit && obedit->type==OB_LATTICE)
367                 return NULL != ((Lattice *)obedit->data)->editlatt;
368         return 0;
369 }
370
371 int ED_operator_editmball(bContext *C)
372 {
373         Object *obedit= CTX_data_edit_object(C);
374         if(obedit && obedit->type==OB_MBALL)
375                 return NULL != ((MetaBall *)obedit->data)->editelems;
376         return 0;
377 }
378
379 /* *************************** action zone operator ************************** */
380
381 /* operator state vars used:  
382  none
383  
384  functions:
385  
386  apply() set actionzone event
387  
388  exit() free customdata
389  
390  callbacks:
391  
392  exec() never used
393  
394  invoke() check if in zone  
395  add customdata, put mouseco and area in it
396  add modal handler
397  
398  modal()        accept modal events while doing it
399  call apply() with gesture info, active window, nonactive window
400  call exit() and remove handler when LMB confirm
401  
402  */
403
404 typedef struct sActionzoneData {
405         ScrArea *sa1, *sa2;
406         AZone *az;
407         int x, y, gesture_dir, modifier;
408 } sActionzoneData;
409
410 /* used by other operators too */
411 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
412 {
413         ScrArea *sa= NULL;
414         sa= scr->areabase.first;
415         while(sa) {
416                 if(BLI_in_rcti(&sa->totrct, x, y)) break;
417                 sa= sa->next;
418         }
419         
420         return sa;
421 }
422
423 /* quick poll to save operators to be created and handled */
424 static int actionzone_area_poll(bContext *C)
425 {
426         wmWindow *win= CTX_wm_window(C);
427         ScrArea *sa= CTX_wm_area(C);
428         
429         if(sa && win) {
430                 AZone *az;
431                 int x= win->eventstate->x;
432                 int y= win->eventstate->y;
433                 
434                 for(az= sa->actionzones.first; az; az= az->next)
435                         if(BLI_in_rcti(&az->rect, x, y))
436                                 return 1;
437         }       
438         return 0;
439 }
440
441 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
442 {
443         AZone *az= NULL;
444         
445         for(az= sa->actionzones.first; az; az= az->next) {
446                 if(BLI_in_rcti(&az->rect, x, y)) {
447                         if(az->type == AZONE_AREA) {
448                                 if(isect_point_tri_v2_int(az->x1, az->y1, az->x2, az->y2, x, y)) 
449                                         break;
450                         }
451                         else if(az->type == AZONE_REGION) {
452                                 break;
453                         }
454                 }
455         }
456         
457         return az;
458 }
459
460
461 static void actionzone_exit(wmOperator *op)
462 {
463         if(op->customdata)
464                 MEM_freeN(op->customdata);
465         op->customdata= NULL;
466 }
467
468 /* send EVT_ACTIONZONE event */
469 static void actionzone_apply(bContext *C, wmOperator *op, int type)
470 {
471         wmEvent event;
472         wmWindow *win= CTX_wm_window(C);
473         sActionzoneData *sad= op->customdata;
474         
475         sad->modifier= RNA_int_get(op->ptr, "modifier");
476         
477         event= *(win->eventstate);      /* XXX huh huh? make api call */
478         if(type==AZONE_AREA)
479                 event.type= EVT_ACTIONZONE_AREA;
480         else
481                 event.type= EVT_ACTIONZONE_REGION;
482         event.customdata= op->customdata;
483         event.customdatafree= TRUE;
484         op->customdata= NULL;
485         
486         wm_event_add(win, &event);
487 }
488
489 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
490 {
491         AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
492         sActionzoneData *sad;
493         
494         /* quick escape */
495         if(az==NULL)
496                 return OPERATOR_PASS_THROUGH;
497         
498         /* ok we do the actionzone */
499         sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
500         sad->sa1= CTX_wm_area(C);
501         sad->az= az;
502         sad->x= event->x; sad->y= event->y;
503         
504         /* region azone directly reacts on mouse clicks */
505         if(sad->az->type==AZONE_REGION) {
506                 actionzone_apply(C, op, AZONE_REGION);
507                 actionzone_exit(op);
508                 return OPERATOR_FINISHED;
509         }
510         else {
511                 /* add modal handler */
512                 WM_event_add_modal_handler(C, op);
513                 
514                 return OPERATOR_RUNNING_MODAL;
515         }
516 }
517
518
519 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
520 {
521         sActionzoneData *sad= op->customdata;
522         int deltax, deltay;
523         int mindelta= sad->az->type==AZONE_REGION?1:12;
524         
525         switch(event->type) {
526                 case MOUSEMOVE:
527                         /* calculate gesture direction */
528                         deltax= (event->x - sad->x);
529                         deltay= (event->y - sad->y);
530                         
531                         if(deltay > ABS(deltax))
532                                 sad->gesture_dir= 'n';
533                         else if(deltax > ABS(deltay))
534                                 sad->gesture_dir= 'e';
535                         else if(deltay < -ABS(deltax))
536                                 sad->gesture_dir= 's';
537                         else
538                                 sad->gesture_dir= 'w';
539                         
540                         /* gesture is large enough? */
541                         if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
542                                 
543                                 /* second area, for join */
544                                 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
545                                 /* apply sends event */
546                                 actionzone_apply(C, op, sad->az->type);
547                                 actionzone_exit(op);
548                                 
549                                 return OPERATOR_FINISHED;
550                         }
551                         break;
552                 case ESCKEY:
553                         actionzone_exit(op);
554                         return OPERATOR_CANCELLED;
555                 case LEFTMOUSE:                         
556                         actionzone_exit(op);
557                         return OPERATOR_CANCELLED;
558                         
559         }
560         
561         return OPERATOR_RUNNING_MODAL;
562 }
563
564 static void SCREEN_OT_actionzone(wmOperatorType *ot)
565 {
566         /* identifiers */
567         ot->name= "Handle area action zones";
568         ot->description= "Handle area action zones for mouse actions/gestures";
569         ot->idname= "SCREEN_OT_actionzone";
570         
571         ot->invoke= actionzone_invoke;
572         ot->modal= actionzone_modal;
573         ot->poll= actionzone_area_poll;
574         
575         ot->flag= OPTYPE_BLOCKING;
576         
577         RNA_def_int(ot->srna, "modifier", 0, 0, 2, "modifier", "modifier state", 0, 2);
578 }
579
580 /* ************** swap area operator *********************************** */
581
582 /* operator state vars used:  
583  sa1            start area
584  sa2            area to swap with
585  
586  functions:
587  
588  init()   set custom data for operator, based on actionzone event custom data
589  
590  cancel()       cancel the operator
591  
592  exit() cleanup, send notifier
593  
594  callbacks:
595  
596  invoke() gets called on shift+lmb drag in actionzone
597  call init(), add handler
598  
599  modal()  accept modal events while doing it
600  
601  */
602
603 typedef struct sAreaSwapData {
604         ScrArea *sa1, *sa2;
605 } sAreaSwapData;
606
607 static int area_swap_init(wmOperator *op, wmEvent *event)
608 {
609         sAreaSwapData *sd= NULL;
610         sActionzoneData *sad= event->customdata;
611         
612         if(sad==NULL || sad->sa1==NULL)
613                 return 0;
614         
615         sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
616         sd->sa1= sad->sa1;
617         sd->sa2= sad->sa2;
618         op->customdata= sd;
619         
620         return 1;
621 }
622
623
624 static void area_swap_exit(bContext *C, wmOperator *op)
625 {
626         WM_cursor_restore(CTX_wm_window(C));
627         if(op->customdata)
628                 MEM_freeN(op->customdata);
629         op->customdata= NULL;
630 }
631
632 static int area_swap_cancel(bContext *C, wmOperator *op)
633 {
634         area_swap_exit(C, op);
635         return OPERATOR_CANCELLED;
636 }
637
638 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
639 {
640         
641         if(!area_swap_init(op, event))
642                 return OPERATOR_PASS_THROUGH;
643         
644         /* add modal handler */
645         WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
646         WM_event_add_modal_handler(C, op);
647         
648         return OPERATOR_RUNNING_MODAL;
649         
650 }
651
652 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
653 {
654         sActionzoneData *sad= op->customdata;
655         
656         switch(event->type) {
657                 case MOUSEMOVE:
658                         /* second area, for join */
659                         sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
660                         break;
661                 case LEFTMOUSE: /* release LMB */
662                         if(event->val==KM_RELEASE) {
663                                 if(!sad->sa2 || sad->sa1 == sad->sa2) {
664                                         
665                                         return area_swap_cancel(C, op);
666                                 }
667
668                                 ED_area_tag_redraw(sad->sa1);
669                                 ED_area_tag_redraw(sad->sa2);
670
671                                 ED_area_swapspace(C, sad->sa1, sad->sa2);
672                                 
673                                 area_swap_exit(C, op);
674                                 
675                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
676                                 
677                                 return OPERATOR_FINISHED;
678                         }
679                         break;
680                         
681                 case ESCKEY:
682                         return area_swap_cancel(C, op);
683         }
684         return OPERATOR_RUNNING_MODAL;
685 }
686
687 static void SCREEN_OT_area_swap(wmOperatorType *ot)
688 {
689         ot->name= "Swap areas";
690         ot->description= "Swap selected areas screen positions";
691         ot->idname= "SCREEN_OT_area_swap";
692         
693         ot->invoke= area_swap_invoke;
694         ot->modal= area_swap_modal;
695         ot->poll= ED_operator_areaactive;
696         
697         ot->flag= OPTYPE_BLOCKING;
698 }
699
700 /* *********** Duplicate area as new window operator ****************** */
701
702 /* operator callback */
703 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
704 {
705         wmWindow *newwin, *win;
706         bScreen *newsc, *sc;
707         ScrArea *sa;
708         rcti rect;
709         
710         win= CTX_wm_window(C);
711         sc= CTX_wm_screen(C);
712         sa= CTX_wm_area(C);
713         
714         /* XXX hrmf! */
715         if(event->type==EVT_ACTIONZONE_AREA) {
716                 sActionzoneData *sad= event->customdata;
717                 
718                 if(sad==NULL)
719                         return OPERATOR_PASS_THROUGH;
720                 
721                 sa= sad->sa1;
722         }
723         
724         /*  poll() checks area context, but we don't accept full-area windows */
725         if(sc->full != SCREENNORMAL) {
726                 if(event->type==EVT_ACTIONZONE_AREA)
727                         actionzone_exit(op);
728                 return OPERATOR_CANCELLED;
729         }
730         
731         /* adds window to WM */
732         rect= sa->totrct;
733         BLI_translate_rcti(&rect, win->posx, win->posy);
734         newwin= WM_window_open(C, &rect);
735         
736         /* allocs new screen and adds to newly created window, using window size */
737         newsc= ED_screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
738         newwin->screen= newsc;
739         
740         /* copy area to new screen */
741         area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
742
743         ED_area_tag_redraw((ScrArea *)newsc->areabase.first);
744
745         /* screen, areas init */
746         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
747         
748         if(event->type==EVT_ACTIONZONE_AREA)
749                 actionzone_exit(op);
750         
751         return OPERATOR_FINISHED;
752 }
753
754 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
755 {
756         ot->name= "Duplicate Area into New Window";
757         ot->description= "Duplicate selected area into new window";
758         ot->idname= "SCREEN_OT_area_dupli";
759         
760         ot->invoke= area_dupli_invoke;
761         ot->poll= ED_operator_areaactive;
762 }
763
764
765 /* ************** move area edge operator *********************************** */
766
767 /* operator state vars used:  
768  x, y                           mouse coord near edge
769  delta            movement of edge
770  
771  functions:
772  
773  init()   set default property values, find edge based on mouse coords, test
774  if the edge can be moved, select edges, calculate min and max movement
775  
776  apply()        apply delta on selection
777  
778  exit() cleanup, send notifier
779  
780  cancel() cancel moving
781  
782  callbacks:
783  
784  exec()   execute without any user interaction, based on properties
785  call init(), apply(), exit()
786  
787  invoke() gets called on mouse click near edge
788  call init(), add handler
789  
790  modal()  accept modal events while doing it
791  call apply() with delta motion
792  call exit() and remove handler
793  
794  */
795
796 typedef struct sAreaMoveData {
797         int bigger, smaller, origval, step;
798         char dir;
799 } sAreaMoveData;
800
801 /* helper call to move area-edge, sets limits */
802 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
803 {
804         ScrArea *sa;
805         
806         /* we check all areas and test for free space with MINSIZE */
807         *bigger= *smaller= 100000;
808         
809         for(sa= sc->areabase.first; sa; sa= sa->next) {
810                 if(dir=='h') {
811                         int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
812                         
813                         /* if top or down edge selected, test height */
814                         if(sa->v1->flag && sa->v4->flag)
815                                 *bigger= MIN2(*bigger, y1);
816                         else if(sa->v2->flag && sa->v3->flag)
817                                 *smaller= MIN2(*smaller, y1);
818                 }
819                 else {
820                         int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
821                         
822                         /* if left or right edge selected, test width */
823                         if(sa->v1->flag && sa->v2->flag)
824                                 *bigger= MIN2(*bigger, x1);
825                         else if(sa->v3->flag && sa->v4->flag)
826                                 *smaller= MIN2(*smaller, x1);
827                 }
828         }
829 }
830
831 /* validate selection inside screen, set variables OK */
832 /* return 0: init failed */
833 static int area_move_init (bContext *C, wmOperator *op)
834 {
835         bScreen *sc= CTX_wm_screen(C);
836         ScrEdge *actedge;
837         sAreaMoveData *md;
838         int x, y;
839         
840         /* required properties */
841         x= RNA_int_get(op->ptr, "x");
842         y= RNA_int_get(op->ptr, "y");
843         
844         /* setup */
845         actedge= screen_find_active_scredge(sc, x, y);
846         if(actedge==NULL) return 0;
847         
848         md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
849         op->customdata= md;
850         
851         md->dir= scredge_is_horizontal(actedge)?'h':'v';
852         if(md->dir=='h') md->origval= actedge->v1->vec.y;
853         else md->origval= actedge->v1->vec.x;
854         
855         select_connected_scredge(sc, actedge);
856         /* now all vertices with 'flag==1' are the ones that can be moved. */
857         
858         area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
859         
860         return 1;
861 }
862
863 /* moves selected screen edge amount of delta, used by split & move */
864 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
865 {
866         wmWindow *win= CTX_wm_window(C);
867         bScreen *sc= CTX_wm_screen(C);
868         ScrVert *v1;
869         ScrArea *sa;
870         
871         delta= CLAMPIS(delta, -smaller, bigger);
872         
873         for (v1= sc->vertbase.first; v1; v1= v1->next) {
874                 if (v1->flag) {
875                         /* that way a nice AREAGRID  */
876                         if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
877                                 v1->vec.x= origval + delta;
878                                 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
879                         }
880                         if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
881                                 v1->vec.y= origval + delta;
882                                 
883                                 v1->vec.y+= AREAGRID-1;
884                                 v1->vec.y-= (v1->vec.y % AREAGRID);
885                                 
886                                 /* prevent too small top header */
887                                 if(v1->vec.y > win->sizey-AREAMINY)
888                                         v1->vec.y= win->sizey-AREAMINY;
889                         }
890                 }
891         }
892
893         for(sa= sc->areabase.first; sa; sa= sa->next) {
894                 if(sa->v1->flag || sa->v2->flag || sa->v3->flag || sa->v4->flag)
895                         ED_area_tag_redraw(sa);
896         }
897
898         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); /* redraw everything */
899 }
900
901 static void area_move_apply(bContext *C, wmOperator *op)
902 {
903         sAreaMoveData *md= op->customdata;
904         int delta;
905         
906         delta= RNA_int_get(op->ptr, "delta");
907         area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
908 }
909
910 static void area_move_exit(bContext *C, wmOperator *op)
911 {
912         if(op->customdata)
913                 MEM_freeN(op->customdata);
914         op->customdata= NULL;
915         
916         /* this makes sure aligned edges will result in aligned grabbing */
917         removedouble_scrverts(CTX_wm_screen(C));
918         removedouble_scredges(CTX_wm_screen(C));
919 }
920
921 static int area_move_exec(bContext *C, wmOperator *op)
922 {
923         if(!area_move_init(C, op))
924                 return OPERATOR_CANCELLED;
925         
926         area_move_apply(C, op);
927         area_move_exit(C, op);
928         
929         return OPERATOR_FINISHED;
930 }
931
932 /* interaction callback */
933 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
934 {
935         RNA_int_set(op->ptr, "x", event->x);
936         RNA_int_set(op->ptr, "y", event->y);
937         
938         if(!area_move_init(C, op)) 
939                 return OPERATOR_PASS_THROUGH;
940         
941         /* add temp handler */
942         WM_event_add_modal_handler(C, op);
943         
944         return OPERATOR_RUNNING_MODAL;
945 }
946
947 static int area_move_cancel(bContext *C, wmOperator *op)
948 {
949         
950         RNA_int_set(op->ptr, "delta", 0);
951         area_move_apply(C, op);
952         area_move_exit(C, op);
953         
954         return OPERATOR_CANCELLED;
955 }
956
957 /* modal callback for while moving edges */
958 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
959 {
960         sAreaMoveData *md= op->customdata;
961         int delta, x, y;
962         
963         /* execute the events */
964         switch(event->type) {
965                 case MOUSEMOVE:
966                         
967                         x= RNA_int_get(op->ptr, "x");
968                         y= RNA_int_get(op->ptr, "y");
969                         
970                         delta= (md->dir == 'v')? event->x - x: event->y - y;
971                         if(md->step) delta= delta - (delta % md->step);
972                         RNA_int_set(op->ptr, "delta", delta);
973                         
974                         area_move_apply(C, op);
975                         break;
976                         
977                 case EVT_MODAL_MAP:
978                         
979                         switch (event->val) {
980                                 case KM_MODAL_APPLY:
981                                         area_move_exit(C, op);
982                                         return OPERATOR_FINISHED;
983                                         
984                                 case KM_MODAL_CANCEL:
985                                         return area_move_cancel(C, op);
986                                         
987                                 case KM_MODAL_STEP10:
988                                         md->step= 10;
989                                         break;
990                                 case KM_MODAL_STEP10_OFF:
991                                         md->step= 0;
992                                         break;
993                         }
994         }
995         
996         return OPERATOR_RUNNING_MODAL;
997 }
998
999 static void SCREEN_OT_area_move(wmOperatorType *ot)
1000 {
1001         /* identifiers */
1002         ot->name= "Move area edges";
1003         ot->description= "Move selected area edges";
1004         ot->idname= "SCREEN_OT_area_move";
1005         
1006         ot->exec= area_move_exec;
1007         ot->invoke= area_move_invoke;
1008         ot->cancel= area_move_cancel;
1009         ot->modal= area_move_modal;
1010         ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
1011         
1012         ot->flag= OPTYPE_BLOCKING;
1013         
1014         /* rna */
1015         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1016         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1017         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1018 }
1019
1020 /* ************** split area operator *********************************** */
1021
1022 /* 
1023  operator state vars:  
1024  fac              spit point
1025  dir              direction 'v' or 'h'
1026  
1027  operator customdata:
1028  area                           pointer to (active) area
1029  x, y                   last used mouse pos
1030  (more, see below)
1031  
1032  functions:
1033  
1034  init()   set default property values, find area based on context
1035  
1036  apply()        split area based on state vars
1037  
1038  exit() cleanup, send notifier
1039  
1040  cancel() remove duplicated area
1041  
1042  callbacks:
1043  
1044  exec()   execute without any user interaction, based on state vars
1045  call init(), apply(), exit()
1046  
1047  invoke() gets called on mouse click in action-widget
1048  call init(), add modal handler
1049  call apply() with initial motion
1050  
1051  modal()  accept modal events while doing it
1052  call move-areas code with delta motion
1053  call exit() or cancel() and remove handler
1054  
1055  */
1056
1057 #define SPLIT_STARTED   1
1058 #define SPLIT_PROGRESS  2
1059
1060 typedef struct sAreaSplitData
1061         {
1062                 int x, y;       /* last used mouse position */
1063                 
1064                 int origval;                    /* for move areas */
1065                 int bigger, smaller;    /* constraints for moving new edge */
1066                 int delta;                              /* delta move edge */
1067                 int origmin, origsize;  /* to calculate fac, for property storage */
1068                 
1069                 ScrEdge *nedge;                 /* new edge */
1070                 ScrArea *sarea;                 /* start area */
1071                 ScrArea *narea;                 /* new area */
1072         } sAreaSplitData;
1073
1074 /* generic init, no UI stuff here */
1075 static int area_split_init(bContext *C, wmOperator *op)
1076 {
1077         ScrArea *sa= CTX_wm_area(C);
1078         sAreaSplitData *sd;
1079         int dir;
1080         
1081         /* required context */
1082         if(sa==NULL) return 0;
1083         
1084         /* required properties */
1085         dir= RNA_enum_get(op->ptr, "direction");
1086         
1087         /* minimal size */
1088         if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
1089         if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
1090         
1091         /* custom data */
1092         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
1093         op->customdata= sd;
1094         
1095         sd->sarea= sa;
1096         sd->origsize= dir=='v' ? sa->winx:sa->winy;
1097         sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
1098         
1099         return 1;
1100 }
1101
1102 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
1103 /* used with split operator */
1104 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
1105 {
1106         ScrVert *sav1= sa->v1;
1107         ScrVert *sav2= sa->v2;
1108         ScrVert *sav3= sa->v3;
1109         ScrVert *sav4= sa->v4;
1110         ScrVert *sbv1= sb->v1;
1111         ScrVert *sbv2= sb->v2;
1112         ScrVert *sbv3= sb->v3;
1113         ScrVert *sbv4= sb->v4;
1114         
1115         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
1116                 return screen_findedge(screen, sav1, sav2);
1117         }
1118         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
1119                 return screen_findedge(screen, sav2, sav3);
1120         }
1121         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
1122                 return screen_findedge(screen, sav3, sav4);
1123         }
1124         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
1125                 return screen_findedge(screen, sav1, sav4);
1126         }
1127         
1128         return NULL;
1129 }
1130
1131
1132 /* do the split, return success */
1133 static int area_split_apply(bContext *C, wmOperator *op)
1134 {
1135         bScreen *sc= CTX_wm_screen(C);
1136         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1137         float fac;
1138         int dir;
1139         
1140         fac= RNA_float_get(op->ptr, "factor");
1141         dir= RNA_enum_get(op->ptr, "direction");
1142         
1143         sd->narea= area_split(sc, sd->sarea, dir, fac);
1144         
1145         if(sd->narea) {
1146                 ScrVert *sv;
1147                 
1148                 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
1149                 
1150                 /* select newly created edge, prepare for moving edge */
1151                 for(sv= sc->vertbase.first; sv; sv= sv->next)
1152                         sv->flag = 0;
1153                 
1154                 sd->nedge->v1->flag= 1;
1155                 sd->nedge->v2->flag= 1;
1156                 
1157                 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
1158                 else sd->origval= sd->nedge->v1->vec.x;
1159
1160                 ED_area_tag_redraw(sd->sarea);
1161                 ED_area_tag_redraw(sd->narea);
1162
1163                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1164                 
1165                 return 1;
1166         }               
1167         
1168         return 0;
1169 }
1170
1171 static void area_split_exit(bContext *C, wmOperator *op)
1172 {
1173         if (op->customdata) {
1174                 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1175                 if(sd->sarea) ED_area_tag_redraw(sd->sarea);
1176                 if(sd->narea) ED_area_tag_redraw(sd->narea);
1177
1178                 MEM_freeN(op->customdata);
1179                 op->customdata = NULL;
1180         }
1181         
1182         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1183         
1184         /* this makes sure aligned edges will result in aligned grabbing */
1185         removedouble_scrverts(CTX_wm_screen(C));
1186         removedouble_scredges(CTX_wm_screen(C));
1187 }
1188
1189
1190 /* UI callback, adds new handler */
1191 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1192 {
1193         sAreaSplitData *sd;
1194         
1195         if(event->type==EVT_ACTIONZONE_AREA) {
1196                 sActionzoneData *sad= event->customdata;
1197                 int dir;
1198                 
1199                 if(sad->modifier>0) {
1200                         return OPERATOR_PASS_THROUGH;
1201                 }
1202                 
1203                 /* no full window splitting allowed */
1204                 if(CTX_wm_area(C)->full)
1205                         return OPERATOR_PASS_THROUGH;
1206                 
1207                 /* verify *sad itself */
1208                 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1209                         return OPERATOR_PASS_THROUGH;
1210                 
1211                 /* is this our *sad? if areas not equal it should be passed on */
1212                 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1213                         return OPERATOR_PASS_THROUGH;
1214                 
1215                 /* prepare operator state vars */
1216                 if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
1217                         dir= 'h';
1218                         RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1219                 }
1220                 else {
1221                         dir= 'v';
1222                         RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1223                 }
1224                 RNA_enum_set(op->ptr, "direction", dir);
1225                 
1226                 /* general init, also non-UI case, adds customdata, sets area and defaults */
1227                 if(!area_split_init(C, op))
1228                         return OPERATOR_PASS_THROUGH;
1229                 
1230                 sd= (sAreaSplitData *)op->customdata;
1231                 
1232                 sd->x= event->x;
1233                 sd->y= event->y;
1234                 
1235                 /* do the split */
1236                 if(area_split_apply(C, op)) {
1237                         area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1238                         
1239                         /* add temp handler for edge move or cancel */
1240                         WM_event_add_modal_handler(C, op);
1241                         
1242                         return OPERATOR_RUNNING_MODAL;
1243                 }
1244                 
1245         }
1246         else {
1247                 /* nonmodal for now */
1248                 return op->type->exec(C, op);
1249         }
1250         
1251         return OPERATOR_PASS_THROUGH;
1252 }
1253
1254 /* function to be called outside UI context, or for redo */
1255 static int area_split_exec(bContext *C, wmOperator *op)
1256 {
1257         
1258         if(!area_split_init(C, op))
1259                 return OPERATOR_CANCELLED;
1260         
1261         area_split_apply(C, op);
1262         area_split_exit(C, op);
1263         
1264         return OPERATOR_FINISHED;
1265 }
1266
1267
1268 static int area_split_cancel(bContext *C, wmOperator *op)
1269 {
1270         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1271         
1272         if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1273                 if (CTX_wm_area(C) == sd->narea) {
1274                         CTX_wm_area_set(C, NULL);
1275                         CTX_wm_region_set(C, NULL);
1276                 }
1277                 sd->narea = NULL;
1278         }
1279         area_split_exit(C, op);
1280         
1281         return OPERATOR_CANCELLED;
1282 }
1283
1284 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1285 {
1286         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1287         float fac;
1288         int dir;
1289         
1290         /* execute the events */
1291         switch(event->type) {
1292                 case MOUSEMOVE:
1293                         dir= RNA_enum_get(op->ptr, "direction");
1294                         
1295                         sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1296                         area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1297                         
1298                         fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1299                         RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1300                         break;
1301                         
1302                 case LEFTMOUSE:
1303                         if(event->val==KM_RELEASE) { /* mouse up */
1304                                 area_split_exit(C, op);
1305                                 return OPERATOR_FINISHED;
1306                         }
1307                         break;
1308                 case RIGHTMOUSE: /* cancel operation */
1309                 case ESCKEY:
1310                         return area_split_cancel(C, op);
1311         }
1312         
1313         return OPERATOR_RUNNING_MODAL;
1314 }
1315
1316 static EnumPropertyItem prop_direction_items[] = {
1317 {'h', "HORIZONTAL", 0, "Horizontal", ""},
1318 {'v', "VERTICAL", 0, "Vertical", ""},
1319 {0, NULL, 0, NULL, NULL}};
1320
1321 static void SCREEN_OT_area_split(wmOperatorType *ot)
1322 {
1323         ot->name = "Split area";
1324         ot->description= "Split selected area into new windows";
1325         ot->idname = "SCREEN_OT_area_split";
1326         
1327         ot->exec= area_split_exec;
1328         ot->invoke= area_split_invoke;
1329         ot->modal= area_split_modal;
1330         
1331         ot->poll= ED_operator_areaactive;
1332         ot->flag= OPTYPE_BLOCKING;
1333         
1334         /* rna */
1335         RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1336         RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1337 }
1338
1339
1340
1341 /* ************** scale region edge operator *********************************** */
1342
1343 typedef struct RegionMoveData {
1344         AZone *az;
1345         ARegion *ar;
1346         ScrArea *sa;
1347         int bigger, smaller, origval;
1348         int origx, origy;
1349         int maxsize;
1350         AZEdge edge;
1351         
1352 } RegionMoveData;
1353
1354
1355 static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge)
1356 {
1357         ARegion *ar;
1358         int dist;
1359         
1360         if(edge==AE_RIGHT_TO_TOPLEFT || edge==AE_LEFT_TO_TOPRIGHT) {
1361                 dist = sa->totrct.xmax - sa->totrct.xmin;
1362         } else {        /* AE_BOTTOM_TO_TOPLEFT, AE_TOP_TO_BOTTOMRIGHT */
1363                 dist = sa->totrct.ymax - sa->totrct.ymin;
1364         }
1365         
1366         /* subtractwidth of regions on opposite side 
1367          * prevents dragging regions into other opposite regions */
1368         for (ar=sa->regionbase.first; ar; ar=ar->next)
1369         {
1370                 if (ar == scalear)
1371                         continue;
1372                 
1373                 if (scalear->alignment == RGN_ALIGN_TOP && ar->alignment == RGN_ALIGN_BOTTOM)
1374                         dist -= ar->winy;
1375                 else if (scalear->alignment == RGN_ALIGN_BOTTOM && ar->alignment == RGN_ALIGN_TOP)
1376                         dist -= ar->winy;
1377                 else if (scalear->alignment == RGN_ALIGN_LEFT && ar->alignment == RGN_ALIGN_RIGHT)
1378                         dist -= ar->winx;
1379                 else if (scalear->alignment == RGN_ALIGN_RIGHT && ar->alignment == RGN_ALIGN_LEFT)
1380                         dist -= ar->winx;
1381                 
1382                 /* case of regions in regions, like operator properties panel */
1383                 /* these can sit on top of other regions such as headers, so account for this */
1384                 else if (edge == AE_BOTTOM_TO_TOPLEFT && scalear->alignment & RGN_ALIGN_TOP && ar->alignment == RGN_ALIGN_TOP && ar->regiontype == RGN_TYPE_HEADER)
1385                         dist -= ar->winy;
1386                 else if (edge == AE_TOP_TO_BOTTOMRIGHT && scalear->alignment & RGN_ALIGN_BOTTOM && ar->alignment == RGN_ALIGN_BOTTOM && ar->regiontype == RGN_TYPE_HEADER)
1387                         dist -= ar->winy;
1388         }
1389
1390         return dist;
1391 }
1392
1393 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1394 {
1395         sActionzoneData *sad= event->customdata;
1396         AZone *az;
1397         
1398         if(event->type!=EVT_ACTIONZONE_REGION) {
1399                 BKE_report(op->reports, RPT_ERROR, "Can only scale region size from an action zone");   
1400                 return OPERATOR_CANCELLED;
1401         }
1402         
1403         az = sad->az;
1404         
1405         if(az->ar) {
1406                 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1407                 int maxsize;
1408                 
1409                 op->customdata= rmd;
1410                 
1411                 rmd->az = az;
1412                 rmd->ar= az->ar;
1413                 rmd->sa = sad->sa1;
1414                 rmd->edge= az->edge;
1415                 rmd->origx= event->x;
1416                 rmd->origy= event->y;
1417                 rmd->maxsize = area_max_regionsize(rmd->sa, rmd->ar, rmd->edge);
1418                 
1419                 /* if not set we do now, otherwise it uses type */
1420                 if(rmd->ar->sizex==0) 
1421                         rmd->ar->sizex= rmd->ar->type->prefsizex;
1422                 if(rmd->ar->sizey==0) 
1423                         rmd->ar->sizey= rmd->ar->type->prefsizey;
1424                 
1425                 /* now copy to regionmovedata */
1426                 if(rmd->edge==AE_LEFT_TO_TOPRIGHT || rmd->edge==AE_RIGHT_TO_TOPLEFT) {
1427                         rmd->origval= rmd->ar->sizex;
1428                 } else {
1429                         rmd->origval= rmd->ar->sizey;
1430                 }
1431                 
1432                 /* limit headers to standard height for now */
1433                 if (rmd->ar->regiontype == RGN_TYPE_HEADER)
1434                         maxsize = rmd->ar->type->prefsizey;
1435                 else
1436                         maxsize = 1000;
1437                 
1438                 CLAMP(rmd->maxsize, 0, maxsize);
1439                 
1440                 /* add temp handler */
1441                 WM_event_add_modal_handler(C, op);
1442                 
1443                 return OPERATOR_RUNNING_MODAL;
1444         }
1445         
1446         return OPERATOR_FINISHED;
1447 }
1448
1449 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1450 {
1451         RegionMoveData *rmd= op->customdata;
1452         int delta;
1453         
1454         /* execute the events */
1455         switch(event->type) {
1456                 case MOUSEMOVE:
1457                         
1458                         if(rmd->edge==AE_LEFT_TO_TOPRIGHT || rmd->edge==AE_RIGHT_TO_TOPLEFT) {
1459                                 delta= event->x - rmd->origx;
1460                                 if(rmd->edge==AE_LEFT_TO_TOPRIGHT) delta= -delta;
1461                                 
1462                                 rmd->ar->sizex= rmd->origval + delta;
1463                                 CLAMP(rmd->ar->sizex, 0, rmd->maxsize);
1464                                 
1465                                 if(rmd->ar->sizex < 24) {
1466                                         rmd->ar->sizex= rmd->origval;
1467                                         if(!(rmd->ar->flag & RGN_FLAG_HIDDEN))
1468                                                 ED_region_toggle_hidden(C, rmd->ar);
1469                                 }
1470                                 else if(rmd->ar->flag & RGN_FLAG_HIDDEN)
1471                                         ED_region_toggle_hidden(C, rmd->ar);
1472                         }
1473                         else {
1474                                 int maxsize=0;
1475                                 delta= event->y - rmd->origy;
1476                                 if(rmd->edge==AE_BOTTOM_TO_TOPLEFT) delta= -delta;
1477                                 
1478                                 rmd->ar->sizey= rmd->origval + delta;
1479                                 CLAMP(rmd->ar->sizey, 0, rmd->maxsize);
1480                                 
1481                                 if(rmd->ar->regiontype == RGN_TYPE_TOOL_PROPS)
1482                                         maxsize = rmd->maxsize - ((rmd->sa->headertype==2)?48:24) - 10;
1483
1484                                 if(rmd->ar->sizey < 24 || (maxsize > 0 && (rmd->ar->sizey > maxsize)) ) {
1485                                         rmd->ar->sizey= rmd->origval;
1486                                         if(!(rmd->ar->flag & RGN_FLAG_HIDDEN))
1487                                                 ED_region_toggle_hidden(C, rmd->ar);
1488                                 }
1489                                 else if(rmd->ar->flag & RGN_FLAG_HIDDEN)
1490                                         ED_region_toggle_hidden(C, rmd->ar);
1491                         }
1492                         ED_area_tag_redraw(rmd->sa);
1493                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1494                         
1495                         break;
1496                         
1497                 case LEFTMOUSE:
1498                         if(event->val==KM_RELEASE) {
1499                                 
1500                                 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1501                                         if(rmd->ar->flag & RGN_FLAG_HIDDEN) {
1502                                                 ED_region_toggle_hidden(C, rmd->ar);
1503                                                 ED_area_tag_redraw(rmd->sa);
1504                                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1505                                         }
1506                                 }
1507                                 MEM_freeN(op->customdata);
1508                                 op->customdata = NULL;
1509                                 
1510                                 return OPERATOR_FINISHED;
1511                         }
1512                         break;
1513                         
1514                 case ESCKEY:
1515                         ;
1516         }
1517         
1518         return OPERATOR_RUNNING_MODAL;
1519 }
1520
1521
1522 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1523 {
1524         /* identifiers */
1525         ot->name= "Scale Region Size";
1526         ot->description= "Scale selected area";
1527         ot->idname= "SCREEN_OT_region_scale";
1528         
1529         ot->invoke= region_scale_invoke;
1530         ot->modal= region_scale_modal;
1531         
1532         ot->poll= ED_operator_areaactive;
1533         
1534         ot->flag= OPTYPE_BLOCKING;
1535 }
1536
1537
1538 /* ************** frame change operator ***************************** */
1539
1540 /* function to be called outside UI context, or for redo */
1541 static int frame_offset_exec(bContext *C, wmOperator *op)
1542 {
1543         int delta;
1544         
1545         delta = RNA_int_get(op->ptr, "delta");
1546
1547         CTX_data_scene(C)->r.cfra += delta;
1548         CTX_data_scene(C)->r.subframe = 0.f;
1549         
1550         sound_seek_scene(C);
1551
1552         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1553         
1554         return OPERATOR_FINISHED;
1555 }
1556
1557 static void SCREEN_OT_frame_offset(wmOperatorType *ot)
1558 {
1559         ot->name = "Frame Offset";
1560         ot->idname = "SCREEN_OT_frame_offset";
1561         
1562         ot->exec= frame_offset_exec;
1563         
1564         ot->poll= ED_operator_screenactive;
1565         ot->flag= 0;
1566         
1567         /* rna */
1568         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1569 }
1570
1571
1572 /* function to be called outside UI context, or for redo */
1573 static int frame_jump_exec(bContext *C, wmOperator *op)
1574 {
1575         Scene *scene= CTX_data_scene(C);
1576         wmTimer *animtimer= CTX_wm_screen(C)->animtimer;
1577
1578         /* Don't change CFRA directly if animtimer is running as this can cause
1579          * first/last frame not to be actually shown (bad since for example physics
1580          * simulations aren't reset properly).
1581          */
1582         if(animtimer) {
1583                 ScreenAnimData *sad = animtimer->customdata;
1584                 
1585                 sad->flag |= ANIMPLAY_FLAG_USE_NEXT_FRAME;
1586                 
1587                 if (RNA_boolean_get(op->ptr, "end"))
1588                         sad->nextfra= PEFRA;
1589                 else
1590                         sad->nextfra= PSFRA;
1591         }
1592         else {
1593                 if (RNA_boolean_get(op->ptr, "end"))
1594                         CFRA= PEFRA;
1595                 else
1596                         CFRA= PSFRA;
1597                 
1598                 sound_seek_scene(C);
1599
1600                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1601         }
1602         
1603         return OPERATOR_FINISHED;
1604 }
1605
1606 static void SCREEN_OT_frame_jump(wmOperatorType *ot)
1607 {
1608         ot->name = "Jump to Endpoint";
1609         ot->description= "Jump to first/last frame in frame range";
1610         ot->idname = "SCREEN_OT_frame_jump";
1611         
1612         ot->exec= frame_jump_exec;
1613         
1614         ot->poll= ED_operator_screenactive;
1615         ot->flag= OPTYPE_UNDO;
1616         
1617         /* rna */
1618         RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range.");
1619 }
1620
1621
1622 /* ************** jump to keyframe operator ***************************** */
1623
1624 /* function to be called outside UI context, or for redo */
1625 static int keyframe_jump_exec(bContext *C, wmOperator *op)
1626 {
1627         Scene *scene= CTX_data_scene(C);
1628         Object *ob= CTX_data_active_object(C);
1629         DLRBT_Tree keys;
1630         ActKeyColumn *ak;
1631         float cfra= (scene)? (float)(CFRA) : 0.0f;
1632         short next= RNA_boolean_get(op->ptr, "next");
1633         short done = 0;
1634         
1635         /* sanity checks */
1636         if (scene == NULL)
1637                 return OPERATOR_CANCELLED;
1638         
1639         /* init binarytree-list for getting keyframes */
1640         BLI_dlrbTree_init(&keys);
1641         
1642         /* populate tree with keyframe nodes */
1643         if (scene && scene->adt)
1644                 scene_to_keylist(NULL, scene, &keys, NULL);
1645         if (ob && ob->adt)
1646                 ob_to_keylist(NULL, ob, &keys, NULL);
1647         
1648         /* build linked-list for searching */
1649         BLI_dlrbTree_linkedlist_sync(&keys);
1650         
1651         /* find matching keyframe in the right direction */
1652         do {
1653                 if (next)
1654                         ak= (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfra);
1655                 else
1656                         ak= (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfra);
1657                 
1658                 if (ak) {
1659                         if (CFRA != (int)ak->cfra) {
1660                                 /* this changes the frame, so set the frame and we're done */
1661                                 CFRA= (int)ak->cfra;
1662                                 done = 1;
1663                         }
1664                         else {
1665                                 /* make this the new starting point for the search */
1666                                 cfra = ak->cfra;
1667                         }
1668                 }
1669         } while ((ak != NULL) && (done == 0));
1670         
1671         /* any success? */
1672         if (done == 0)
1673                 BKE_report(op->reports, RPT_INFO, "No more keyframes to jump to in this direction");
1674         
1675         /* free temp stuff */
1676         BLI_dlrbTree_free(&keys);
1677         
1678         sound_seek_scene(C);
1679
1680         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1681         
1682         return OPERATOR_FINISHED;
1683 }
1684
1685 static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
1686 {
1687         ot->name = "Jump to Keyframe";
1688         ot->description= "Jump to previous/next keyframe";
1689         ot->idname = "SCREEN_OT_keyframe_jump";
1690         
1691         ot->exec= keyframe_jump_exec;
1692         
1693         ot->poll= ED_operator_screenactive;
1694         ot->flag= OPTYPE_UNDO;
1695         
1696         /* rna */
1697         RNA_def_boolean(ot->srna, "next", 1, "Next Keyframe", "");
1698 }
1699
1700 /* ************** switch screen operator ***************************** */
1701
1702
1703 /* function to be called outside UI context, or for redo */
1704 static int screen_set_exec(bContext *C, wmOperator *op)
1705 {
1706         bScreen *screen= CTX_wm_screen(C);
1707         ScrArea *sa= CTX_wm_area(C);
1708         int tot= BLI_countlist(&CTX_data_main(C)->screen);
1709         int delta= RNA_int_get(op->ptr, "delta");
1710         
1711         /* return to previous state before switching screens */
1712         if(sa && sa->full)
1713                 ED_screen_full_restore(C, sa);
1714         
1715         if(delta==1) {
1716                 while(tot--) {
1717                         screen= screen->id.next;
1718                         if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1719                         if(screen->winid==0 && screen->full==0)
1720                                 break;
1721                 }
1722         }
1723         else if(delta== -1) {
1724                 while(tot--) {
1725                         screen= screen->id.prev;
1726                         if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1727                         if(screen->winid==0 && screen->full==0)
1728                                 break;
1729                 }
1730         }
1731         else {
1732                 screen= NULL;
1733         }
1734         
1735         if(screen) {
1736                 ED_screen_set(C, screen);
1737                 return OPERATOR_FINISHED;
1738         }
1739         return OPERATOR_CANCELLED;
1740 }
1741
1742 static void SCREEN_OT_screen_set(wmOperatorType *ot)
1743 {
1744         ot->name = "Set Screen";
1745         ot->description= "Cycle through available screens";
1746         ot->idname = "SCREEN_OT_screen_set";
1747         
1748         ot->exec= screen_set_exec;
1749         ot->poll= ED_operator_screenactive;
1750         
1751         /* rna */
1752         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1753 }
1754
1755 /* ************** screen full-area operator ***************************** */
1756
1757
1758 /* function to be called outside UI context, or for redo */
1759 static int screen_full_area_exec(bContext *C, wmOperator *UNUSED(op))
1760 {
1761         ED_screen_full_toggle(C, CTX_wm_window(C), CTX_wm_area(C));
1762         return OPERATOR_FINISHED;
1763 }
1764
1765 static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1766 {
1767         ot->name = "Toggle Full Screen";
1768         ot->description= "Toggle display selected area as fullscreen";
1769         ot->idname = "SCREEN_OT_screen_full_area";
1770         
1771         ot->exec= screen_full_area_exec;
1772         ot->poll= ED_operator_areaactive;
1773         ot->flag= 0;
1774         
1775 }
1776
1777
1778
1779 /* ************** join area operator ********************************************** */
1780
1781 /* operator state vars used:  
1782  x1, y1     mouse coord in first area, which will disappear
1783  x2, y2     mouse coord in 2nd area, which will become joined
1784  
1785  functions:
1786  
1787  init()   find edge based on state vars 
1788  test if the edge divides two areas, 
1789  store active and nonactive area,
1790  
1791  apply()  do the actual join
1792  
1793  exit() cleanup, send notifier
1794  
1795  callbacks:
1796  
1797  exec() calls init, apply, exit 
1798  
1799  invoke() sets mouse coords in x,y
1800  call init()
1801  add modal handler
1802  
1803  modal()        accept modal events while doing it
1804  call apply() with active window and nonactive window
1805  call exit() and remove handler when LMB confirm
1806  
1807  */
1808
1809 typedef struct sAreaJoinData
1810         {
1811                 ScrArea *sa1;   /* first area to be considered */
1812                 ScrArea *sa2;   /* second area to be considered */
1813                 ScrArea *scr;   /* designed for removal */
1814                 
1815         } sAreaJoinData;
1816
1817
1818 /* validate selection inside screen, set variables OK */
1819 /* return 0: init failed */
1820 /* XXX todo: find edge based on (x,y) and set other area? */
1821 static int area_join_init(bContext *C, wmOperator *op)
1822 {
1823         ScrArea *sa1, *sa2;
1824         sAreaJoinData* jd= NULL;
1825         int x1, y1;
1826         int x2, y2;
1827         
1828         /* required properties, make negative to get return 0 if not set by caller */
1829         x1= RNA_int_get(op->ptr, "min_x");
1830         y1= RNA_int_get(op->ptr, "min_y");
1831         x2= RNA_int_get(op->ptr, "max_x");
1832         y2= RNA_int_get(op->ptr, "max_y");
1833         
1834         sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1835         sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1836         if(sa1==NULL || sa2==NULL || sa1==sa2)
1837                 return 0;
1838         
1839         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1840         
1841         jd->sa1 = sa1;
1842         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1843         jd->sa2 = sa2;
1844         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1845         
1846         op->customdata= jd;
1847         
1848         return 1;
1849 }
1850
1851 /* apply the join of the areas (space types) */
1852 static int area_join_apply(bContext *C, wmOperator *op)
1853 {
1854         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1855         if (!jd) return 0;
1856         
1857         if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1858                 return 0;
1859         }
1860         if (CTX_wm_area(C) == jd->sa2) {
1861                 CTX_wm_area_set(C, NULL);
1862                 CTX_wm_region_set(C, NULL);
1863         }
1864         
1865         return 1;
1866 }
1867
1868 /* finish operation */
1869 static void area_join_exit(bContext *C, wmOperator *op)
1870 {
1871         if (op->customdata) {
1872                 MEM_freeN(op->customdata);
1873                 op->customdata = NULL;
1874         }
1875         
1876         /* this makes sure aligned edges will result in aligned grabbing */
1877         removedouble_scredges(CTX_wm_screen(C));
1878         removenotused_scredges(CTX_wm_screen(C));
1879         removenotused_scrverts(CTX_wm_screen(C));
1880 }
1881
1882 static int area_join_exec(bContext *C, wmOperator *op)
1883 {
1884         if(!area_join_init(C, op)) 
1885                 return OPERATOR_CANCELLED;
1886         
1887         area_join_apply(C, op);
1888         area_join_exit(C, op);
1889         
1890         return OPERATOR_FINISHED;
1891 }
1892
1893 /* interaction callback */
1894 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1895 {
1896         
1897         if(event->type==EVT_ACTIONZONE_AREA) {
1898                 sActionzoneData *sad= event->customdata;
1899                 
1900                 if(sad->modifier>0) {
1901                         return OPERATOR_PASS_THROUGH;
1902                 }
1903                 
1904                 /* verify *sad itself */
1905                 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1906                         return OPERATOR_PASS_THROUGH;
1907                 
1908                 /* is this our *sad? if areas equal it should be passed on */
1909                 if(sad->sa1==sad->sa2)
1910                         return OPERATOR_PASS_THROUGH;
1911                 
1912                 /* prepare operator state vars */
1913                 RNA_int_set(op->ptr, "min_x", sad->x);
1914                 RNA_int_set(op->ptr, "min_y", sad->y);
1915                 RNA_int_set(op->ptr, "max_x", event->x);
1916                 RNA_int_set(op->ptr, "max_y", event->y);
1917                 
1918                 if(!area_join_init(C, op)) 
1919                         return OPERATOR_PASS_THROUGH;
1920                 
1921                 /* add temp handler */
1922                 WM_event_add_modal_handler(C, op);
1923                 
1924                 return OPERATOR_RUNNING_MODAL;
1925         }
1926         
1927         return OPERATOR_PASS_THROUGH;
1928 }
1929
1930 static int area_join_cancel(bContext *C, wmOperator *op)
1931 {
1932         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1933         
1934         if (jd->sa1) {
1935                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1936                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1937         }
1938         if (jd->sa2) {
1939                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1940                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1941         }
1942         
1943         WM_event_add_notifier(C, NC_WINDOW, NULL);
1944         
1945         area_join_exit(C, op);
1946         
1947         return OPERATOR_CANCELLED;
1948 }
1949
1950 /* modal callback while selecting area (space) that will be removed */
1951 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1952 {
1953         bScreen *sc= CTX_wm_screen(C);
1954         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1955         
1956         /* execute the events */
1957         switch(event->type) {
1958                         
1959                 case MOUSEMOVE: 
1960                 {
1961                         ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1962                         int dir;
1963                         
1964                         if (sa) {                                       
1965                                 if (jd->sa1 != sa) {
1966                                         dir = area_getorientation(jd->sa1, sa);
1967                                         if (dir >= 0) {
1968                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1969                                                 jd->sa2 = sa;
1970                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1971                                         } 
1972                                         else {
1973                                                 /* we are not bordering on the previously selected area 
1974                                                  we check if area has common border with the one marked for removal
1975                                                  in this case we can swap areas.
1976                                                  */
1977                                                 dir = area_getorientation(sa, jd->sa2);
1978                                                 if (dir >= 0) {
1979                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1980                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1981                                                         jd->sa1 = jd->sa2;
1982                                                         jd->sa2 = sa;
1983                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1984                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1985                                                 } 
1986                                                 else {
1987                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1988                                                         jd->sa2 = NULL;
1989                                                 }
1990                                         }
1991                                         WM_event_add_notifier(C, NC_WINDOW, NULL);
1992                                 } 
1993                                 else {
1994                                         /* we are back in the area previously selected for keeping 
1995                                          * we swap the areas if possible to allow user to choose */
1996                                         if (jd->sa2 != NULL) {
1997                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1998                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1999                                                 jd->sa1 = jd->sa2;
2000                                                 jd->sa2 = sa;
2001                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
2002                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
2003                                                 dir = area_getorientation(jd->sa1, jd->sa2);
2004                                                 if (dir < 0) {
2005                                                         printf("oops, didn't expect that!\n");
2006                                                 }
2007                                         } 
2008                                         else {
2009                                                 dir = area_getorientation(jd->sa1, sa);
2010                                                 if (dir >= 0) {
2011                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
2012                                                         jd->sa2 = sa;
2013                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
2014                                                 }
2015                                         }
2016                                         WM_event_add_notifier(C, NC_WINDOW, NULL);
2017                                 }
2018                         }
2019                 }
2020                         break;
2021                 case LEFTMOUSE:
2022                         if(event->val==KM_RELEASE) {
2023                                 ED_area_tag_redraw(jd->sa1);
2024                                 ED_area_tag_redraw(jd->sa2);
2025
2026                                 area_join_apply(C, op);
2027                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2028                                 area_join_exit(C, op);
2029                                 return OPERATOR_FINISHED;
2030                         }
2031                         break;
2032                         
2033                 case RIGHTMOUSE:
2034                 case ESCKEY:
2035                         return area_join_cancel(C, op);
2036         }
2037         
2038         return OPERATOR_RUNNING_MODAL;
2039 }
2040
2041 /* Operator for joining two areas (space types) */
2042 static void SCREEN_OT_area_join(wmOperatorType *ot)
2043 {
2044         /* identifiers */
2045         ot->name= "Join area";
2046         ot->description= "Join selected areas into new window";
2047         ot->idname= "SCREEN_OT_area_join";
2048         
2049         /* api callbacks */
2050         ot->exec= area_join_exec;
2051         ot->invoke= area_join_invoke;
2052         ot->modal= area_join_modal;
2053         ot->poll= ED_operator_areaactive;
2054         
2055         ot->flag= OPTYPE_BLOCKING;
2056         
2057         /* rna */
2058         RNA_def_int(ot->srna, "min_x", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
2059         RNA_def_int(ot->srna, "min_y", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
2060         RNA_def_int(ot->srna, "max_x", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
2061         RNA_def_int(ot->srna, "max_y", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
2062 }
2063
2064 /* ************** repeat last operator ***************************** */
2065
2066 static int repeat_last_exec(bContext *C, wmOperator *UNUSED(op))
2067 {
2068         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
2069         
2070         if(lastop)
2071                 WM_operator_repeat(C, lastop);
2072         
2073         return OPERATOR_CANCELLED;
2074 }
2075
2076 static void SCREEN_OT_repeat_last(wmOperatorType *ot)
2077 {
2078         /* identifiers */
2079         ot->name= "Repeat Last";
2080         ot->description= "Repeat last action";
2081         ot->idname= "SCREEN_OT_repeat_last";
2082         
2083         /* api callbacks */
2084         ot->exec= repeat_last_exec;
2085         
2086         ot->poll= ED_operator_screenactive;
2087         
2088 }
2089
2090 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2091 {
2092         wmWindowManager *wm= CTX_wm_manager(C);
2093         wmOperator *lastop;
2094         uiPopupMenu *pup;
2095         uiLayout *layout;
2096         int items, i;
2097         
2098         items= BLI_countlist(&wm->operators);
2099         if(items==0)
2100                 return OPERATOR_CANCELLED;
2101         
2102         pup= uiPupMenuBegin(C, op->type->name, 0);
2103         layout= uiPupMenuLayout(pup);
2104         
2105         for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
2106                 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
2107         
2108         uiPupMenuEnd(C, pup);
2109         
2110         return OPERATOR_CANCELLED;
2111 }
2112
2113 static int repeat_history_exec(bContext *C, wmOperator *op)
2114 {
2115         wmWindowManager *wm= CTX_wm_manager(C);
2116         
2117         op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
2118         if(op) {
2119                 /* let's put it as last operator in list */
2120                 BLI_remlink(&wm->operators, op);
2121                 BLI_addtail(&wm->operators, op);
2122                 
2123                 WM_operator_repeat(C, op);
2124         }
2125         
2126         return OPERATOR_FINISHED;
2127 }
2128
2129 static void SCREEN_OT_repeat_history(wmOperatorType *ot)
2130 {
2131         /* identifiers */
2132         ot->name= "Repeat History";
2133         ot->description= "Display menu for previous actions performed";
2134         ot->idname= "SCREEN_OT_repeat_history";
2135         
2136         /* api callbacks */
2137         ot->invoke= repeat_history_invoke;
2138         ot->exec= repeat_history_exec;
2139         
2140         ot->poll= ED_operator_screenactive;
2141         
2142         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
2143 }
2144
2145 /* ********************** redo operator ***************************** */
2146
2147 static int redo_last_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
2148 {
2149         wmWindowManager *wm= CTX_wm_manager(C);
2150         wmOperator *lastop;
2151         
2152         /* only for operators that are registered and did an undo push */
2153         for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
2154                 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
2155                         break;
2156         
2157         if(lastop)
2158                 WM_operator_redo_popup(C, lastop);
2159         
2160         return OPERATOR_CANCELLED;
2161 }
2162
2163 static void SCREEN_OT_redo_last(wmOperatorType *ot)
2164 {
2165         /* identifiers */
2166         ot->name= "Redo Last";
2167         ot->description= "Display menu for last action performed";
2168         ot->idname= "SCREEN_OT_redo_last";
2169         
2170         /* api callbacks */
2171         ot->invoke= redo_last_invoke;
2172         
2173         ot->poll= ED_operator_screenactive;
2174 }
2175
2176 /* ************** region four-split operator ***************************** */
2177
2178 /* insert a region in the area region list */
2179 static int region_quadview_exec(bContext *C, wmOperator *op)
2180 {
2181         ARegion *ar= CTX_wm_region(C);
2182         
2183         /* some rules... */
2184         if(ar->regiontype!=RGN_TYPE_WINDOW)
2185                 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
2186         else if(ar->alignment==RGN_ALIGN_QSPLIT) {
2187                 ScrArea *sa= CTX_wm_area(C);
2188                 ARegion *arn;
2189                 
2190                 /* keep current region */
2191                 ar->alignment= 0;
2192                 
2193                 if(sa->spacetype==SPACE_VIEW3D) {
2194                         RegionView3D *rv3d= ar->regiondata;
2195                         rv3d->viewlock= 0;
2196                         rv3d->rflag &= ~RV3D_CLIPPING;
2197                 }
2198                 
2199                 for(ar= sa->regionbase.first; ar; ar= arn) {
2200                         arn= ar->next;
2201                         if(ar->alignment==RGN_ALIGN_QSPLIT) {
2202                                 ED_region_exit(C, ar);
2203                                 BKE_area_region_free(sa->type, ar);
2204                                 BLI_remlink(&sa->regionbase, ar);
2205                                 MEM_freeN(ar);
2206                         }
2207                 }
2208                 ED_area_tag_redraw(sa);
2209                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2210         }
2211         else if(ar->next)
2212                 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
2213         else {
2214                 ScrArea *sa= CTX_wm_area(C);
2215                 ARegion *newar;
2216                 int count;
2217                 
2218                 ar->alignment= RGN_ALIGN_QSPLIT;
2219                 
2220                 for(count=0; count<3; count++) {
2221                         newar= BKE_area_region_copy(sa->type, ar);
2222                         BLI_addtail(&sa->regionbase, newar);
2223                 }
2224                 
2225                 /* lock views and set them */
2226                 if(sa->spacetype==SPACE_VIEW3D) {
2227                         RegionView3D *rv3d;
2228                         
2229                         rv3d= ar->regiondata;
2230                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_FRONT; rv3d->persp= RV3D_ORTHO;
2231                         if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2232                         
2233                         ar= ar->next;
2234                         rv3d= ar->regiondata;
2235                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_TOP; rv3d->persp= RV3D_ORTHO;
2236                         if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2237                         
2238                         ar= ar->next;
2239                         rv3d= ar->regiondata;
2240                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_RIGHT; rv3d->persp= RV3D_ORTHO;
2241                         if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2242                         
2243                         ar= ar->next;
2244                         rv3d= ar->regiondata;
2245                         rv3d->view= RV3D_VIEW_CAMERA; rv3d->persp= RV3D_CAMOB;
2246                         if (rv3d->localvd) {rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2247                 }
2248                 ED_area_tag_redraw(sa);
2249                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2250         }
2251         
2252         
2253         return OPERATOR_FINISHED;
2254 }
2255
2256 static void SCREEN_OT_region_quadview(wmOperatorType *ot)
2257 {
2258         /* identifiers */
2259         ot->name= "Toggle Quad View";
2260         ot->description= "Split selected area into camera, front, right & top views";
2261         ot->idname= "SCREEN_OT_region_quadview";
2262         
2263         /* api callbacks */
2264         //      ot->invoke= WM_operator_confirm;
2265         ot->exec= region_quadview_exec;
2266         ot->poll= ED_operator_region_view3d_active;
2267         ot->flag= 0;
2268 }
2269
2270
2271
2272 /* ************** region flip operator ***************************** */
2273
2274 /* flip a region alignment */
2275 static int region_flip_exec(bContext *C, wmOperator *UNUSED(op))
2276 {
2277         ARegion *ar= CTX_wm_region(C);
2278         
2279         if (!ar)
2280                 return OPERATOR_CANCELLED;
2281         
2282         if(ar->alignment==RGN_ALIGN_TOP)
2283                 ar->alignment= RGN_ALIGN_BOTTOM;
2284         else if(ar->alignment==RGN_ALIGN_BOTTOM)
2285                 ar->alignment= RGN_ALIGN_TOP;
2286         else if(ar->alignment==RGN_ALIGN_LEFT)
2287                 ar->alignment= RGN_ALIGN_RIGHT;
2288         else if(ar->alignment==RGN_ALIGN_RIGHT)
2289                 ar->alignment= RGN_ALIGN_LEFT;
2290
2291         ED_area_tag_redraw(CTX_wm_area(C));
2292         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2293         
2294         return OPERATOR_FINISHED;
2295 }
2296
2297
2298 static void SCREEN_OT_region_flip(wmOperatorType *ot)
2299 {
2300         /* identifiers */
2301         ot->name= "Flip Region";
2302         ot->idname= "SCREEN_OT_region_flip";
2303         
2304         /* api callbacks */
2305         ot->exec= region_flip_exec;
2306         ot->poll= ED_operator_areaactive;
2307         ot->flag= 0;
2308 }
2309
2310 /* ************** header flip operator ***************************** */
2311
2312 /* flip a header region alignment */
2313 static int header_flip_exec(bContext *C, wmOperator *UNUSED(op))
2314 {
2315         ARegion *ar= CTX_wm_region(C);
2316         
2317         /* find the header region 
2318          *      - try context first, but upon failing, search all regions in area...
2319          */
2320         if((ar == NULL) || (ar->regiontype != RGN_TYPE_HEADER)) {
2321                 ScrArea *sa= CTX_wm_area(C);
2322                 
2323                 /* loop over all regions until a matching one is found */
2324                 for (ar= sa->regionbase.first; ar; ar= ar->next) {
2325                         if(ar->regiontype == RGN_TYPE_HEADER)
2326                                 break;
2327                 }
2328                 
2329                 /* don't do anything if no region */
2330                 if(ar == NULL)
2331                         return OPERATOR_CANCELLED;
2332         }       
2333         
2334         /* copied from SCREEN_OT_region_flip */
2335         if(ar->alignment==RGN_ALIGN_TOP)
2336                 ar->alignment= RGN_ALIGN_BOTTOM;
2337         else if(ar->alignment==RGN_ALIGN_BOTTOM)
2338                 ar->alignment= RGN_ALIGN_TOP;
2339         else if(ar->alignment==RGN_ALIGN_LEFT)
2340                 ar->alignment= RGN_ALIGN_RIGHT;
2341         else if(ar->alignment==RGN_ALIGN_RIGHT)
2342                 ar->alignment= RGN_ALIGN_LEFT;
2343
2344         ED_area_tag_redraw(CTX_wm_area(C));
2345
2346         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2347         
2348         return OPERATOR_FINISHED;
2349 }
2350
2351
2352 static void SCREEN_OT_header_flip(wmOperatorType *ot)
2353 {
2354         /* identifiers */
2355         ot->name= "Flip Header Region";
2356         ot->idname= "SCREEN_OT_header_flip";
2357         
2358         /* api callbacks */
2359         ot->exec= header_flip_exec;
2360         
2361         ot->poll= ED_operator_areaactive;
2362         ot->flag= 0;
2363 }
2364
2365 /* ************** header tools operator ***************************** */
2366
2367 static int header_toolbox_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
2368 {
2369         ScrArea *sa= CTX_wm_area(C);
2370         ARegion *ar= CTX_wm_region(C);
2371         uiPopupMenu *pup;
2372         uiLayout *layout;
2373         
2374         pup= uiPupMenuBegin(C, "Header", 0);
2375         layout= uiPupMenuLayout(pup);
2376         
2377         // XXX SCREEN_OT_region_flip doesn't work - gets wrong context for active region, so added custom operator
2378         if (ar->alignment == RGN_ALIGN_TOP)
2379                 uiItemO(layout, "Flip to Bottom", 0, "SCREEN_OT_header_flip");  
2380         else
2381                 uiItemO(layout, "Flip to Top", 0, "SCREEN_OT_header_flip");
2382         
2383         uiItemS(layout);
2384         
2385         /* file browser should be fullscreen all the time, but other regions can be maximised/restored... */
2386         if (sa->spacetype != SPACE_FILE) {
2387                 if (sa->full) 
2388                         uiItemO(layout, "Tile Area", 0, "SCREEN_OT_screen_full_area");
2389                 else
2390                         uiItemO(layout, "Maximize Area", 0, "SCREEN_OT_screen_full_area");
2391         }
2392         
2393         uiPupMenuEnd(C, pup);
2394         
2395         return OPERATOR_CANCELLED;
2396 }
2397
2398 void SCREEN_OT_header_toolbox(wmOperatorType *ot)
2399 {
2400         /* identifiers */
2401         ot->name= "Header Toolbox";
2402         ot->description="Display header region toolbox";
2403         ot->idname= "SCREEN_OT_header_toolbox";
2404         
2405         /* api callbacks */
2406         ot->invoke= header_toolbox_invoke;
2407 }
2408
2409 /* ****************** anim player, with timer ***************** */
2410
2411 static int match_area_with_refresh(int spacetype, int refresh)
2412 {
2413         switch (spacetype) {
2414                 case SPACE_TIME:
2415                         if (refresh & SPACE_TIME)
2416                                 return 1;
2417                         break;
2418         }
2419         
2420         return 0;
2421 }
2422
2423 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2424 {
2425         if(regiontype==RGN_TYPE_WINDOW) {
2426                 
2427                 switch (spacetype) {
2428                         case SPACE_VIEW3D:
2429                                 if(redraws & TIME_ALL_3D_WIN)
2430                                         return 1;
2431                                 break;
2432                         case SPACE_IPO:
2433                         case SPACE_ACTION:
2434                         case SPACE_NLA:
2435                                 if(redraws & TIME_ALL_ANIM_WIN)
2436                                         return 1;
2437                                 break;
2438                         case SPACE_TIME:
2439                                 /* if only 1 window or 3d windows, we do timeline too */
2440                                 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2441                                         return 1;
2442                                 break;
2443                         case SPACE_BUTS:
2444                                 if(redraws & TIME_ALL_BUTS_WIN)
2445                                         return 1;
2446                                 break;
2447                         case SPACE_SEQ:
2448                                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2449                                         return 1;
2450                                 break;
2451                         case SPACE_NODE:
2452                                 if(redraws & (TIME_NODES))
2453                                         return 1;
2454                                 break;
2455                         case SPACE_IMAGE:
2456                                 if(redraws & TIME_ALL_IMAGE_WIN)
2457                                         return 1;
2458                                 break;
2459                                 
2460                 }
2461         }
2462         else if(regiontype==RGN_TYPE_UI) {
2463                 if(redraws & TIME_ALL_BUTS_WIN)
2464                         return 1;
2465         }
2466         else if(regiontype==RGN_TYPE_HEADER) {
2467                 if(spacetype==SPACE_TIME)
2468                         return 1;
2469         }
2470         else if (regiontype==RGN_TYPE_PREVIEW) {
2471                 switch (spacetype) {
2472                         case SPACE_SEQ:
2473                                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2474                                         return 1;
2475                                 break;
2476                 }
2477         }
2478         return 0;
2479 }
2480
2481 static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
2482 {
2483         bScreen *screen= CTX_wm_screen(C);
2484
2485         if(screen->animtimer && screen->animtimer==event->customdata) {
2486                 Scene *scene= CTX_data_scene(C);
2487                 wmTimer *wt= screen->animtimer;
2488                 ScreenAnimData *sad= wt->customdata;
2489                 ScrArea *sa;
2490                 int sync;
2491                 float time;
2492                 
2493                 /* sync, don't sync, or follow scene setting */
2494                 if (sad->flag & ANIMPLAY_FLAG_SYNC) sync= 1;
2495                 else if (sad->flag & ANIMPLAY_FLAG_NO_SYNC) sync= 0;
2496                 else sync= (scene->flag & SCE_FRAME_DROP);
2497                 
2498                 if((scene->audio.flag & AUDIO_SYNC) && !(sad->flag & ANIMPLAY_FLAG_REVERSE) && finite(time = sound_sync_scene(scene)))
2499                         scene->r.cfra = time * FPS + 0.5;
2500                 else
2501                 {
2502                         if (sync) {
2503                                 int step = floor(wt->duration * FPS);
2504                                 /* skip frames */
2505                                 if (sad->flag & ANIMPLAY_FLAG_REVERSE)
2506                                         scene->r.cfra -= step;
2507                                 else
2508                                         scene->r.cfra += step;
2509                                 wt->duration -= ((float)step)/FPS;
2510                         }
2511                         else {
2512                                 /* one frame +/- */
2513                                 if (sad->flag & ANIMPLAY_FLAG_REVERSE)
2514                                         scene->r.cfra--;
2515                                 else
2516                                         scene->r.cfra++;
2517                         }
2518                 }
2519                 
2520                 /* reset 'jumped' flag before checking if we need to jump... */
2521                 sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
2522                 
2523                 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
2524                         /* jump back to end? */
2525                         if (PRVRANGEON) {
2526                                 if (scene->r.cfra < scene->r.psfra) {
2527                                         scene->r.cfra= scene->r.pefra;
2528                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2529                                 }
2530                         }
2531                         else {
2532                                 if (scene->r.cfra < scene->r.sfra) {
2533                                         scene->r.cfra= scene->r.efra;
2534                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2535                                 }
2536                         }
2537                 }
2538                 else {
2539                         /* jump back to start? */
2540                         if (PRVRANGEON) {
2541                                 if (scene->r.cfra > scene->r.pefra) {
2542                                         scene->r.cfra= scene->r.psfra;
2543                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2544                                 }
2545                         }
2546                         else {
2547                                 if (scene->r.cfra > scene->r.efra) {
2548                                         scene->r.cfra= scene->r.sfra;
2549                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2550                                 }
2551                         }
2552                 }
2553
2554                 /* next frame overriden by user action (pressed jump to first/last frame) */
2555                 if(sad->flag & ANIMPLAY_FLAG_USE_NEXT_FRAME) {
2556                         scene->r.cfra = sad->nextfra;
2557                         sad->flag &= ~ANIMPLAY_FLAG_USE_NEXT_FRAME;
2558                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2559                 }
2560                 
2561                 if (sad->flag & ANIMPLAY_FLAG_JUMPED)
2562                         sound_seek_scene(C);
2563                 
2564                 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2565                 ED_update_for_newframe(CTX_data_main(C), scene, screen, 1);
2566                 
2567                 for (sa= screen->areabase.first; sa; sa= sa->next) {
2568                         ARegion *ar;
2569                         for (ar= sa->regionbase.first; ar; ar= ar->next) {
2570                                 if (ar==sad->ar)
2571                                         ED_region_tag_redraw(ar);
2572                                 else
2573                                         if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2574                                                 ED_region_tag_redraw(ar);
2575                         }
2576                         
2577                         if (match_area_with_refresh(sa->spacetype, sad->refresh))
2578                                 ED_area_tag_refresh(sa);
2579                 }
2580                 
2581                 /* update frame rate info too 
2582                  * NOTE: this may not be accurate enough, since we might need this after modifiers/etc. 
2583                  * have been calculated instead of just before updates have been done?
2584                  */
2585                 ED_refresh_viewport_fps(C);
2586                 
2587                 /* recalculate the timestep for the timer now that we've finished calculating this,
2588                  * since the frames-per-second value may have been changed
2589                  */
2590                 // TODO: this may make evaluation a bit slower if the value doesn't change... any way to avoid this?
2591                 wt->timestep= (1.0/FPS);
2592                 
2593                 return OPERATOR_FINISHED;
2594         }
2595         return OPERATOR_PASS_THROUGH;
2596 }
2597
2598 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2599 {
2600         /* identifiers */
2601         ot->name= "Animation Step";
2602         ot->description= "Step through animation by position";
2603         ot->idname= "SCREEN_OT_animation_step";
2604         
2605         /* api callbacks */
2606         ot->invoke= screen_animation_step;
2607         
2608         ot->poll= ED_operator_screenactive;
2609         
2610 }
2611
2612 /* ****************** anim player, starts or ends timer ***************** */
2613
2614 /* toggle operator */
2615 int ED_screen_animation_play(bContext *C, int sync, int mode)
2616 {
2617         bScreen *screen= CTX_wm_screen(C);
2618         Scene *scene = CTX_data_scene(C);
2619
2620         if (screen->animtimer) {
2621                 /* stop playback now */
2622                 ED_screen_animation_timer(C, 0, 0, 0, 0);
2623                 sound_stop_scene(scene);
2624         }
2625         else {
2626                 ScrArea *sa= CTX_wm_area(C);
2627                 int refresh= SPACE_TIME;
2628                 
2629                 if (mode == 1) // XXX only play audio forwards!?
2630                         sound_play_scene(scene);
2631                 
2632                 /* timeline gets special treatment since it has it's own menu for determining redraws */
2633                 if ((sa) && (sa->spacetype == SPACE_TIME)) {
2634                         SpaceTime *stime= (SpaceTime *)sa->spacedata.first;
2635                         
2636                         ED_screen_animation_timer(C, stime->redraws, refresh, sync, mode);
2637                         
2638                         /* update region if TIME_REGION was set, to leftmost 3d window */
2639                         ED_screen_animation_timer_update(screen, stime->redraws, refresh);
2640                 }
2641                 else {
2642                         int redraws = TIME_REGION|TIME_ALL_3D_WIN;
2643                         
2644                         /* XXX - would like a better way to deal with this situation - Campbell */
2645                         if ((!sa) || (sa->spacetype == SPACE_SEQ)) {
2646                                 redraws |= TIME_SEQ;
2647                         }
2648                         
2649                         ED_screen_animation_timer(C, redraws, refresh, sync, mode);
2650                         
2651                         if(screen->animtimer) {
2652                                 wmTimer *wt= screen->animtimer;
2653                                 ScreenAnimData *sad= wt->customdata;
2654                                 
2655                                 sad->ar= CTX_wm_region(C);
2656                         }
2657                 }
2658         }
2659
2660         return OPERATOR_FINISHED;
2661 }
2662
2663 static int screen_animation_play_exec(bContext *C, wmOperator *op)
2664 {
2665         int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2666         int sync= -1;
2667         
2668         if (RNA_property_is_set(op->ptr, "sync"))
2669                 sync= (RNA_boolean_get(op->ptr, "sync"));
2670         
2671         return ED_screen_animation_play(C, sync, mode);
2672 }
2673
2674 static void SCREEN_OT_animation_play(wmOperatorType *ot)
2675 {
2676         /* identifiers */
2677         ot->name= "Play Animation";
2678         ot->description= "Play animation";
2679         ot->idname= "SCREEN_OT_animation_play";
2680         
2681         /* api callbacks */
2682         ot->exec= screen_animation_play_exec;
2683         
2684         ot->poll= ED_operator_screenactive;
2685         
2686         RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2687         RNA_def_boolean(ot->srna, "sync", 0, "Sync", "Drop frames to maintain framerate");
2688 }
2689
2690 static int screen_animation_cancel_exec(bContext *C, wmOperator *UNUSED(op))
2691 {
2692         bScreen *screen= CTX_wm_screen(C);
2693         
2694         if(screen->animtimer) {
2695                 ScreenAnimData *sad= screen->animtimer->customdata;
2696                 Scene *scene= CTX_data_scene(C);
2697                 
2698                 /* reset current frame before stopping, and just send a notifier to deal with the rest 
2699                  * (since playback still needs to be stopped)
2700                  */
2701                 scene->r.cfra= sad->sfra;
2702                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2703                 
2704                 /* call the other "toggling" operator to clean up now */
2705                 ED_screen_animation_play(C, 0, 0);
2706         }
2707
2708         return OPERATOR_PASS_THROUGH;
2709 }
2710
2711 static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
2712 {
2713         /* identifiers */
2714         ot->name= "Cancel Animation";
2715         ot->description= "Cancel animation, returning to the original frame";
2716         ot->idname= "SCREEN_OT_animation_cancel";
2717         
2718         /* api callbacks */
2719         ot->exec= screen_animation_cancel_exec;
2720         
2721         ot->poll= ED_operator_screenactive;
2722 }
2723
2724 /* ************** border select operator (template) ***************************** */
2725
2726 /* operator state vars used: (added by default WM callbacks)   
2727  xmin, ymin     
2728  xmax, ymax     
2729  
2730  customdata: the wmGesture pointer
2731  
2732  callbacks:
2733  
2734  exec() has to be filled in by user
2735  
2736  invoke() default WM function
2737  adds modal handler
2738  
2739  modal()        default WM function 
2740  accept modal events while doing it, calls exec(), handles ESC and border drawing
2741  
2742  poll() has to be filled in by user for context
2743  */
2744 #if 0
2745 static int border_select_do(bContext *C, wmOperator *op)
2746 {
2747         int event_type= RNA_int_get(op->ptr, "event_type");
2748         
2749         if(event_type==LEFTMOUSE)
2750                 printf("border select do select\n");
2751         else if(event_type==RIGHTMOUSE)
2752                 printf("border select deselect\n");
2753         else 
2754                 printf("border select do something\n");
2755         
2756         return 1;
2757 }
2758
2759 static void SCREEN_OT_border_select(wmOperatorType *ot)
2760 {
2761         /* identifiers */
2762         ot->name= "Border select";
2763         ot->idname= "SCREEN_OT_border_select";
2764         
2765         /* api callbacks */
2766         ot->exec= border_select_do;
2767         ot->invoke= WM_border_select_invoke;
2768         ot->modal= WM_border_select_modal;
2769         
2770         ot->poll= ED_operator_areaactive;
2771         
2772         /* rna */
2773         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2774         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2775         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2776         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2777         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2778         
2779 }
2780 #endif
2781
2782 /* *********************** generic fullscreen 'back' button *************** */
2783
2784
2785 static int fullscreen_back_exec(bContext *C, wmOperator *op)
2786 {
2787         bScreen *screen = CTX_wm_screen(C);
2788         ScrArea *sa=NULL;
2789         
2790         /* search current screen for 'fullscreen' areas */
2791         for (sa=screen->areabase.first; sa; sa=sa->next) {
2792                 if (sa->full) break;
2793         }
2794         if (!sa) {
2795                 BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found.");
2796                 return OPERATOR_CANCELLED;
2797         }
2798         
2799         ED_screen_full_restore(C, sa);
2800         
2801         return OPERATOR_FINISHED;
2802 }
2803
2804 static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
2805 {
2806         /* identifiers */
2807         ot->name= "Back to Previous Screen";
2808         ot->description= "Revert back to the original screen layout, before fullscreen area overlay";
2809         ot->idname= "SCREEN_OT_back_to_previous";
2810         
2811         /* api callbacks */
2812         ot->exec= fullscreen_back_exec;
2813         ot->poll= ED_operator_screenactive;
2814 }
2815
2816 /* *********** show user pref window ****** */
2817
2818 static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
2819 {
2820         ScrArea *sa;
2821         rcti rect;
2822         int sizex, sizey;
2823         
2824         sizex= 800;
2825         sizey= 480;
2826         
2827         /* some magic to calculate postition */
2828         rect.xmin= event->x + CTX_wm_window(C)->posx - sizex/2;
2829         rect.ymin= event->y + CTX_wm_window(C)->posy - sizey/2;
2830         rect.xmax= rect.xmin + sizex;
2831         rect.ymax= rect.ymin + sizey;
2832         
2833         /* changes context! */
2834         WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS);
2835         
2836         sa= CTX_wm_area(C);
2837         
2838         
2839         return OPERATOR_FINISHED;
2840 }
2841
2842
2843 static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
2844 {
2845         /* identifiers */
2846         ot->name= "Show/Hide User Preferences";
2847         ot->description= "Show/hide user preferences";
2848         ot->idname= "SCREEN_OT_userpref_show";
2849         
2850         /* api callbacks */
2851         ot->invoke= userpref_show_invoke;
2852         ot->poll= ED_operator_screenactive;
2853 }
2854
2855 /********************* new screen operator *********************/
2856
2857 static int screen_new_exec(bContext *C, wmOperator *UNUSED(op))
2858 {
2859         wmWindow *win= CTX_wm_window(C);
2860         bScreen *sc= CTX_wm_screen(C);
2861         
2862         sc= ED_screen_duplicate(win, sc);
2863         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENBROWSE, sc);
2864         
2865         return OPERATOR_FINISHED;
2866 }
2867
2868 void SCREEN_OT_new(wmOperatorType *ot)
2869 {
2870         /* identifiers */
2871         ot->name= "New Screen";
2872         ot->description= "Add a new screen";
2873         ot->idname= "SCREEN_OT_new";
2874         
2875         /* api callbacks */
2876         ot->exec= screen_new_exec;
2877         
2878         /* flags */
2879         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2880 }
2881
2882 /********************* delete screen operator *********************/
2883
2884 static int screen_delete_exec(bContext *C, wmOperator *UNUSED(op))
2885 {
2886         bScreen *sc= CTX_wm_screen(C);
2887         
2888         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENDELETE, sc);
2889         
2890         return OPERATOR_FINISHED;
2891 }
2892
2893 void SCREEN_OT_delete(wmOperatorType *ot)
2894 {
2895         /* identifiers */
2896         ot->name= "Delete Screen"; //was scene
2897         ot->description= "Delete active screen";
2898         ot->idname= "SCREEN_OT_delete";
2899         
2900         /* api callbacks */
2901         ot->exec= screen_delete_exec;
2902         
2903         /* flags */
2904         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2905 }
2906
2907 /********************* new scene operator *********************/
2908
2909 static int scene_new_exec(bContext *C, wmOperator *op)
2910 {
2911         Scene *newscene, *scene= CTX_data_scene(C);
2912         Main *bmain= CTX_data_main(C);
2913         int type= RNA_enum_get(op->ptr, "type");
2914         
2915         newscene= copy_scene(scene, type);
2916         
2917         /* these can't be handled in blenkernel curently, so do them here */
2918         if(type == SCE_COPY_LINK_DATA)
2919                 ED_object_single_users(bmain, newscene, 0);
2920         else if(type == SCE_COPY_FULL)
2921                 ED_object_single_users(bmain, newscene, 1);
2922         
2923         WM_event_add_notifier(C, NC_SCENE|ND_SCENEBROWSE, newscene);
2924         
2925         return OPERATOR_FINISHED;
2926 }
2927
2928 void SCENE_OT_new(wmOperatorType *ot)
2929 {
2930         static EnumPropertyItem type_items[]= {
2931                 {SCE_COPY_EMPTY, "EMPTY", 0, "Empty", "Add empty scene"},
2932                 {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene"},
2933                 {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene"},
2934                 {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene"},
2935                 {0, NULL, 0, NULL, NULL}};
2936         
2937         /* identifiers */
2938         ot->name= "New Scene";
2939         ot->description= "Add new scene by type";
2940         ot->idname= "SCENE_OT_new";
2941         
2942         /* api callbacks */
2943         ot->exec= scene_new_exec;
2944         ot->invoke= WM_menu_invoke;
2945         
2946         /* flags */
2947         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2948         
2949         /* properties */
2950         ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
2951 }
2952
2953 /********************* delete scene operator *********************/
2954
2955 static int scene_delete_exec(bContext *C, wmOperator *UNUSED(op))
2956 {
2957         Scene *scene= CTX_data_scene(C);
2958         
2959         WM_event_add_notifier(C, NC_SCENE|NA_REMOVED, scene);
2960         
2961         return OPERATOR_FINISHED;
2962 }
2963
2964 void SCENE_OT_delete(wmOperatorType *ot)
2965 {
2966         /* identifiers */
2967         ot->name= "Delete Scene";
2968         ot->description= "Delete active scene";
2969         ot->idname= "SCENE_OT_delete";
2970         
2971         /* api callbacks */
2972         ot->exec= scene_delete_exec;
2973         
2974         /* flags */
2975         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2976 }
2977
2978 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
2979
2980 /* called in spacetypes.c */
2981 void ED_operatortypes_screen(void)
2982 {
2983         /* generic UI stuff */
2984         WM_operatortype_append(SCREEN_OT_actionzone);
2985         WM_operatortype_append(SCREEN_OT_repeat_last);
2986         WM_operatortype_append(SCREEN_OT_repeat_history);
2987         WM_operatortype_append(SCREEN_OT_redo_last);
2988         
2989         /* screen tools */
2990         WM_operatortype_append(SCREEN_OT_area_move);
2991         WM_operatortype_append(SCREEN_OT_area_split);
2992         WM_operatortype_append(SCREEN_OT_area_join);
2993         WM_operatortype_append(SCREEN_OT_area_dupli);
2994         WM_operatortype_append(SCREEN_OT_area_swap);
2995         WM_operatortype_append(SCREEN_OT_region_quadview);
2996         WM_operatortype_append(SCREEN_OT_region_scale);
2997         WM_operatortype_append(SCREEN_OT_region_flip);
2998         WM_operatortype_append(SCREEN_OT_header_flip);
2999         WM_operatortype_append(SCREEN_OT_header_toolbox);
3000         WM_operatortype_append(SCREEN_OT_screen_set);
3001         WM_operatortype_append(SCREEN_OT_screen_full_area);
3002         WM_operatortype_append(SCREEN_OT_back_to_previous);
3003         WM_operatortype_append(SCREEN_OT_screenshot);
3004         WM_operatortype_append(SCREEN_OT_screencast);
3005         WM_operatortype_append(SCREEN_OT_userpref_show);
3006         
3007         /*frame changes*/
3008         WM_operatortype_append(SCREEN_OT_frame_offset);
3009         WM_operatortype_append(SCREEN_OT_frame_jump);
3010         WM_operatortype_append(SCREEN_OT_keyframe_jump);
3011         
3012         WM_operatortype_append(SCREEN_OT_animation_step);
3013         WM_operatortype_append(SCREEN_OT_animation_play);
3014         WM_operatortype_append(SCREEN_OT_animation_cancel);
3015         
3016         /* new/delete */
3017         WM_operatortype_append(SCREEN_OT_new);
3018         WM_operatortype_append(SCREEN_OT_delete);
3019         WM_operatortype_append(SCENE_OT_new);
3020         WM_operatortype_append(SCENE_OT_delete);
3021         
3022         /* tools shared by more space types */
3023         WM_operatortype_append(ED_OT_undo);
3024         WM_operatortype_append(ED_OT_redo);     
3025         
3026 }
3027
3028 static void keymap_modal_set(wmKeyConfig *keyconf)
3029 {
3030         static EnumPropertyItem modal_items[] = {
3031                 {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
3032                 {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
3033                 {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""},
3034                 {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""},
3035                 {0, NULL, 0, NULL, NULL}};
3036         wmKeyMap *keymap;
3037         
3038         /* Standard Modal keymap ------------------------------------------------ */
3039         keymap= WM_modalkeymap_add(keyconf, "Standard Modal Map", modal_items);
3040         
3041         WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, KM_MODAL_CANCEL);
3042         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KM_MODAL_APPLY);
3043         WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
3044         WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
3045         
3046         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10);
3047         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF);
3048         
3049         WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
3050         
3051 }
3052
3053 /* called in spacetypes.c */
3054 void ED_keymap_screen(wmKeyConfig *keyconf)
3055 {
3056         wmKeyMap *keymap;
3057         //wmKeyMapItem *kmi;
3058         
3059         /* Screen Editing ------------------------------------------------ */
3060         keymap= WM_keymap_find(keyconf, "Screen Editing", 0, 0);
3061         
3062         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
3063         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
3064         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "modifier", 2);
3065         
3066         /* screen tools */
3067         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
3068         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
3069         WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
3070         WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_CTRL, 0);
3071         WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
3072         /* area move after action zones */
3073         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
3074         
3075         /* Header Editing ------------------------------------------------ */
3076         keymap= WM_keymap_find(keyconf, "Header", 0, 0);
3077         
3078         WM_keymap_add_item(keymap, "SCREEN_OT_header_toolbox", RIGHTMOUSE, KM_PRESS, 0, 0);
3079         
3080         /* Screen General ------------------------------------------------ */
3081         keymap= WM_keymap_find(keyconf, "Screen", 0, 0);
3082         
3083         /* standard timers */
3084         WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
3085         
3086         
3087         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
3088         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
3089         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
3090         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
3091         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_SHIFT, 0);
3092         WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
3093         WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
3094         
3095         /* tests */
3096         WM_keymap_add_item(keymap, "SCREEN_OT_region_quadview", QKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
3097         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
3098         WM_keymap_add_item(keymap, "SCREEN_OT_repeat_last", RKEY, KM_PRESS, KM_SHIFT, 0);
3099         WM_keymap_verify_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
3100         WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
3101         WM_keymap_verify_item(keymap, "SCRIPT_OT_reload", F8KEY, KM_PRESS, 0, 0);
3102         
3103         /* files */
3104         WM_keymap_add_item(keymap, "FILE_OT_execute", RETKEY, KM_PRESS, 0, 0);
3105         WM_keymap_add_item(keymap, "FILE_OT_execute", PADENTER, KM_PRESS, 0, 0);
3106         WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
3107         
3108         /* undo */
3109 #ifdef __APPLE__
3110         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
3111         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
3112 #endif
3113         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
3114         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
3115         
3116         
3117         /* render */
3118         WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, 0, 0);
3119         RNA_boolean_set(WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, KM_CTRL, 0)->ptr, "animation", 1);
3120         WM_keymap_add_item(keymap, "RENDER_OT_view_cancel", ESCKEY, KM_PRESS, 0, 0);
3121         WM_keymap_add_item(keymap, "RENDER_OT_view_show", F11KEY, KM_PRESS, 0, 0);
3122         WM_keymap_add_item(keymap, "RENDER_OT_play_rendered_anim", F11KEY, KM_PRESS, KM_CTRL, 0);
3123         
3124         /* user prefs */
3125 #ifdef __APPLE__
3126         WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", COMMAKEY, KM_PRESS, KM_OSKEY, 0);
3127 #endif
3128         WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", UKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
3129         
3130         
3131         /* Anim Playback ------------------------------------------------ */
3132         keymap= WM_keymap_find(keyconf, "Frames", 0, 0);
3133         
3134         /* frame offsets */
3135         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
3136         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
3137         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
3138         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
3139         
3140         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "delta", 1);
3141         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", WHEELUPMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "delta", -1);
3142         
3143         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", UPARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 1);
3144         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 0);
3145         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 1);
3146         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 0);
3147         
3148         WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", PAGEUPKEY, KM_PRESS, KM_CTRL, 0);
3149         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", PAGEDOWNKEY, KM_PRESS, KM_CTRL, 0)->ptr, "next", 0);
3150         
3151         /* play (forward and backwards) */
3152         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
3153         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT|KM_SHIFT, 0)->ptr, "reverse", 1);
3154         WM_keymap_add_item(keymap, "SCREEN_OT_animation_cancel", ESCKEY, KM_PRESS, 0, 0);
3155         
3156         /* Alternative keys for animation and sequencer playing */
3157 #if 0 // XXX: disabled for restoring later... bad implementation
3158         keymap= WM_keymap_find(keyconf, "Frames", 0, 0);
3159         kmi = WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0);
3160                 RNA_boolean_set(kmi->ptr, "cycle_speed", 1);
3161         
3162         kmi = WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", LEFTARROWKEY, KM_PRESS, KM_ALT, 0);
3163                 RNA_boolean_set(kmi->ptr, "reverse", 1);
3164                 RNA_boolean_set(kmi->ptr, "cycle_speed", 1);
3165         
3166         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", DOWNARROWKEY, KM_PRESS, KM_ALT, 0);
3167 #endif
3168
3169         keymap_modal_set(keyconf);
3170 }
3171