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