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