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