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