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