Bugfix #20812 (and probably others)
[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         /* temp screens are for userpref or render display */
1712         if(screen->temp)
1713                 return OPERATOR_CANCELLED;
1714         
1715         /* return to previous state before switching screens */
1716         if(sa && sa->full)
1717                 ED_screen_full_restore(C, sa);
1718         
1719         if(delta==1) {
1720                 while(tot--) {
1721                         screen= screen->id.next;
1722                         if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1723                         if(screen->winid==0 && screen->full==0)
1724                                 break;
1725                 }
1726         }
1727         else if(delta== -1) {
1728                 while(tot--) {
1729                         screen= screen->id.prev;
1730                         if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1731                         if(screen->winid==0 && screen->full==0)
1732                                 break;
1733                 }
1734         }
1735         else {
1736                 screen= NULL;
1737         }
1738         
1739         if(screen) {
1740                 ED_screen_set(C, screen);
1741                 return OPERATOR_FINISHED;
1742         }
1743         return OPERATOR_CANCELLED;
1744 }
1745
1746 static void SCREEN_OT_screen_set(wmOperatorType *ot)
1747 {
1748         ot->name = "Set Screen";
1749         ot->description= "Cycle through available screens";
1750         ot->idname = "SCREEN_OT_screen_set";
1751         
1752         ot->exec= screen_set_exec;
1753         ot->poll= ED_operator_screenactive;
1754         
1755         /* rna */
1756         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1757 }
1758
1759 /* ************** screen full-area operator ***************************** */
1760
1761
1762 /* function to be called outside UI context, or for redo */
1763 static int screen_full_area_exec(bContext *C, wmOperator *UNUSED(op))
1764 {
1765         ED_screen_full_toggle(C, CTX_wm_window(C), CTX_wm_area(C));
1766         return OPERATOR_FINISHED;
1767 }
1768
1769 static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1770 {
1771         ot->name = "Toggle Full Screen";
1772         ot->description= "Toggle display selected area as fullscreen";
1773         ot->idname = "SCREEN_OT_screen_full_area";
1774         
1775         ot->exec= screen_full_area_exec;
1776         ot->poll= ED_operator_areaactive;
1777         ot->flag= 0;
1778         
1779 }
1780
1781
1782
1783 /* ************** join area operator ********************************************** */
1784
1785 /* operator state vars used:  
1786  x1, y1     mouse coord in first area, which will disappear
1787  x2, y2     mouse coord in 2nd area, which will become joined
1788  
1789  functions:
1790  
1791  init()   find edge based on state vars 
1792  test if the edge divides two areas, 
1793  store active and nonactive area,
1794  
1795  apply()  do the actual join
1796  
1797  exit() cleanup, send notifier
1798  
1799  callbacks:
1800  
1801  exec() calls init, apply, exit 
1802  
1803  invoke() sets mouse coords in x,y
1804  call init()
1805  add modal handler
1806  
1807  modal()        accept modal events while doing it
1808  call apply() with active window and nonactive window
1809  call exit() and remove handler when LMB confirm
1810  
1811  */
1812
1813 typedef struct sAreaJoinData
1814         {
1815                 ScrArea *sa1;   /* first area to be considered */
1816                 ScrArea *sa2;   /* second area to be considered */
1817                 ScrArea *scr;   /* designed for removal */
1818                 
1819         } sAreaJoinData;
1820
1821
1822 /* validate selection inside screen, set variables OK */
1823 /* return 0: init failed */
1824 /* XXX todo: find edge based on (x,y) and set other area? */
1825 static int area_join_init(bContext *C, wmOperator *op)
1826 {
1827         ScrArea *sa1, *sa2;
1828         sAreaJoinData* jd= NULL;
1829         int x1, y1;
1830         int x2, y2;
1831         
1832         /* required properties, make negative to get return 0 if not set by caller */
1833         x1= RNA_int_get(op->ptr, "min_x");
1834         y1= RNA_int_get(op->ptr, "min_y");
1835         x2= RNA_int_get(op->ptr, "max_x");
1836         y2= RNA_int_get(op->ptr, "max_y");
1837         
1838         sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1839         sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1840         if(sa1==NULL || sa2==NULL || sa1==sa2)
1841                 return 0;
1842         
1843         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1844         
1845         jd->sa1 = sa1;
1846         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1847         jd->sa2 = sa2;
1848         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1849         
1850         op->customdata= jd;
1851         
1852         return 1;
1853 }
1854
1855 /* apply the join of the areas (space types) */
1856 static int area_join_apply(bContext *C, wmOperator *op)
1857 {
1858         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1859         if (!jd) return 0;
1860         
1861         if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1862                 return 0;
1863         }
1864         if (CTX_wm_area(C) == jd->sa2) {
1865                 CTX_wm_area_set(C, NULL);
1866                 CTX_wm_region_set(C, NULL);
1867         }
1868         
1869         return 1;
1870 }
1871
1872 /* finish operation */
1873 static void area_join_exit(bContext *C, wmOperator *op)
1874 {
1875         if (op->customdata) {
1876                 MEM_freeN(op->customdata);
1877                 op->customdata = NULL;
1878         }
1879         
1880         /* this makes sure aligned edges will result in aligned grabbing */
1881         removedouble_scredges(CTX_wm_screen(C));
1882         removenotused_scredges(CTX_wm_screen(C));
1883         removenotused_scrverts(CTX_wm_screen(C));
1884 }
1885
1886 static int area_join_exec(bContext *C, wmOperator *op)
1887 {
1888         if(!area_join_init(C, op)) 
1889                 return OPERATOR_CANCELLED;
1890         
1891         area_join_apply(C, op);
1892         area_join_exit(C, op);
1893         
1894         return OPERATOR_FINISHED;
1895 }
1896
1897 /* interaction callback */
1898 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1899 {
1900         
1901         if(event->type==EVT_ACTIONZONE_AREA) {
1902                 sActionzoneData *sad= event->customdata;
1903                 
1904                 if(sad->modifier>0) {
1905                         return OPERATOR_PASS_THROUGH;
1906                 }
1907                 
1908                 /* verify *sad itself */
1909                 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1910                         return OPERATOR_PASS_THROUGH;
1911                 
1912                 /* is this our *sad? if areas equal it should be passed on */
1913                 if(sad->sa1==sad->sa2)
1914                         return OPERATOR_PASS_THROUGH;
1915                 
1916                 /* prepare operator state vars */
1917                 RNA_int_set(op->ptr, "min_x", sad->x);
1918                 RNA_int_set(op->ptr, "min_y", sad->y);
1919                 RNA_int_set(op->ptr, "max_x", event->x);
1920                 RNA_int_set(op->ptr, "max_y", event->y);
1921                 
1922                 if(!area_join_init(C, op)) 
1923                         return OPERATOR_PASS_THROUGH;
1924                 
1925                 /* add temp handler */
1926                 WM_event_add_modal_handler(C, op);
1927                 
1928                 return OPERATOR_RUNNING_MODAL;
1929         }
1930         
1931         return OPERATOR_PASS_THROUGH;
1932 }
1933
1934 static int area_join_cancel(bContext *C, wmOperator *op)
1935 {
1936         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1937         
1938         if (jd->sa1) {
1939                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1940                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1941         }
1942         if (jd->sa2) {
1943                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1944                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1945         }
1946         
1947         WM_event_add_notifier(C, NC_WINDOW, NULL);
1948         
1949         area_join_exit(C, op);
1950         
1951         return OPERATOR_CANCELLED;
1952 }
1953
1954 /* modal callback while selecting area (space) that will be removed */
1955 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1956 {
1957         bScreen *sc= CTX_wm_screen(C);
1958         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1959         
1960         /* execute the events */
1961         switch(event->type) {
1962                         
1963                 case MOUSEMOVE: 
1964                 {
1965                         ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1966                         int dir;
1967                         
1968                         if (sa) {                                       
1969                                 if (jd->sa1 != sa) {
1970                                         dir = area_getorientation(jd->sa1, sa);
1971                                         if (dir >= 0) {
1972                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1973                                                 jd->sa2 = sa;
1974                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1975                                         } 
1976                                         else {
1977                                                 /* we are not bordering on the previously selected area 
1978                                                  we check if area has common border with the one marked for removal
1979                                                  in this case we can swap areas.
1980                                                  */
1981                                                 dir = area_getorientation(sa, jd->sa2);
1982                                                 if (dir >= 0) {
1983                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1984                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1985                                                         jd->sa1 = jd->sa2;
1986                                                         jd->sa2 = sa;
1987                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1988                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1989                                                 } 
1990                                                 else {
1991                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1992                                                         jd->sa2 = NULL;
1993                                                 }
1994                                         }
1995                                         WM_event_add_notifier(C, NC_WINDOW, NULL);
1996                                 } 
1997                                 else {
1998                                         /* we are back in the area previously selected for keeping 
1999                                          * we swap the areas if possible to allow user to choose */
2000                                         if (jd->sa2 != NULL) {
2001                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
2002                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
2003                                                 jd->sa1 = jd->sa2;
2004                                                 jd->sa2 = sa;
2005                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
2006                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
2007                                                 dir = area_getorientation(jd->sa1, jd->sa2);
2008                                                 if (dir < 0) {
2009                                                         printf("oops, didn't expect that!\n");
2010                                                 }
2011                                         } 
2012                                         else {
2013                                                 dir = area_getorientation(jd->sa1, sa);
2014                                                 if (dir >= 0) {
2015                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
2016                                                         jd->sa2 = sa;
2017                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
2018                                                 }
2019                                         }
2020                                         WM_event_add_notifier(C, NC_WINDOW, NULL);
2021                                 }
2022                         }
2023                 }
2024                         break;
2025                 case LEFTMOUSE:
2026                         if(event->val==KM_RELEASE) {
2027                                 ED_area_tag_redraw(jd->sa1);
2028                                 ED_area_tag_redraw(jd->sa2);
2029
2030                                 area_join_apply(C, op);
2031                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2032                                 area_join_exit(C, op);
2033                                 return OPERATOR_FINISHED;
2034                         }
2035                         break;
2036                         
2037                 case RIGHTMOUSE:
2038                 case ESCKEY:
2039                         return area_join_cancel(C, op);
2040         }
2041         
2042         return OPERATOR_RUNNING_MODAL;
2043 }
2044
2045 /* Operator for joining two areas (space types) */
2046 static void SCREEN_OT_area_join(wmOperatorType *ot)
2047 {
2048         /* identifiers */
2049         ot->name= "Join area";
2050         ot->description= "Join selected areas into new window";
2051         ot->idname= "SCREEN_OT_area_join";
2052         
2053         /* api callbacks */
2054         ot->exec= area_join_exec;
2055         ot->invoke= area_join_invoke;
2056         ot->modal= area_join_modal;
2057         ot->poll= ED_operator_areaactive;
2058         
2059         ot->flag= OPTYPE_BLOCKING;
2060         
2061         /* rna */
2062         RNA_def_int(ot->srna, "min_x", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
2063         RNA_def_int(ot->srna, "min_y", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
2064         RNA_def_int(ot->srna, "max_x", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
2065         RNA_def_int(ot->srna, "max_y", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
2066 }
2067
2068 /* ************** repeat last operator ***************************** */
2069
2070 static int repeat_last_exec(bContext *C, wmOperator *UNUSED(op))
2071 {
2072         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
2073         
2074         if(lastop)
2075                 WM_operator_repeat(C, lastop);
2076         
2077         return OPERATOR_CANCELLED;
2078 }
2079
2080 static void SCREEN_OT_repeat_last(wmOperatorType *ot)
2081 {
2082         /* identifiers */
2083         ot->name= "Repeat Last";
2084         ot->description= "Repeat last action";
2085         ot->idname= "SCREEN_OT_repeat_last";
2086         
2087         /* api callbacks */
2088         ot->exec= repeat_last_exec;
2089         
2090         ot->poll= ED_operator_screenactive;
2091         
2092 }
2093
2094 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
2095 {
2096         wmWindowManager *wm= CTX_wm_manager(C);
2097         wmOperator *lastop;
2098         uiPopupMenu *pup;
2099         uiLayout *layout;
2100         int items, i;
2101         
2102         items= BLI_countlist(&wm->operators);
2103         if(items==0)
2104                 return OPERATOR_CANCELLED;
2105         
2106         pup= uiPupMenuBegin(C, op->type->name, 0);
2107         layout= uiPupMenuLayout(pup);
2108         
2109         for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
2110                 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
2111         
2112         uiPupMenuEnd(C, pup);
2113         
2114         return OPERATOR_CANCELLED;
2115 }
2116
2117 static int repeat_history_exec(bContext *C, wmOperator *op)
2118 {
2119         wmWindowManager *wm= CTX_wm_manager(C);
2120         
2121         op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
2122         if(op) {
2123                 /* let's put it as last operator in list */
2124                 BLI_remlink(&wm->operators, op);
2125                 BLI_addtail(&wm->operators, op);
2126                 
2127                 WM_operator_repeat(C, op);
2128         }
2129         
2130         return OPERATOR_FINISHED;
2131 }
2132
2133 static void SCREEN_OT_repeat_history(wmOperatorType *ot)
2134 {
2135         /* identifiers */
2136         ot->name= "Repeat History";
2137         ot->description= "Display menu for previous actions performed";
2138         ot->idname= "SCREEN_OT_repeat_history";
2139         
2140         /* api callbacks */
2141         ot->invoke= repeat_history_invoke;
2142         ot->exec= repeat_history_exec;
2143         
2144         ot->poll= ED_operator_screenactive;
2145         
2146         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
2147 }
2148
2149 /* ********************** redo operator ***************************** */
2150
2151 static int redo_last_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
2152 {
2153         wmWindowManager *wm= CTX_wm_manager(C);
2154         wmOperator *lastop;
2155         
2156         /* only for operators that are registered and did an undo push */
2157         for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
2158                 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
2159                         break;
2160         
2161         if(lastop)
2162                 WM_operator_redo_popup(C, lastop);
2163         
2164         return OPERATOR_CANCELLED;
2165 }
2166
2167 static void SCREEN_OT_redo_last(wmOperatorType *ot)
2168 {
2169         /* identifiers */
2170         ot->name= "Redo Last";
2171         ot->description= "Display menu for last action performed";
2172         ot->idname= "SCREEN_OT_redo_last";
2173         
2174         /* api callbacks */
2175         ot->invoke= redo_last_invoke;
2176         
2177         ot->poll= ED_operator_screenactive;
2178 }
2179
2180 /* ************** region four-split operator ***************************** */
2181
2182 /* insert a region in the area region list */
2183 static int region_quadview_exec(bContext *C, wmOperator *op)
2184 {
2185         ARegion *ar= CTX_wm_region(C);
2186         
2187         /* some rules... */
2188         if(ar->regiontype!=RGN_TYPE_WINDOW)
2189                 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
2190         else if(ar->alignment==RGN_ALIGN_QSPLIT) {
2191                 ScrArea *sa= CTX_wm_area(C);
2192                 ARegion *arn;
2193                 
2194                 /* keep current region */
2195                 ar->alignment= 0;
2196                 
2197                 if(sa->spacetype==SPACE_VIEW3D) {
2198                         RegionView3D *rv3d= ar->regiondata;
2199                         rv3d->viewlock= 0;
2200                         rv3d->rflag &= ~RV3D_CLIPPING;
2201                 }
2202                 
2203                 for(ar= sa->regionbase.first; ar; ar= arn) {
2204                         arn= ar->next;
2205                         if(ar->alignment==RGN_ALIGN_QSPLIT) {
2206                                 ED_region_exit(C, ar);
2207                                 BKE_area_region_free(sa->type, ar);
2208                                 BLI_remlink(&sa->regionbase, ar);
2209                                 MEM_freeN(ar);
2210                         }
2211                 }
2212                 ED_area_tag_redraw(sa);
2213                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2214         }
2215         else if(ar->next)
2216                 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
2217         else {
2218                 ScrArea *sa= CTX_wm_area(C);
2219                 ARegion *newar;
2220                 int count;
2221                 
2222                 ar->alignment= RGN_ALIGN_QSPLIT;
2223                 
2224                 for(count=0; count<3; count++) {
2225                         newar= BKE_area_region_copy(sa->type, ar);
2226                         BLI_addtail(&sa->regionbase, newar);
2227                 }
2228                 
2229                 /* lock views and set them */
2230                 if(sa->spacetype==SPACE_VIEW3D) {
2231                         RegionView3D *rv3d;
2232                         
2233                         rv3d= ar->regiondata;
2234                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_FRONT; rv3d->persp= RV3D_ORTHO;
2235                         if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2236                         
2237                         ar= ar->next;
2238                         rv3d= ar->regiondata;
2239                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_TOP; rv3d->persp= RV3D_ORTHO;
2240                         if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2241                         
2242                         ar= ar->next;
2243                         rv3d= ar->regiondata;
2244                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_RIGHT; rv3d->persp= RV3D_ORTHO;
2245                         if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2246                         
2247                         ar= ar->next;
2248                         rv3d= ar->regiondata;
2249                         rv3d->view= RV3D_VIEW_CAMERA; rv3d->persp= RV3D_CAMOB;
2250                         if (rv3d->localvd) {rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2251                 }
2252                 ED_area_tag_redraw(sa);
2253                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2254         }
2255         
2256         
2257         return OPERATOR_FINISHED;
2258 }
2259
2260 static void SCREEN_OT_region_quadview(wmOperatorType *ot)
2261 {
2262         /* identifiers */
2263         ot->name= "Toggle Quad View";
2264         ot->description= "Split selected area into camera, front, right & top views";
2265         ot->idname= "SCREEN_OT_region_quadview";
2266         
2267         /* api callbacks */
2268         //      ot->invoke= WM_operator_confirm;
2269         ot->exec= region_quadview_exec;
2270         ot->poll= ED_operator_region_view3d_active;
2271         ot->flag= 0;
2272 }
2273
2274
2275
2276 /* ************** region flip operator ***************************** */
2277
2278 /* flip a region alignment */
2279 static int region_flip_exec(bContext *C, wmOperator *UNUSED(op))
2280 {
2281         ARegion *ar= CTX_wm_region(C);
2282         
2283         if (!ar)
2284                 return OPERATOR_CANCELLED;
2285         
2286         if(ar->alignment==RGN_ALIGN_TOP)
2287                 ar->alignment= RGN_ALIGN_BOTTOM;
2288         else if(ar->alignment==RGN_ALIGN_BOTTOM)
2289                 ar->alignment= RGN_ALIGN_TOP;
2290         else if(ar->alignment==RGN_ALIGN_LEFT)
2291                 ar->alignment= RGN_ALIGN_RIGHT;
2292         else if(ar->alignment==RGN_ALIGN_RIGHT)
2293                 ar->alignment= RGN_ALIGN_LEFT;
2294
2295         ED_area_tag_redraw(CTX_wm_area(C));
2296         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2297         
2298         return OPERATOR_FINISHED;
2299 }
2300
2301
2302 static void SCREEN_OT_region_flip(wmOperatorType *ot)
2303 {
2304         /* identifiers */
2305         ot->name= "Flip Region";
2306         ot->idname= "SCREEN_OT_region_flip";
2307         
2308         /* api callbacks */
2309         ot->exec= region_flip_exec;
2310         ot->poll= ED_operator_areaactive;
2311         ot->flag= 0;
2312 }
2313
2314 /* ************** header flip operator ***************************** */
2315
2316 /* flip a header region alignment */
2317 static int header_flip_exec(bContext *C, wmOperator *UNUSED(op))
2318 {
2319         ARegion *ar= CTX_wm_region(C);
2320         
2321         /* find the header region 
2322          *      - try context first, but upon failing, search all regions in area...
2323          */
2324         if((ar == NULL) || (ar->regiontype != RGN_TYPE_HEADER)) {
2325                 ScrArea *sa= CTX_wm_area(C);
2326                 
2327                 /* loop over all regions until a matching one is found */
2328                 for (ar= sa->regionbase.first; ar; ar= ar->next) {
2329                         if(ar->regiontype == RGN_TYPE_HEADER)
2330                                 break;
2331                 }
2332                 
2333                 /* don't do anything if no region */
2334                 if(ar == NULL)
2335                         return OPERATOR_CANCELLED;
2336         }       
2337         
2338         /* copied from SCREEN_OT_region_flip */
2339         if(ar->alignment==RGN_ALIGN_TOP)
2340                 ar->alignment= RGN_ALIGN_BOTTOM;
2341         else if(ar->alignment==RGN_ALIGN_BOTTOM)
2342                 ar->alignment= RGN_ALIGN_TOP;
2343         else if(ar->alignment==RGN_ALIGN_LEFT)
2344                 ar->alignment= RGN_ALIGN_RIGHT;
2345         else if(ar->alignment==RGN_ALIGN_RIGHT)
2346                 ar->alignment= RGN_ALIGN_LEFT;
2347
2348         ED_area_tag_redraw(CTX_wm_area(C));
2349
2350         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2351         
2352         return OPERATOR_FINISHED;
2353 }
2354
2355
2356 static void SCREEN_OT_header_flip(wmOperatorType *ot)
2357 {
2358         /* identifiers */
2359         ot->name= "Flip Header Region";
2360         ot->idname= "SCREEN_OT_header_flip";
2361         
2362         /* api callbacks */
2363         ot->exec= header_flip_exec;
2364         
2365         ot->poll= ED_operator_areaactive;
2366         ot->flag= 0;
2367 }
2368
2369 /* ************** header tools operator ***************************** */
2370
2371 static int header_toolbox_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *UNUSED(event))
2372 {
2373         ScrArea *sa= CTX_wm_area(C);
2374         ARegion *ar= CTX_wm_region(C);
2375         uiPopupMenu *pup;
2376         uiLayout *layout;
2377         
2378         pup= uiPupMenuBegin(C, "Header", 0);
2379         layout= uiPupMenuLayout(pup);
2380         
2381         // XXX SCREEN_OT_region_flip doesn't work - gets wrong context for active region, so added custom operator
2382         if (ar->alignment == RGN_ALIGN_TOP)
2383                 uiItemO(layout, "Flip to Bottom", 0, "SCREEN_OT_header_flip");  
2384         else
2385                 uiItemO(layout, "Flip to Top", 0, "SCREEN_OT_header_flip");
2386         
2387         uiItemS(layout);
2388         
2389         /* file browser should be fullscreen all the time, but other regions can be maximised/restored... */
2390         if (sa->spacetype != SPACE_FILE) {
2391                 if (sa->full) 
2392                         uiItemO(layout, "Tile Area", 0, "SCREEN_OT_screen_full_area");
2393                 else
2394                         uiItemO(layout, "Maximize Area", 0, "SCREEN_OT_screen_full_area");
2395         }
2396         
2397         uiPupMenuEnd(C, pup);
2398         
2399         return OPERATOR_CANCELLED;
2400 }
2401
2402 void SCREEN_OT_header_toolbox(wmOperatorType *ot)
2403 {
2404         /* identifiers */
2405         ot->name= "Header Toolbox";
2406         ot->description="Display header region toolbox";
2407         ot->idname= "SCREEN_OT_header_toolbox";
2408         
2409         /* api callbacks */
2410         ot->invoke= header_toolbox_invoke;
2411 }
2412
2413 /* ****************** anim player, with timer ***************** */
2414
2415 static int match_area_with_refresh(int spacetype, int refresh)
2416 {
2417         switch (spacetype) {
2418                 case SPACE_TIME:
2419                         if (refresh & SPACE_TIME)
2420                                 return 1;
2421                         break;
2422         }
2423         
2424         return 0;
2425 }
2426
2427 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2428 {
2429         if(regiontype==RGN_TYPE_WINDOW) {
2430                 
2431                 switch (spacetype) {
2432                         case SPACE_VIEW3D:
2433                                 if(redraws & TIME_ALL_3D_WIN)
2434                                         return 1;
2435                                 break;
2436                         case SPACE_IPO:
2437                         case SPACE_ACTION:
2438                         case SPACE_NLA:
2439                                 if(redraws & TIME_ALL_ANIM_WIN)
2440                                         return 1;
2441                                 break;
2442                         case SPACE_TIME:
2443                                 /* if only 1 window or 3d windows, we do timeline too */
2444                                 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2445                                         return 1;
2446                                 break;
2447                         case SPACE_BUTS:
2448                                 if(redraws & TIME_ALL_BUTS_WIN)
2449                                         return 1;
2450                                 break;
2451                         case SPACE_SEQ:
2452                                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2453                                         return 1;
2454                                 break;
2455                         case SPACE_NODE:
2456                                 if(redraws & (TIME_NODES))
2457                                         return 1;
2458                                 break;
2459                         case SPACE_IMAGE:
2460                                 if(redraws & TIME_ALL_IMAGE_WIN)
2461                                         return 1;
2462                                 break;
2463                                 
2464                 }
2465         }
2466         else if(regiontype==RGN_TYPE_UI) {
2467                 if(redraws & TIME_ALL_BUTS_WIN)
2468                         return 1;
2469         }
2470         else if(regiontype==RGN_TYPE_HEADER) {
2471                 if(spacetype==SPACE_TIME)
2472                         return 1;
2473         }
2474         else if (regiontype==RGN_TYPE_PREVIEW) {
2475                 switch (spacetype) {
2476                         case SPACE_SEQ:
2477                                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2478                                         return 1;
2479                                 break;
2480                 }
2481         }
2482         return 0;
2483 }
2484
2485 static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
2486 {
2487         bScreen *screen= CTX_wm_screen(C);
2488
2489         if(screen->animtimer && screen->animtimer==event->customdata) {
2490                 Scene *scene= CTX_data_scene(C);
2491                 wmTimer *wt= screen->animtimer;
2492                 ScreenAnimData *sad= wt->customdata;
2493                 ScrArea *sa;
2494                 int sync;
2495                 float time;
2496                 
2497                 /* sync, don't sync, or follow scene setting */
2498                 if (sad->flag & ANIMPLAY_FLAG_SYNC) sync= 1;
2499                 else if (sad->flag & ANIMPLAY_FLAG_NO_SYNC) sync= 0;
2500                 else sync= (scene->flag & SCE_FRAME_DROP);
2501                 
2502                 if((scene->audio.flag & AUDIO_SYNC) && !(sad->flag & ANIMPLAY_FLAG_REVERSE) && finite(time = sound_sync_scene(scene)))
2503                         scene->r.cfra = time * FPS + 0.5;
2504                 else
2505                 {
2506                         if (sync) {
2507                                 int step = floor(wt->duration * FPS);
2508                                 /* skip frames */
2509                                 if (sad->flag & ANIMPLAY_FLAG_REVERSE)
2510                                         scene->r.cfra -= step;
2511                                 else
2512                                         scene->r.cfra += step;
2513                                 wt->duration -= ((float)step)/FPS;
2514                         }
2515                         else {
2516                                 /* one frame +/- */
2517                                 if (sad->flag & ANIMPLAY_FLAG_REVERSE)
2518                                         scene->r.cfra--;
2519                                 else
2520                                         scene->r.cfra++;
2521                         }
2522                 }
2523                 
2524                 /* reset 'jumped' flag before checking if we need to jump... */
2525                 sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
2526                 
2527                 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
2528                         /* jump back to end? */
2529                         if (PRVRANGEON) {
2530                                 if (scene->r.cfra < scene->r.psfra) {
2531                                         scene->r.cfra= scene->r.pefra;
2532                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2533                                 }
2534                         }
2535                         else {
2536                                 if (scene->r.cfra < scene->r.sfra) {
2537                                         scene->r.cfra= scene->r.efra;
2538                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2539                                 }
2540                         }
2541                 }
2542                 else {
2543                         /* jump back to start? */
2544                         if (PRVRANGEON) {
2545                                 if (scene->r.cfra > scene->r.pefra) {
2546                                         scene->r.cfra= scene->r.psfra;
2547                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2548                                 }
2549                         }
2550                         else {
2551                                 if (scene->r.cfra > scene->r.efra) {
2552                                         scene->r.cfra= scene->r.sfra;
2553                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2554                                 }
2555                         }
2556                 }
2557
2558                 /* next frame overriden by user action (pressed jump to first/last frame) */
2559                 if(sad->flag & ANIMPLAY_FLAG_USE_NEXT_FRAME) {
2560                         scene->r.cfra = sad->nextfra;
2561                         sad->flag &= ~ANIMPLAY_FLAG_USE_NEXT_FRAME;
2562                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2563                 }
2564                 
2565                 if (sad->flag & ANIMPLAY_FLAG_JUMPED)
2566                         sound_seek_scene(C);
2567                 
2568                 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2569                 ED_update_for_newframe(CTX_data_main(C), scene, screen, 1);
2570                 
2571                 for (sa= screen->areabase.first; sa; sa= sa->next) {
2572                         ARegion *ar;
2573                         for (ar= sa->regionbase.first; ar; ar= ar->next) {
2574                                 if (ar==sad->ar)
2575                                         ED_region_tag_redraw(ar);
2576                                 else
2577                                         if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2578                                                 ED_region_tag_redraw(ar);
2579                         }
2580                         
2581                         if (match_area_with_refresh(sa->spacetype, sad->refresh))
2582                                 ED_area_tag_refresh(sa);
2583                 }
2584                 
2585                 /* update frame rate info too 
2586                  * NOTE: this may not be accurate enough, since we might need this after modifiers/etc. 
2587                  * have been calculated instead of just before updates have been done?
2588                  */
2589                 ED_refresh_viewport_fps(C);
2590                 
2591                 /* recalculate the timestep for the timer now that we've finished calculating this,
2592                  * since the frames-per-second value may have been changed
2593                  */
2594                 // TODO: this may make evaluation a bit slower if the value doesn't change... any way to avoid this?
2595                 wt->timestep= (1.0/FPS);
2596                 
2597                 return OPERATOR_FINISHED;
2598         }
2599         return OPERATOR_PASS_THROUGH;
2600 }
2601
2602 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2603 {
2604         /* identifiers */
2605         ot->name= "Animation Step";
2606         ot->description= "Step through animation by position";
2607         ot->idname= "SCREEN_OT_animation_step";
2608         
2609         /* api callbacks */
2610         ot->invoke= screen_animation_step;
2611         
2612         ot->poll= ED_operator_screenactive;
2613         
2614 }
2615
2616 /* ****************** anim player, starts or ends timer ***************** */
2617
2618 /* toggle operator */
2619 int ED_screen_animation_play(bContext *C, int sync, int mode)
2620 {
2621         bScreen *screen= CTX_wm_screen(C);
2622         Scene *scene = CTX_data_scene(C);
2623
2624         if (screen->animtimer) {
2625                 /* stop playback now */
2626                 ED_screen_animation_timer(C, 0, 0, 0, 0);
2627                 sound_stop_scene(scene);
2628         }
2629         else {
2630                 ScrArea *sa= CTX_wm_area(C);
2631                 int refresh= SPACE_TIME;
2632                 
2633                 if (mode == 1) // XXX only play audio forwards!?
2634                         sound_play_scene(scene);
2635                 
2636                 /* timeline gets special treatment since it has it's own menu for determining redraws */
2637                 if ((sa) && (sa->spacetype == SPACE_TIME)) {
2638                         SpaceTime *stime= (SpaceTime *)sa->spacedata.first;
2639                         
2640                         ED_screen_animation_timer(C, stime->redraws, refresh, sync, mode);
2641                         
2642                         /* update region if TIME_REGION was set, to leftmost 3d window */
2643                         ED_screen_animation_timer_update(screen, stime->redraws, refresh);
2644                 }
2645                 else {
2646                         int redraws = TIME_REGION|TIME_ALL_3D_WIN;
2647                         
2648                         /* XXX - would like a better way to deal with this situation - Campbell */
2649                         if ((!sa) || (sa->spacetype == SPACE_SEQ)) {
2650                                 redraws |= TIME_SEQ;
2651                         }
2652                         
2653                         ED_screen_animation_timer(C, redraws, refresh, sync, mode);
2654                         
2655                         if(screen->animtimer) {
2656                                 wmTimer *wt= screen->animtimer;
2657                                 ScreenAnimData *sad= wt->customdata;
2658                                 
2659                                 sad->ar= CTX_wm_region(C);
2660                         }
2661                 }
2662         }
2663
2664         return OPERATOR_FINISHED;
2665 }
2666
2667 static int screen_animation_play_exec(bContext *C, wmOperator *op)
2668 {
2669         int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2670         int sync= -1;
2671         
2672         if (RNA_property_is_set(op->ptr, "sync"))
2673                 sync= (RNA_boolean_get(op->ptr, "sync"));
2674         
2675         return ED_screen_animation_play(C, sync, mode);
2676 }
2677
2678 static void SCREEN_OT_animation_play(wmOperatorType *ot)
2679 {
2680         /* identifiers */
2681         ot->name= "Play Animation";
2682         ot->description= "Play animation";
2683         ot->idname= "SCREEN_OT_animation_play";
2684         
2685         /* api callbacks */
2686         ot->exec= screen_animation_play_exec;
2687         
2688         ot->poll= ED_operator_screenactive;
2689         
2690         RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2691         RNA_def_boolean(ot->srna, "sync", 0, "Sync", "Drop frames to maintain framerate");
2692 }
2693
2694 static int screen_animation_cancel_exec(bContext *C, wmOperator *UNUSED(op))
2695 {
2696         bScreen *screen= CTX_wm_screen(C);
2697         
2698         if(screen->animtimer) {
2699                 ScreenAnimData *sad= screen->animtimer->customdata;
2700                 Scene *scene= CTX_data_scene(C);
2701                 
2702                 /* reset current frame before stopping, and just send a notifier to deal with the rest 
2703                  * (since playback still needs to be stopped)
2704                  */
2705                 scene->r.cfra= sad->sfra;
2706                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2707                 
2708                 /* call the other "toggling" operator to clean up now */
2709                 ED_screen_animation_play(C, 0, 0);
2710         }
2711
2712         return OPERATOR_PASS_THROUGH;
2713 }
2714
2715 static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
2716 {
2717         /* identifiers */
2718         ot->name= "Cancel Animation";
2719         ot->description= "Cancel animation, returning to the original frame";
2720         ot->idname= "SCREEN_OT_animation_cancel";
2721         
2722         /* api callbacks */
2723         ot->exec= screen_animation_cancel_exec;
2724         
2725         ot->poll= ED_operator_screenactive;
2726 }
2727
2728 /* ************** border select operator (template) ***************************** */
2729
2730 /* operator state vars used: (added by default WM callbacks)   
2731  xmin, ymin     
2732  xmax, ymax     
2733  
2734  customdata: the wmGesture pointer
2735  
2736  callbacks:
2737  
2738  exec() has to be filled in by user
2739  
2740  invoke() default WM function
2741  adds modal handler
2742  
2743  modal()        default WM function 
2744  accept modal events while doing it, calls exec(), handles ESC and border drawing
2745  
2746  poll() has to be filled in by user for context
2747  */
2748 #if 0
2749 static int border_select_do(bContext *C, wmOperator *op)
2750 {
2751         int event_type= RNA_int_get(op->ptr, "event_type");
2752         
2753         if(event_type==LEFTMOUSE)
2754                 printf("border select do select\n");
2755         else if(event_type==RIGHTMOUSE)
2756                 printf("border select deselect\n");
2757         else 
2758                 printf("border select do something\n");
2759         
2760         return 1;
2761 }
2762
2763 static void SCREEN_OT_border_select(wmOperatorType *ot)
2764 {
2765         /* identifiers */
2766         ot->name= "Border select";
2767         ot->idname= "SCREEN_OT_border_select";
2768         
2769         /* api callbacks */
2770         ot->exec= border_select_do;
2771         ot->invoke= WM_border_select_invoke;
2772         ot->modal= WM_border_select_modal;
2773         
2774         ot->poll= ED_operator_areaactive;
2775         
2776         /* rna */
2777         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2778         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2779         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2780         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2781         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2782         
2783 }
2784 #endif
2785
2786 /* *********************** generic fullscreen 'back' button *************** */
2787
2788
2789 static int fullscreen_back_exec(bContext *C, wmOperator *op)
2790 {
2791         bScreen *screen = CTX_wm_screen(C);
2792         ScrArea *sa=NULL;
2793         
2794         /* search current screen for 'fullscreen' areas */
2795         for (sa=screen->areabase.first; sa; sa=sa->next) {
2796                 if (sa->full) break;
2797         }
2798         if (!sa) {
2799                 BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found.");
2800                 return OPERATOR_CANCELLED;
2801         }
2802         
2803         ED_screen_full_restore(C, sa);
2804         
2805         return OPERATOR_FINISHED;
2806 }
2807
2808 static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
2809 {
2810         /* identifiers */
2811         ot->name= "Back to Previous Screen";
2812         ot->description= "Revert back to the original screen layout, before fullscreen area overlay";
2813         ot->idname= "SCREEN_OT_back_to_previous";
2814         
2815         /* api callbacks */
2816         ot->exec= fullscreen_back_exec;
2817         ot->poll= ED_operator_screenactive;
2818 }
2819
2820 /* *********** show user pref window ****** */
2821
2822 static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
2823 {
2824         rcti rect;
2825         int sizex, sizey;
2826         
2827         sizex= 800;
2828         sizey= 480;
2829         
2830         /* some magic to calculate postition */
2831         rect.xmin= event->x + CTX_wm_window(C)->posx - sizex/2;
2832         rect.ymin= event->y + CTX_wm_window(C)->posy - sizey/2;
2833         rect.xmax= rect.xmin + sizex;
2834         rect.ymax= rect.ymin + sizey;
2835         
2836         /* changes context! */
2837         WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS);
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