NLA SoC: Merge from 2.5
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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
29 #include "MEM_guardedalloc.h"
30
31 #include "BLI_arithb.h"
32 #include "BLI_blenlib.h"
33 #include "BLI_editVert.h"
34
35 #include "DNA_armature_types.h"
36 #include "DNA_image_types.h"
37 #include "DNA_object_types.h"
38 #include "DNA_mesh_types.h"
39 #include "DNA_curve_types.h"
40 #include "DNA_scene_types.h"
41
42 #include "BKE_blender.h"
43 #include "BKE_context.h"
44 #include "BKE_customdata.h"
45 #include "BKE_global.h"
46 #include "BKE_image.h"
47 #include "BKE_idprop.h"
48 #include "BKE_library.h"
49 #include "BKE_main.h"
50 #include "BKE_mesh.h"
51 #include "BKE_multires.h"
52 #include "BKE_report.h"
53 #include "BKE_screen.h"
54 #include "BKE_utildefines.h"
55
56 #include "WM_api.h"
57 #include "WM_types.h"
58
59 #include "ED_util.h"
60 #include "ED_screen.h"
61 #include "ED_mesh.h"
62 #include "ED_screen_types.h"
63
64 #include "RE_pipeline.h"
65 #include "IMB_imbuf.h"
66 #include "IMB_imbuf_types.h"
67
68 #include "RNA_access.h"
69 #include "RNA_define.h"
70
71 #include "UI_interface.h"
72 #include "UI_resources.h"
73
74 #include "screen_intern.h"      /* own module include */
75
76 /* ************** Exported Poll tests ********************** */
77
78 int ED_operator_regionactive(bContext *C)
79 {
80         if(CTX_wm_window(C)==NULL) return 0;
81         if(CTX_wm_screen(C)==NULL) return 0;
82         if(CTX_wm_region(C)==NULL) return 0;
83         return 1;
84 }
85
86 int ED_operator_areaactive(bContext *C)
87 {
88         if(CTX_wm_window(C)==NULL) return 0;
89         if(CTX_wm_screen(C)==NULL) return 0;
90         if(CTX_wm_area(C)==NULL) return 0;
91         return 1;
92 }
93
94 int ED_operator_screenactive(bContext *C)
95 {
96         if(CTX_wm_window(C)==NULL) return 0;
97         if(CTX_wm_screen(C)==NULL) return 0;
98         return 1;
99 }
100
101 /* when mouse is over area-edge */
102 int ED_operator_screen_mainwinactive(bContext *C)
103 {
104         if(CTX_wm_window(C)==NULL) return 0;
105         if(CTX_wm_screen(C)==NULL) return 0;
106         if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
107         return 1;
108 }
109
110 int ED_operator_scene_editable(bContext *C)
111 {
112         Scene *scene= CTX_data_scene(C);
113         if(scene && scene->id.lib==NULL)
114                 return 1;
115         return 0;
116 }
117
118 static int ed_spacetype_test(bContext *C, int type)
119 {
120         if(ED_operator_areaactive(C)) {
121                 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
122                 return sl && (sl->spacetype == type);
123         }
124         return 0;
125 }
126
127 int ED_operator_view3d_active(bContext *C)
128 {
129         return ed_spacetype_test(C, SPACE_VIEW3D);
130 }
131
132 int ED_operator_timeline_active(bContext *C)
133 {
134         return ed_spacetype_test(C, SPACE_TIME);
135 }
136
137 int ED_operator_outliner_active(bContext *C)
138 {
139         return ed_spacetype_test(C, SPACE_OUTLINER);
140 }
141
142 int ED_operator_file_active(bContext *C)
143 {
144         return ed_spacetype_test(C, SPACE_FILE);
145 }
146
147 int ED_operator_action_active(bContext *C)
148 {
149         return ed_spacetype_test(C, SPACE_ACTION);
150 }
151
152 int ED_operator_buttons_active(bContext *C)
153 {
154         return ed_spacetype_test(C, SPACE_BUTS);
155 }
156
157 int ED_operator_node_active(bContext *C)
158 {
159         if(ed_spacetype_test(C, SPACE_NODE)) {
160                 SpaceNode *snode= (SpaceNode *)CTX_wm_space_data(C);
161                 if(snode->edittree)
162                         return 1;
163         }
164         return 0;
165 }
166
167 // XXX rename
168 int ED_operator_ipo_active(bContext *C)
169 {
170         return ed_spacetype_test(C, SPACE_IPO);
171 }
172
173 int ED_operator_sequencer_active(bContext *C)
174 {
175         return ed_spacetype_test(C, SPACE_SEQ);
176 }
177
178 int ED_operator_image_active(bContext *C)
179 {
180         return ed_spacetype_test(C, SPACE_IMAGE);
181 }
182
183 int ED_operator_nla_active(bContext *C)
184 {
185         return ed_spacetype_test(C, SPACE_NLA);
186 }
187
188 int ED_operator_object_active(bContext *C)
189 {
190         return NULL != CTX_data_active_object(C);
191 }
192
193 int ED_operator_editmesh(bContext *C)
194 {
195         Object *obedit= CTX_data_edit_object(C);
196         if(obedit && obedit->type==OB_MESH)
197                 return NULL != ((Mesh *)obedit->data)->edit_mesh;
198         return 0;
199 }
200
201 int ED_operator_editarmature(bContext *C)
202 {
203         Object *obedit= CTX_data_edit_object(C);
204         if(obedit && obedit->type==OB_ARMATURE)
205                 return NULL != ((bArmature *)obedit->data)->edbo;
206         return 0;
207 }
208
209 int ED_operator_posemode(bContext *C)
210 {
211         Object *obact= CTX_data_active_object(C);
212         Object *obedit= CTX_data_edit_object(C);
213         
214         if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE))
215                 return (obact->flag & OB_POSEMODE)!=0;
216                 
217         return 0;
218 }
219
220
221 int ED_operator_uvedit(bContext *C)
222 {
223         Object *obedit= CTX_data_edit_object(C);
224         EditMesh *em= NULL;
225
226         if(obedit && obedit->type==OB_MESH)
227                 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
228
229         if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE))) {
230                 BKE_mesh_end_editmesh(obedit->data, em);
231                 return 1;
232         }
233
234         if(obedit)
235                 BKE_mesh_end_editmesh(obedit->data, em);
236         return 0;
237 }
238
239 int ED_operator_uvmap(bContext *C)
240 {
241         Object *obedit= CTX_data_edit_object(C);
242         EditMesh *em= NULL;
243
244         if(obedit && obedit->type==OB_MESH)
245                 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
246
247         if(em && (em->faces.first)) {
248                 BKE_mesh_end_editmesh(obedit->data, em);
249                 return 1;
250         }
251
252         if(obedit)
253                 BKE_mesh_end_editmesh(obedit->data, em);
254         return 0;
255 }
256
257 int ED_operator_editsurfcurve(bContext *C)
258 {
259         Object *obedit= CTX_data_edit_object(C);
260         if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
261                 return NULL != ((Curve *)obedit->data)->editnurb;
262         return 0;
263 }
264
265
266 int ED_operator_editcurve(bContext *C)
267 {
268         Object *obedit= CTX_data_edit_object(C);
269         if(obedit && obedit->type==OB_CURVE)
270                 return NULL != ((Curve *)obedit->data)->editnurb;
271         return 0;
272 }
273
274 int ED_operator_editsurf(bContext *C)
275 {
276         Object *obedit= CTX_data_edit_object(C);
277         if(obedit && obedit->type==OB_SURF)
278                 return NULL != ((Curve *)obedit->data)->editnurb;
279         return 0;
280 }
281
282 int ED_operator_editfont(bContext *C)
283 {
284         Object *obedit= CTX_data_edit_object(C);
285         if(obedit && obedit->type==OB_FONT)
286                 return NULL != ((Curve *)obedit->data)->editfont;
287         return 0;
288 }
289
290 /* *************************** action zone operator ************************** */
291
292 /* operator state vars used:  
293         none
294
295 functions:
296
297         apply() set actionzone event
298
299         exit()  free customdata
300         
301 callbacks:
302
303         exec()  never used
304
305         invoke() check if in zone  
306                 add customdata, put mouseco and area in it
307                 add modal handler
308
309         modal() accept modal events while doing it
310                 call apply() with gesture info, active window, nonactive window
311                 call exit() and remove handler when LMB confirm
312
313 */
314
315 typedef struct sActionzoneData {
316         ScrArea *sa1, *sa2;
317         AZone *az;
318         int x, y, gesture_dir, modifier;
319 } sActionzoneData;
320
321 /* used by other operators too */
322 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
323 {
324         ScrArea *sa= NULL;
325         sa= scr->areabase.first;
326         while(sa) {
327                 if(BLI_in_rcti(&sa->totrct, x, y)) break;
328                 sa= sa->next;
329         }
330         
331         return sa;
332 }
333
334 /* quick poll to save operators to be created and handled */
335 static int actionzone_area_poll(bContext *C)
336 {
337         wmWindow *win= CTX_wm_window(C);
338         ScrArea *sa= CTX_wm_area(C);
339         
340         if(sa && win) {
341                 AZone *az;
342                 int x= win->eventstate->x;
343                 int y= win->eventstate->y;
344                 
345                 for(az= sa->actionzones.first; az; az= az->next)
346                         if(BLI_in_rcti(&az->rect, x, y))
347                            return 1;
348         }       
349         return 0;
350 }
351
352 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
353 {
354         AZone *az= NULL;
355         
356         for(az= sa->actionzones.first; az; az= az->next) {
357                 if(BLI_in_rcti(&az->rect, x, y)) {
358                         if(az->type == AZONE_AREA) {
359                                 if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y)) 
360                                         break;
361                         }
362                         else if(az->type == AZONE_REGION) {
363                                 float v1[2], v2[2], v3[2], pt[2];
364                                 
365                                 v1[0]= az->x1; v1[1]= az->y1;
366                                 v2[0]= az->x2; v2[1]= az->y2;
367                                 v3[0]= az->x3; v3[1]= az->y3;
368                                 pt[0]= x; pt[1]=y;
369
370                                 if(IsPointInTri2D(v1, v2, v3, pt)) 
371                                         break;
372                         }
373                 }
374         }
375         
376         return az;
377 }
378
379
380 static void actionzone_exit(bContext *C, wmOperator *op)
381 {
382         if(op->customdata)
383                 MEM_freeN(op->customdata);
384         op->customdata= NULL;
385 }
386
387 /* send EVT_ACTIONZONE event */
388 static void actionzone_apply(bContext *C, wmOperator *op, int type)
389 {
390         wmEvent event;
391         wmWindow *win= CTX_wm_window(C);
392         sActionzoneData *sad= op->customdata;
393         
394         sad->modifier= RNA_int_get(op->ptr, "modifier");
395         
396         event= *(win->eventstate);      /* XXX huh huh? make api call */
397         if(type==AZONE_AREA)
398                 event.type= EVT_ACTIONZONE_AREA;
399         else
400                 event.type= EVT_ACTIONZONE_REGION;
401         event.customdata= op->customdata;
402         event.customdatafree= TRUE;
403         op->customdata= NULL;
404         
405         wm_event_add(win, &event);
406 }
407
408 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
409 {
410         AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
411         sActionzoneData *sad;
412         
413         /* quick escape */
414         if(az==NULL)
415                 return OPERATOR_PASS_THROUGH;
416         
417         /* ok we do the actionzone */
418         sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
419         sad->sa1= CTX_wm_area(C);
420         sad->az= az;
421         sad->x= event->x; sad->y= event->y;
422         
423         /* region azone directly reacts on mouse clicks */
424         if(sad->az->type==AZONE_REGION) {
425                 actionzone_apply(C, op, AZONE_REGION);
426                 actionzone_exit(C, op);
427                 return OPERATOR_FINISHED;
428         }
429         else {
430                 /* add modal handler */
431                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
432                 
433                 return OPERATOR_RUNNING_MODAL;
434         }
435 }
436
437
438 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
439 {
440         sActionzoneData *sad= op->customdata;
441         int deltax, deltay;
442         int mindelta= sad->az->type==AZONE_REGION?1:12;
443         
444         switch(event->type) {
445                 case MOUSEMOVE:
446                         /* calculate gesture direction */
447                         deltax= (event->x - sad->x);
448                         deltay= (event->y - sad->y);
449                         
450                         if(deltay > ABS(deltax))
451                                 sad->gesture_dir= 'n';
452                         else if(deltax > ABS(deltay))
453                                 sad->gesture_dir= 'e';
454                         else if(deltay < -ABS(deltax))
455                                 sad->gesture_dir= 's';
456                         else
457                                 sad->gesture_dir= 'w';
458                         
459                         /* gesture is large enough? */
460                         if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
461                                 
462                                 /* second area, for join */
463                                 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
464                                 /* apply sends event */
465                                 actionzone_apply(C, op, sad->az->type);
466                                 actionzone_exit(C, op);
467                                 
468                                 return OPERATOR_FINISHED;
469                         }
470                                 break;
471                 case ESCKEY:
472                         actionzone_exit(C, op);
473                         return OPERATOR_CANCELLED;
474                 case LEFTMOUSE:                         
475                         actionzone_exit(C, op);
476                         return OPERATOR_CANCELLED;
477
478         }
479         
480         return OPERATOR_RUNNING_MODAL;
481 }
482
483 void SCREEN_OT_actionzone(wmOperatorType *ot)
484 {
485         /* identifiers */
486         ot->name= "Handle area action zones";
487         ot->idname= "SCREEN_OT_actionzone";
488         
489         ot->invoke= actionzone_invoke;
490         ot->modal= actionzone_modal;
491         
492         ot->poll= actionzone_area_poll;
493         RNA_def_int(ot->srna, "modifier", 0, 0, 2, "modifier", "modifier state", 0, 2);
494 }
495
496 /* ************** swap area operator *********************************** */
497
498 /* operator state vars used:  
499                                         sa1             start area
500                                         sa2             area to swap with
501
502         functions:
503
504         init()   set custom data for operator, based on actionzone event custom data
505
506         cancel()        cancel the operator
507
508         exit()  cleanup, send notifier
509
510         callbacks:
511
512         invoke() gets called on shift+lmb drag in actionzone
513             call init(), add handler
514
515         modal()  accept modal events while doing it
516
517 */
518
519 typedef struct sAreaSwapData {
520         ScrArea *sa1, *sa2;
521 } sAreaSwapData;
522
523 static int area_swap_init(bContext *C, wmOperator *op, wmEvent *event)
524 {
525         sAreaSwapData *sd= NULL;
526         sActionzoneData *sad= event->customdata;
527
528         if(sad==NULL || sad->sa1==NULL)
529                                         return 0;
530         
531         sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
532         sd->sa1= sad->sa1;
533         sd->sa2= sad->sa2;
534         op->customdata= sd;
535
536         return 1;
537 }
538
539
540 static void area_swap_exit(bContext *C, wmOperator *op)
541 {
542         if(op->customdata)
543                 MEM_freeN(op->customdata);
544         op->customdata= NULL;
545 }
546
547 static int area_swap_cancel(bContext *C, wmOperator *op)
548 {
549         area_swap_exit(C, op);
550         return OPERATOR_CANCELLED;
551 }
552
553 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
554 {
555
556         if(!area_swap_init(C, op, event))
557                 return OPERATOR_PASS_THROUGH;
558
559         /* add modal handler */
560         WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
561         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
562         
563         return OPERATOR_RUNNING_MODAL;
564
565 }
566
567 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
568 {
569         sActionzoneData *sad= op->customdata;
570
571         switch(event->type) {
572                 case MOUSEMOVE:
573                         /* second area, for join */
574                         sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
575                         break;
576                 case LEFTMOUSE: /* release LMB */
577                         if(event->val==0) {
578                                 if(sad->sa1 == sad->sa2) {
579
580                                         return area_swap_cancel(C, op);
581                                 }
582                                 ED_area_swapspace(C, sad->sa1, sad->sa2);
583
584                                 area_swap_exit(C, op);
585
586                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
587
588                                 return OPERATOR_FINISHED;
589                         }
590                         break;
591
592                 case ESCKEY:
593                         return area_swap_cancel(C, op);
594         }
595         return OPERATOR_RUNNING_MODAL;
596 }
597
598 static void SCREEN_OT_area_swap(wmOperatorType *ot)
599 {
600         ot->name= "Swap areas";
601         ot->idname= "SCREEN_OT_area_swap";
602
603         ot->invoke= area_swap_invoke;
604         ot->modal= area_swap_modal;
605         ot->poll= ED_operator_areaactive;
606 }
607
608 /* *********** Duplicate area as new window operator ****************** */
609
610 /* operator callback */
611 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
612 {
613         wmWindow *newwin, *win;
614         bScreen *newsc, *sc;
615         ScrArea *sa;
616         rcti rect;
617         
618         win= CTX_wm_window(C);
619         sc= CTX_wm_screen(C);
620         sa= CTX_wm_area(C);
621         
622         /* XXX hrmf! */
623         if(event->type==EVT_ACTIONZONE_AREA) {
624                 sActionzoneData *sad= event->customdata;
625
626                 if(sad==NULL)
627                         return OPERATOR_PASS_THROUGH;
628         
629                 sa= sad->sa1;
630         }
631         
632         /*  poll() checks area context, but we don't accept full-area windows */
633         if(sc->full != SCREENNORMAL) {
634                 if(event->type==EVT_ACTIONZONE_AREA)
635                         actionzone_exit(C, op);
636                 return OPERATOR_CANCELLED;
637         }
638         
639         /* adds window to WM */
640         rect= sa->totrct;
641         BLI_translate_rcti(&rect, win->posx, win->posy);
642         newwin= WM_window_open(C, &rect);
643         
644         /* allocs new screen and adds to newly created window, using window size */
645         newsc= screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
646         newwin->screen= newsc;
647         
648         /* copy area to new screen */
649         area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
650         
651         /* screen, areas init */
652         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
653
654         if(event->type==EVT_ACTIONZONE_AREA)
655                 actionzone_exit(C, op);
656         
657         return OPERATOR_FINISHED;
658 }
659
660 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
661 {
662         ot->name= "Duplicate Area into New Window";
663         ot->idname= "SCREEN_OT_area_dupli";
664         
665         ot->invoke= area_dupli_invoke;
666         ot->poll= ED_operator_areaactive;
667 }
668
669
670 /* ************** move area edge operator *********************************** */
671
672 /* operator state vars used:  
673            x, y                         mouse coord near edge
674            delta            movement of edge
675
676         functions:
677
678         init()   set default property values, find edge based on mouse coords, test
679             if the edge can be moved, select edges, calculate min and max movement
680
681         apply() apply delta on selection
682
683         exit()  cleanup, send notifier
684
685         cancel() cancel moving
686
687         callbacks:
688
689         exec()   execute without any user interaction, based on properties
690             call init(), apply(), exit()
691
692         invoke() gets called on mouse click near edge
693             call init(), add handler
694
695         modal()  accept modal events while doing it
696                         call apply() with delta motion
697             call exit() and remove handler
698
699 */
700
701 typedef struct sAreaMoveData {
702         int bigger, smaller, origval;
703         char dir;
704 } sAreaMoveData;
705
706 /* helper call to move area-edge, sets limits */
707 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
708 {
709         ScrArea *sa;
710         
711         /* we check all areas and test for free space with MINSIZE */
712         *bigger= *smaller= 100000;
713         
714         for(sa= sc->areabase.first; sa; sa= sa->next) {
715                 if(dir=='h') {
716                         int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
717                         
718                         /* if top or down edge selected, test height */
719                         if(sa->v1->flag && sa->v4->flag)
720                                 *bigger= MIN2(*bigger, y1);
721                         else if(sa->v2->flag && sa->v3->flag)
722                                 *smaller= MIN2(*smaller, y1);
723                 }
724                 else {
725                         int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
726                         
727                         /* if left or right edge selected, test width */
728                         if(sa->v1->flag && sa->v2->flag)
729                                 *bigger= MIN2(*bigger, x1);
730                         else if(sa->v3->flag && sa->v4->flag)
731                                 *smaller= MIN2(*smaller, x1);
732                 }
733         }
734 }
735
736 /* validate selection inside screen, set variables OK */
737 /* return 0: init failed */
738 static int area_move_init (bContext *C, wmOperator *op)
739 {
740         bScreen *sc= CTX_wm_screen(C);
741         ScrEdge *actedge;
742         sAreaMoveData *md;
743         int x, y;
744
745         /* required properties */
746         x= RNA_int_get(op->ptr, "x");
747         y= RNA_int_get(op->ptr, "y");
748
749         /* setup */
750         actedge= screen_find_active_scredge(sc, x, y);
751         if(actedge==NULL) return 0;
752
753         md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
754         op->customdata= md;
755
756         md->dir= scredge_is_horizontal(actedge)?'h':'v';
757         if(md->dir=='h') md->origval= actedge->v1->vec.y;
758         else md->origval= actedge->v1->vec.x;
759         
760         select_connected_scredge(sc, actedge);
761         /* now all vertices with 'flag==1' are the ones that can be moved. */
762
763         area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
764         
765         return 1;
766 }
767
768 /* moves selected screen edge amount of delta, used by split & move */
769 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
770 {
771         wmWindow *win= CTX_wm_window(C);
772         bScreen *sc= CTX_wm_screen(C);
773         ScrVert *v1;
774         
775         delta= CLAMPIS(delta, -smaller, bigger);
776         
777         for (v1= sc->vertbase.first; v1; v1= v1->next) {
778                 if (v1->flag) {
779                         /* that way a nice AREAGRID  */
780                         if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
781                                 v1->vec.x= origval + delta;
782                                 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
783                         }
784                         if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
785                                 v1->vec.y= origval + delta;
786
787                                 v1->vec.y+= AREAGRID-1;
788                                 v1->vec.y-= (v1->vec.y % AREAGRID);
789                                 
790                                 /* prevent too small top header */
791                                 if(v1->vec.y > win->sizey-AREAMINY)
792                                         v1->vec.y= win->sizey-AREAMINY;
793                         }
794                 }
795         }
796
797         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
798 }
799
800 static void area_move_apply(bContext *C, wmOperator *op)
801 {
802         sAreaMoveData *md= op->customdata;
803         int delta;
804         
805         delta= RNA_int_get(op->ptr, "delta");
806         area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
807 }
808
809 static void area_move_exit(bContext *C, wmOperator *op)
810 {
811         if(op->customdata)
812                 MEM_freeN(op->customdata);
813         op->customdata= NULL;
814         
815         /* this makes sure aligned edges will result in aligned grabbing */
816         removedouble_scrverts(CTX_wm_screen(C));
817         removedouble_scredges(CTX_wm_screen(C));
818 }
819
820 static int area_move_exec(bContext *C, wmOperator *op)
821 {
822         if(!area_move_init(C, op))
823                 return OPERATOR_CANCELLED;
824         
825         area_move_apply(C, op);
826         area_move_exit(C, op);
827         
828         return OPERATOR_FINISHED;
829 }
830
831 /* interaction callback */
832 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
833 {
834         RNA_int_set(op->ptr, "x", event->x);
835         RNA_int_set(op->ptr, "y", event->y);
836
837         if(!area_move_init(C, op)) 
838                 return OPERATOR_PASS_THROUGH;
839         
840         /* add temp handler */
841         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
842         
843         return OPERATOR_RUNNING_MODAL;
844 }
845
846 static int area_move_cancel(bContext *C, wmOperator *op)
847 {
848
849         RNA_int_set(op->ptr, "delta", 0);
850         area_move_apply(C, op);
851         area_move_exit(C, op);
852
853         return OPERATOR_CANCELLED;
854 }
855
856 /* modal callback for while moving edges */
857 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
858 {
859         sAreaMoveData *md;
860         int delta, x, y;
861
862         md= op->customdata;
863
864         x= RNA_int_get(op->ptr, "x");
865         y= RNA_int_get(op->ptr, "y");
866
867         /* execute the events */
868         switch(event->type) {
869                 case MOUSEMOVE:
870                         delta= (md->dir == 'v')? event->x - x: event->y - y;
871                         RNA_int_set(op->ptr, "delta", delta);
872
873                         area_move_apply(C, op);
874                         break;
875                         
876                 case LEFTMOUSE:
877                         if(event->val==0) {
878                                 area_move_exit(C, op);
879                                 return OPERATOR_FINISHED;
880                         }
881                         break;
882                         
883                 case ESCKEY:
884                         return area_move_cancel(C, op);
885         }
886         
887         return OPERATOR_RUNNING_MODAL;
888 }
889
890 void SCREEN_OT_area_move(wmOperatorType *ot)
891 {
892         /* identifiers */
893         ot->name= "Move area edges";
894         ot->idname= "SCREEN_OT_area_move";
895
896         ot->exec= area_move_exec;
897         ot->invoke= area_move_invoke;
898         ot->cancel= area_move_cancel;
899         ot->modal= area_move_modal;
900
901         ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
902
903         /* rna */
904         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
905         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
906         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
907 }
908
909 /* ************** split area operator *********************************** */
910
911 /* 
912 operator state vars:  
913         fac              spit point
914         dir              direction 'v' or 'h'
915
916 operator customdata:
917         area                    pointer to (active) area
918         x, y                    last used mouse pos
919         (more, see below)
920
921 functions:
922
923         init()   set default property values, find area based on context
924
925         apply() split area based on state vars
926
927         exit()  cleanup, send notifier
928
929         cancel() remove duplicated area
930
931 callbacks:
932
933         exec()   execute without any user interaction, based on state vars
934             call init(), apply(), exit()
935
936         invoke() gets called on mouse click in action-widget
937             call init(), add modal handler
938                         call apply() with initial motion
939
940         modal()  accept modal events while doing it
941             call move-areas code with delta motion
942             call exit() or cancel() and remove handler
943
944 */
945
946 #define SPLIT_STARTED   1
947 #define SPLIT_PROGRESS  2
948
949 typedef struct sAreaSplitData
950 {
951         int x, y;       /* last used mouse position */
952         
953         int origval;                    /* for move areas */
954         int bigger, smaller;    /* constraints for moving new edge */
955         int delta;                              /* delta move edge */
956         int origmin, origsize;  /* to calculate fac, for property storage */
957
958         ScrEdge *nedge;                 /* new edge */
959         ScrArea *sarea;                 /* start area */
960         ScrArea *narea;                 /* new area */
961 } sAreaSplitData;
962
963 /* generic init, no UI stuff here */
964 static int area_split_init(bContext *C, wmOperator *op)
965 {
966         ScrArea *sa= CTX_wm_area(C);
967         sAreaSplitData *sd;
968         int dir;
969         
970         /* required context */
971         if(sa==NULL) return 0;
972         
973         /* required properties */
974         dir= RNA_enum_get(op->ptr, "direction");
975         
976         /* minimal size */
977         if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
978         if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
979            
980         /* custom data */
981         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
982         op->customdata= sd;
983         
984         sd->sarea= sa;
985         sd->origsize= dir=='v' ? sa->winx:sa->winy;
986         sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
987         
988         return 1;
989 }
990
991 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
992 /* used with split operator */
993 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
994 {
995         ScrVert *sav1= sa->v1;
996         ScrVert *sav2= sa->v2;
997         ScrVert *sav3= sa->v3;
998         ScrVert *sav4= sa->v4;
999         ScrVert *sbv1= sb->v1;
1000         ScrVert *sbv2= sb->v2;
1001         ScrVert *sbv3= sb->v3;
1002         ScrVert *sbv4= sb->v4;
1003         
1004         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
1005                 return screen_findedge(screen, sav1, sav2);
1006         }
1007         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
1008                 return screen_findedge(screen, sav2, sav3);
1009         }
1010         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
1011                 return screen_findedge(screen, sav3, sav4);
1012         }
1013         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
1014                 return screen_findedge(screen, sav1, sav4);
1015         }
1016
1017         return NULL;
1018 }
1019
1020
1021 /* do the split, return success */
1022 static int area_split_apply(bContext *C, wmOperator *op)
1023 {
1024         bScreen *sc= CTX_wm_screen(C);
1025         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1026         float fac;
1027         int dir;
1028         
1029         fac= RNA_float_get(op->ptr, "factor");
1030         dir= RNA_enum_get(op->ptr, "direction");
1031
1032         sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
1033         
1034         if(sd->narea) {
1035                 ScrVert *sv;
1036                 
1037                 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
1038         
1039                 /* select newly created edge, prepare for moving edge */
1040                 for(sv= sc->vertbase.first; sv; sv= sv->next)
1041                         sv->flag = 0;
1042                 
1043                 sd->nedge->v1->flag= 1;
1044                 sd->nedge->v2->flag= 1;
1045
1046                 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
1047                 else sd->origval= sd->nedge->v1->vec.x;
1048
1049                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1050                 
1051                 return 1;
1052         }               
1053         
1054         return 0;
1055 }
1056
1057 static void area_split_exit(bContext *C, wmOperator *op)
1058 {
1059         if (op->customdata) {
1060                 MEM_freeN(op->customdata);
1061                 op->customdata = NULL;
1062         }
1063         
1064         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1065
1066         /* this makes sure aligned edges will result in aligned grabbing */
1067         removedouble_scrverts(CTX_wm_screen(C));
1068         removedouble_scredges(CTX_wm_screen(C));
1069 }
1070
1071
1072 /* UI callback, adds new handler */
1073 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1074 {
1075         sAreaSplitData *sd;
1076         
1077         if(event->type==EVT_ACTIONZONE_AREA) {
1078                 sActionzoneData *sad= event->customdata;
1079                 int dir;
1080
1081                 if(sad->modifier>0) {
1082                         return OPERATOR_PASS_THROUGH;
1083                 }
1084                 
1085                 /* no full window splitting allowed */
1086                 if(CTX_wm_area(C)->full)
1087                         return OPERATOR_PASS_THROUGH;
1088                 
1089                 /* verify *sad itself */
1090                 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1091                         return OPERATOR_PASS_THROUGH;
1092                 
1093                 /* is this our *sad? if areas not equal it should be passed on */
1094                 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1095                         return OPERATOR_PASS_THROUGH;
1096                 
1097                 /* prepare operator state vars */
1098                 if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
1099                         dir= 'h';
1100                         RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1101                 }
1102                 else {
1103                         dir= 'v';
1104                         RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1105                 }
1106                 RNA_enum_set(op->ptr, "direction", dir);
1107
1108                 /* general init, also non-UI case, adds customdata, sets area and defaults */
1109                 if(!area_split_init(C, op))
1110                         return OPERATOR_PASS_THROUGH;
1111                 
1112                 sd= (sAreaSplitData *)op->customdata;
1113                 
1114                 sd->x= event->x;
1115                 sd->y= event->y;
1116                 
1117                 /* do the split */
1118                 if(area_split_apply(C, op)) {
1119                         area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1120                         
1121                         /* add temp handler for edge move or cancel */
1122                         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1123                         
1124                         return OPERATOR_RUNNING_MODAL;
1125                 }
1126                 
1127         }
1128         else {
1129                 /* nonmodal for now */
1130                 return op->type->exec(C, op);
1131         }
1132         
1133         return OPERATOR_PASS_THROUGH;
1134 }
1135
1136 /* function to be called outside UI context, or for redo */
1137 static int area_split_exec(bContext *C, wmOperator *op)
1138 {
1139         
1140         if(!area_split_init(C, op))
1141                 return OPERATOR_CANCELLED;
1142         
1143         area_split_apply(C, op);
1144         area_split_exit(C, op);
1145         
1146         return OPERATOR_FINISHED;
1147 }
1148
1149
1150 static int area_split_cancel(bContext *C, wmOperator *op)
1151 {
1152         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1153
1154         if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1155                 if (CTX_wm_area(C) == sd->narea) {
1156                         CTX_wm_area_set(C, NULL);
1157                         CTX_wm_region_set(C, NULL);
1158                 }
1159                 sd->narea = NULL;
1160         }
1161         area_split_exit(C, op);
1162
1163         return OPERATOR_CANCELLED;
1164 }
1165
1166 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1167 {
1168         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1169         float fac;
1170         int dir;
1171
1172         /* execute the events */
1173         switch(event->type) {
1174                 case MOUSEMOVE:
1175                         dir= RNA_enum_get(op->ptr, "direction");
1176                         
1177                         sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1178                         area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1179                         
1180                         fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1181                         RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1182                         
1183                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1184                         break;
1185                         
1186                 case LEFTMOUSE:
1187                         if(event->val==0) { /* mouse up */
1188                                 area_split_exit(C, op);
1189                                 return OPERATOR_FINISHED;
1190                         }
1191                         break;
1192                 case RIGHTMOUSE: /* cancel operation */
1193                 case ESCKEY:
1194                         return area_split_cancel(C, op);
1195         }
1196         
1197         return OPERATOR_RUNNING_MODAL;
1198 }
1199
1200 static EnumPropertyItem prop_direction_items[] = {
1201         {'h', "HORIZONTAL", "Horizontal", ""},
1202         {'v', "VERTICAL", "Vertical", ""},
1203         {0, NULL, NULL, NULL}};
1204
1205 void SCREEN_OT_area_split(wmOperatorType *ot)
1206 {
1207         ot->name = "Split area";
1208         ot->idname = "SCREEN_OT_area_split";
1209         
1210         ot->exec= area_split_exec;
1211         ot->invoke= area_split_invoke;
1212         ot->modal= area_split_modal;
1213         
1214         ot->poll= ED_operator_areaactive;
1215         ot->flag= OPTYPE_REGISTER;
1216         
1217         /* rna */
1218         RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1219         RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1220 }
1221
1222
1223
1224 /* ************** scale region edge operator *********************************** */
1225
1226 typedef struct RegionMoveData {
1227         ARegion *ar;
1228         int bigger, smaller, origval;
1229         int origx, origy;
1230         char edge;
1231         
1232 } RegionMoveData;
1233
1234 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1235 {
1236         sActionzoneData *sad= event->customdata;
1237         AZone *az= sad->az;
1238         
1239         if(az->ar) {
1240                 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1241                 
1242                 op->customdata= rmd;
1243                 
1244                 rmd->ar= az->ar;
1245                 rmd->edge= az->edge;
1246                 rmd->origx= event->x;
1247                 rmd->origy= event->y;
1248                 if(rmd->edge=='l' || rmd->edge=='r') 
1249                         rmd->origval= rmd->ar->type->minsizex;
1250                 else
1251                         rmd->origval= rmd->ar->type->minsizey;
1252                 
1253                 /* add temp handler */
1254                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1255                 
1256                 return OPERATOR_RUNNING_MODAL;
1257         }
1258         
1259         return OPERATOR_FINISHED;
1260 }
1261
1262 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1263 {
1264         RegionMoveData *rmd= op->customdata;
1265         int delta;
1266         
1267         /* execute the events */
1268         switch(event->type) {
1269                 case MOUSEMOVE:
1270                         
1271                         if(rmd->edge=='l' || rmd->edge=='r') {
1272                                 delta= event->x - rmd->origx;
1273                                 if(rmd->edge=='l') delta= -delta;
1274                                 rmd->ar->type->minsizex= rmd->origval + delta;
1275                                 CLAMP(rmd->ar->type->minsizex, 0, 1000);
1276                                 if(rmd->ar->type->minsizex < 10) {
1277                                         rmd->ar->type->minsizex= 10;
1278                                         rmd->ar->flag |= RGN_FLAG_HIDDEN;
1279                                 }
1280                                 else
1281                                         rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1282                         }
1283                         else {
1284                                 delta= event->y - rmd->origy;
1285                                 if(rmd->edge=='b') delta= -delta;
1286                                 rmd->ar->type->minsizey= rmd->origval + delta;
1287                                 CLAMP(rmd->ar->type->minsizey, 0, 1000);
1288                                 if(rmd->ar->type->minsizey < 10) {
1289                                         rmd->ar->type->minsizey= 10;
1290                                         rmd->ar->flag |= RGN_FLAG_HIDDEN;
1291                                 }
1292                                 else
1293                                         rmd->ar->flag &= ~RGN_FLAG_HIDDEN;
1294                         }
1295                         
1296                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1297                                         
1298                         break;
1299                         
1300                 case LEFTMOUSE:
1301                         if(event->val==0) {
1302                                 
1303                                 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1304                                         rmd->ar->flag ^= RGN_FLAG_HIDDEN;
1305                                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1306                                 }                               
1307                                 MEM_freeN(op->customdata);
1308                                 op->customdata = NULL;
1309
1310                                 return OPERATOR_FINISHED;
1311                         }
1312                         break;
1313                         
1314                 case ESCKEY:
1315                         ;
1316         }
1317         
1318         return OPERATOR_RUNNING_MODAL;
1319 }
1320
1321
1322 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1323 {
1324         /* identifiers */
1325         ot->name= "Scale Region Size";
1326         ot->idname= "SCREEN_OT_region_scale";
1327         
1328         ot->invoke= region_scale_invoke;
1329         ot->modal= region_scale_modal;
1330         
1331         ot->poll= ED_operator_areaactive;
1332 }
1333
1334
1335 /* ************** frame change operator ***************************** */
1336
1337
1338 /* function to be called outside UI context, or for redo */
1339 static int frame_offset_exec(bContext *C, wmOperator *op)
1340 {
1341         int delta;
1342
1343         delta = RNA_int_get(op->ptr, "delta");
1344
1345         CTX_data_scene(C)->r.cfra += delta;
1346
1347         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1348
1349         return OPERATOR_FINISHED;
1350 }
1351
1352 void SCREEN_OT_frame_offset(wmOperatorType *ot)
1353 {
1354         ot->name = "Frame Offset";
1355         ot->idname = "SCREEN_OT_frame_offset";
1356
1357         ot->exec= frame_offset_exec;
1358
1359         ot->poll= ED_operator_screenactive;
1360         ot->flag= 0;
1361
1362         /* rna */
1363         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1364 }
1365
1366 /* ************** switch screen operator ***************************** */
1367
1368
1369 /* function to be called outside UI context, or for redo */
1370 static int screen_set_exec(bContext *C, wmOperator *op)
1371 {
1372         bScreen *screen= CTX_wm_screen(C);
1373         ScrArea *sa= CTX_wm_area(C);
1374         int tot= BLI_countlist(&CTX_data_main(C)->screen);
1375         int delta= RNA_int_get(op->ptr, "delta");
1376         
1377         /* this screen is 'fake', solve later XXX */
1378         if(sa && sa->full)
1379                 return OPERATOR_CANCELLED;
1380         
1381         if(delta==1) {
1382                 while(tot--) {
1383                         screen= screen->id.next;
1384                         if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1385                         if(screen->winid==0 && screen->full==0)
1386                                 break;
1387                 }
1388         }
1389         else if(delta== -1) {
1390                 while(tot--) {
1391                         screen= screen->id.prev;
1392                         if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1393                         if(screen->winid==0 && screen->full==0)
1394                                 break;
1395                 }
1396         }
1397         else {
1398                 screen= NULL;
1399         }
1400         
1401         if(screen) {
1402                 ED_screen_set(C, screen);
1403                 return OPERATOR_FINISHED;
1404         }
1405         return OPERATOR_CANCELLED;
1406 }
1407
1408 void SCREEN_OT_screen_set(wmOperatorType *ot)
1409 {
1410         ot->name = "Set Screen";
1411         ot->idname = "SCREEN_OT_screen_set";
1412         
1413         ot->exec= screen_set_exec;
1414         ot->poll= ED_operator_screenactive;
1415         
1416         /* rna */
1417         RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1418         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1419 }
1420
1421 /* ************** screen full-area operator ***************************** */
1422
1423
1424 /* function to be called outside UI context, or for redo */
1425 static int screen_full_area_exec(bContext *C, wmOperator *op)
1426 {
1427         ed_screen_fullarea(C, CTX_wm_area(C));
1428         return OPERATOR_FINISHED;
1429 }
1430
1431 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1432 {
1433         ot->name = "Toggle Make Area Fullscreen";
1434         ot->idname = "SCREEN_OT_screen_full_area";
1435         
1436         ot->exec= screen_full_area_exec;
1437         ot->poll= ED_operator_areaactive;
1438         ot->flag= 0;
1439
1440 }
1441
1442
1443
1444 /* ************** join area operator ********************************************** */
1445
1446 /* operator state vars used:  
1447                         x1, y1     mouse coord in first area, which will disappear
1448                         x2, y2     mouse coord in 2nd area, which will become joined
1449
1450 functions:
1451
1452    init()   find edge based on state vars 
1453                         test if the edge divides two areas, 
1454                         store active and nonactive area,
1455             
1456    apply()  do the actual join
1457
1458    exit()       cleanup, send notifier
1459
1460 callbacks:
1461
1462    exec()       calls init, apply, exit 
1463    
1464    invoke() sets mouse coords in x,y
1465             call init()
1466             add modal handler
1467
1468    modal()      accept modal events while doing it
1469                         call apply() with active window and nonactive window
1470             call exit() and remove handler when LMB confirm
1471
1472 */
1473
1474 typedef struct sAreaJoinData
1475 {
1476         ScrArea *sa1;   /* first area to be considered */
1477         ScrArea *sa2;   /* second area to be considered */
1478         ScrArea *scr;   /* designed for removal */
1479
1480 } sAreaJoinData;
1481
1482
1483 /* validate selection inside screen, set variables OK */
1484 /* return 0: init failed */
1485 /* XXX todo: find edge based on (x,y) and set other area? */
1486 static int area_join_init(bContext *C, wmOperator *op)
1487 {
1488         ScrArea *sa1, *sa2;
1489         sAreaJoinData* jd= NULL;
1490         int x1, y1;
1491         int x2, y2;
1492
1493         /* required properties, make negative to get return 0 if not set by caller */
1494         x1= RNA_int_get(op->ptr, "x1");
1495         y1= RNA_int_get(op->ptr, "y1");
1496         x2= RNA_int_get(op->ptr, "x2");
1497         y2= RNA_int_get(op->ptr, "y2");
1498         
1499         sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1500         sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1501         if(sa1==NULL || sa2==NULL || sa1==sa2)
1502                 return 0;
1503
1504         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1505                 
1506         jd->sa1 = sa1;
1507         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1508         jd->sa2 = sa2;
1509         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1510         
1511         op->customdata= jd;
1512         
1513         return 1;
1514 }
1515
1516 /* apply the join of the areas (space types) */
1517 static int area_join_apply(bContext *C, wmOperator *op)
1518 {
1519         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1520         if (!jd) return 0;
1521
1522         if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1523                 return 0;
1524         }
1525         if (CTX_wm_area(C) == jd->sa2) {
1526                 CTX_wm_area_set(C, NULL);
1527                 CTX_wm_region_set(C, NULL);
1528         }
1529
1530         return 1;
1531 }
1532
1533 /* finish operation */
1534 static void area_join_exit(bContext *C, wmOperator *op)
1535 {
1536         if (op->customdata) {
1537                 MEM_freeN(op->customdata);
1538                 op->customdata = NULL;
1539         }
1540
1541         /* this makes sure aligned edges will result in aligned grabbing */
1542         removedouble_scredges(CTX_wm_screen(C));
1543         removenotused_scredges(CTX_wm_screen(C));
1544         removenotused_scrverts(CTX_wm_screen(C));
1545 }
1546
1547 static int area_join_exec(bContext *C, wmOperator *op)
1548 {
1549         if(!area_join_init(C, op)) 
1550                 return OPERATOR_CANCELLED;
1551         
1552         area_join_apply(C, op);
1553         area_join_exit(C, op);
1554
1555         return OPERATOR_FINISHED;
1556 }
1557
1558 /* interaction callback */
1559 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1560 {
1561
1562         if(event->type==EVT_ACTIONZONE_AREA) {
1563                 sActionzoneData *sad= event->customdata;
1564
1565                 if(sad->modifier>0) {
1566                         return OPERATOR_PASS_THROUGH;
1567                 }
1568                 
1569                 /* verify *sad itself */
1570                 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1571                         return OPERATOR_PASS_THROUGH;
1572                 
1573                 /* is this our *sad? if areas equal it should be passed on */
1574                 if(sad->sa1==sad->sa2)
1575                         return OPERATOR_PASS_THROUGH;
1576                 
1577                 /* prepare operator state vars */
1578                 RNA_int_set(op->ptr, "x1", sad->x);
1579                 RNA_int_set(op->ptr, "y1", sad->y);
1580                 RNA_int_set(op->ptr, "x2", event->x);
1581                 RNA_int_set(op->ptr, "y2", event->y);
1582
1583                 if(!area_join_init(C, op)) 
1584                         return OPERATOR_PASS_THROUGH;
1585         
1586                 /* add temp handler */
1587                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1588         
1589                 return OPERATOR_RUNNING_MODAL;
1590         }
1591         
1592         return OPERATOR_PASS_THROUGH;
1593 }
1594
1595 static int area_join_cancel(bContext *C, wmOperator *op)
1596 {
1597         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1598
1599         if (jd->sa1) {
1600                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1601                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1602         }
1603         if (jd->sa2) {
1604                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1605                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1606         }
1607
1608         WM_event_add_notifier(C, NC_WINDOW, NULL);
1609         
1610         area_join_exit(C, op);
1611
1612         return OPERATOR_CANCELLED;
1613 }
1614
1615 /* modal callback while selecting area (space) that will be removed */
1616 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1617 {
1618         bScreen *sc= CTX_wm_screen(C);
1619         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1620         
1621         /* execute the events */
1622         switch(event->type) {
1623                         
1624                 case MOUSEMOVE: 
1625                         {
1626                                 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1627                                 int dir;
1628                                 
1629                                 if (sa) {                                       
1630                                         if (jd->sa1 != sa) {
1631                                                 dir = area_getorientation(sc, jd->sa1, sa);
1632                                                 if (dir >= 0) {
1633                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1634                                                         jd->sa2 = sa;
1635                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1636                                                 } 
1637                                                 else {
1638                                                         /* we are not bordering on the previously selected area 
1639                                                            we check if area has common border with the one marked for removal
1640                                                            in this case we can swap areas.
1641                                                         */
1642                                                         dir = area_getorientation(sc, sa, jd->sa2);
1643                                                         if (dir >= 0) {
1644                                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1645                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1646                                                                 jd->sa1 = jd->sa2;
1647                                                                 jd->sa2 = sa;
1648                                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1649                                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1650                                                         } 
1651                                                         else {
1652                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1653                                                                 jd->sa2 = NULL;
1654                                                         }
1655                                                 }
1656                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1657                                         } 
1658                                         else {
1659                                                 /* we are back in the area previously selected for keeping 
1660                                                  * we swap the areas if possible to allow user to choose */
1661                                                 if (jd->sa2 != NULL) {
1662                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1663                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1664                                                         jd->sa1 = jd->sa2;
1665                                                         jd->sa2 = sa;
1666                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1667                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1668                                                         dir = area_getorientation(sc, jd->sa1, jd->sa2);
1669                                                         if (dir < 0) {
1670                                                                 printf("oops, didn't expect that!\n");
1671                                                         }
1672                                                 } 
1673                                                 else {
1674                                                         dir = area_getorientation(sc, jd->sa1, sa);
1675                                                         if (dir >= 0) {
1676                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1677                                                                 jd->sa2 = sa;
1678                                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1679                                                         }
1680                                                 }
1681                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1682                                         }
1683                                 }
1684                         }
1685                         break;
1686                 case LEFTMOUSE:
1687                         if(event->val==0) {
1688                                 area_join_apply(C, op);
1689                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1690                                 area_join_exit(C, op);
1691                                 return OPERATOR_FINISHED;
1692                         }
1693                         break;
1694                         
1695                 case ESCKEY:
1696                         return area_join_cancel(C, op);
1697         }
1698
1699         return OPERATOR_RUNNING_MODAL;
1700 }
1701
1702 /* Operator for joining two areas (space types) */
1703 void SCREEN_OT_area_join(wmOperatorType *ot)
1704 {
1705         /* identifiers */
1706         ot->name= "Join area";
1707         ot->idname= "SCREEN_OT_area_join";
1708         
1709         /* api callbacks */
1710         ot->exec= area_join_exec;
1711         ot->invoke= area_join_invoke;
1712         ot->modal= area_join_modal;
1713
1714         ot->poll= ED_operator_areaactive;
1715
1716         /* rna */
1717         RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1718         RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1719         RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1720         RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1721 }
1722
1723 /* ************** repeat last operator ***************************** */
1724
1725 static int repeat_last_exec(bContext *C, wmOperator *op)
1726 {
1727         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1728         
1729         if(lastop)
1730                 WM_operator_repeat(C, lastop);
1731         
1732         return OPERATOR_CANCELLED;
1733 }
1734
1735 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1736 {
1737         /* identifiers */
1738         ot->name= "Repeat Last";
1739         ot->idname= "SCREEN_OT_repeat_last";
1740         
1741         /* api callbacks */
1742         ot->exec= repeat_last_exec;
1743         
1744         ot->poll= ED_operator_screenactive;
1745         
1746 }
1747
1748 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1749 {
1750         wmWindowManager *wm= CTX_wm_manager(C);
1751         wmOperator *lastop;
1752         uiPopupMenu *pup;
1753         uiLayout *layout;
1754         int items, i;
1755         
1756         items= BLI_countlist(&wm->operators);
1757         if(items==0)
1758                 return OPERATOR_CANCELLED;
1759         
1760         pup= uiPupMenuBegin(C, op->type->name, 0);
1761         layout= uiPupMenuLayout(pup);
1762
1763         for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1764                 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
1765
1766         uiPupMenuEnd(C, pup);
1767         
1768         return OPERATOR_CANCELLED;
1769 }
1770
1771 static int repeat_history_exec(bContext *C, wmOperator *op)
1772 {
1773         wmWindowManager *wm= CTX_wm_manager(C);
1774         
1775         op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1776         if(op) {
1777                 /* let's put it as last operator in list */
1778                 BLI_remlink(&wm->operators, op);
1779                 BLI_addtail(&wm->operators, op);
1780                 
1781                 WM_operator_repeat(C, op);
1782         }
1783                                          
1784         return OPERATOR_FINISHED;
1785 }
1786
1787 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1788 {
1789         /* identifiers */
1790         ot->name= "Repeat History";
1791         ot->idname= "SCREEN_OT_repeat_history";
1792         
1793         /* api callbacks */
1794         ot->invoke= repeat_history_invoke;
1795         ot->exec= repeat_history_exec;
1796         
1797         ot->poll= ED_operator_screenactive;
1798         
1799         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1800 }
1801
1802 /* ********************** redo operator ***************************** */
1803
1804 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1805 {
1806         wmWindowManager *wm= CTX_wm_manager(C);
1807         wmOperator *lastop;
1808
1809         /* only for operators that are registered and did an undo push */
1810         for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
1811                 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
1812                         break;
1813         
1814         if(lastop)
1815                 WM_operator_redo_popup(C, lastop);
1816
1817         return OPERATOR_CANCELLED;
1818 }
1819
1820 void SCREEN_OT_redo_last(wmOperatorType *ot)
1821 {
1822         /* identifiers */
1823         ot->name= "Redo Last";
1824         ot->idname= "SCREEN_OT_redo_last";
1825         
1826         /* api callbacks */
1827         ot->invoke= redo_last_invoke;
1828         
1829         ot->poll= ED_operator_screenactive;
1830 }
1831
1832 /* ************** region split operator ***************************** */
1833
1834 /* insert a region in the area region list */
1835 static int region_split_exec(bContext *C, wmOperator *op)
1836 {
1837         ARegion *ar= CTX_wm_region(C);
1838         
1839         if(ar->regiontype==RGN_TYPE_HEADER)
1840                 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1841         else if(ar->alignment==RGN_ALIGN_QSPLIT)
1842                 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1843         else {
1844                 ScrArea *sa= CTX_wm_area(C);
1845                 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1846                 int dir= RNA_enum_get(op->ptr, "type");
1847         
1848                 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1849                 
1850                 newar->alignment= ar->alignment;
1851                 
1852                 if(dir=='h')
1853                         ar->alignment= RGN_ALIGN_HSPLIT;
1854                 else
1855                         ar->alignment= RGN_ALIGN_VSPLIT;
1856                 
1857                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1858         }
1859         
1860         return OPERATOR_FINISHED;
1861 }
1862
1863 void SCREEN_OT_region_split(wmOperatorType *ot)
1864 {
1865         /* identifiers */
1866         ot->name= "Split Region";
1867         ot->idname= "SCREEN_OT_region_split";
1868         
1869         /* api callbacks */
1870         ot->invoke= WM_menu_invoke;
1871         ot->exec= region_split_exec;
1872         ot->poll= ED_operator_areaactive;
1873         
1874         RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
1875 }
1876
1877 /* ************** region four-split operator ***************************** */
1878
1879 /* insert a region in the area region list */
1880 static int region_foursplit_exec(bContext *C, wmOperator *op)
1881 {
1882         ARegion *ar= CTX_wm_region(C);
1883         
1884         /* some rules... */
1885         if(ar->regiontype!=RGN_TYPE_WINDOW)
1886                 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
1887         else if(ar->alignment==RGN_ALIGN_QSPLIT) {
1888                 ScrArea *sa= CTX_wm_area(C);
1889                 ARegion *arn;
1890                 
1891                 /* keep current region */
1892                 ar->alignment= 0;
1893                 
1894                 if(sa->spacetype==SPACE_VIEW3D) {
1895                         RegionView3D *rv3d= ar->regiondata;
1896                         rv3d->viewlock= 0;
1897                         rv3d->rflag &= ~RV3D_CLIPPING;
1898                 }
1899                 
1900                 for(ar= sa->regionbase.first; ar; ar= arn) {
1901                         arn= ar->next;
1902                         if(ar->alignment==RGN_ALIGN_QSPLIT) {
1903                                 ED_region_exit(C, ar);
1904                                 BKE_area_region_free(sa->type, ar);
1905                                 BLI_remlink(&sa->regionbase, ar);
1906                                 MEM_freeN(ar);
1907                         }
1908                 }
1909                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1910         }
1911         else if(ar->next)
1912                 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
1913         else {
1914                 ScrArea *sa= CTX_wm_area(C);
1915                 ARegion *newar;
1916                 int count;
1917                 
1918                 ar->alignment= RGN_ALIGN_QSPLIT;
1919                 
1920                 for(count=0; count<3; count++) {
1921                         newar= BKE_area_region_copy(sa->type, ar);
1922                         BLI_addtail(&sa->regionbase, newar);
1923                 }
1924                 
1925                 /* lock views and set them */
1926                 if(sa->spacetype==SPACE_VIEW3D) {
1927                         RegionView3D *rv3d;
1928                         
1929                         rv3d= ar->regiondata;
1930                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
1931                         
1932                         ar= ar->next;
1933                         rv3d= ar->regiondata;
1934                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
1935                         
1936                         ar= ar->next;
1937                         rv3d= ar->regiondata;
1938                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
1939                         
1940                         ar= ar->next;
1941                         rv3d= ar->regiondata;
1942                         rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
1943                 }
1944                 
1945                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1946         }
1947         
1948         
1949         return OPERATOR_FINISHED;
1950 }
1951
1952 void SCREEN_OT_region_foursplit(wmOperatorType *ot)
1953 {
1954         /* identifiers */
1955         ot->name= "Split Region in 4 Parts";
1956         ot->idname= "SCREEN_OT_region_foursplit";
1957         
1958         /* api callbacks */
1959         ot->invoke= WM_operator_confirm;
1960         ot->exec= region_foursplit_exec;
1961         ot->poll= ED_operator_areaactive;
1962         ot->flag= OPTYPE_REGISTER;
1963 }
1964
1965
1966
1967 /* ************** region flip operator ***************************** */
1968
1969 /* flip a region alignment */
1970 static int region_flip_exec(bContext *C, wmOperator *op)
1971 {
1972         ARegion *ar= CTX_wm_region(C);
1973
1974         if(ar->alignment==RGN_ALIGN_TOP)
1975                 ar->alignment= RGN_ALIGN_BOTTOM;
1976         else if(ar->alignment==RGN_ALIGN_BOTTOM)
1977                 ar->alignment= RGN_ALIGN_TOP;
1978         else if(ar->alignment==RGN_ALIGN_LEFT)
1979                 ar->alignment= RGN_ALIGN_RIGHT;
1980         else if(ar->alignment==RGN_ALIGN_RIGHT)
1981                 ar->alignment= RGN_ALIGN_LEFT;
1982         
1983         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1984         printf("executed region flip\n");
1985         
1986         return OPERATOR_FINISHED;
1987 }
1988
1989
1990 void SCREEN_OT_region_flip(wmOperatorType *ot)
1991 {
1992         /* identifiers */
1993         ot->name= "Flip Region";
1994         ot->idname= "SCREEN_OT_region_flip";
1995         
1996         /* api callbacks */
1997         ot->exec= region_flip_exec;
1998         
1999         ot->poll= ED_operator_areaactive;
2000         ot->flag= OPTYPE_REGISTER;
2001
2002 }
2003
2004 /* ****************** anim player, with timer ***************** */
2005
2006 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2007 {
2008         if(regiontype==RGN_TYPE_WINDOW) {
2009
2010                 switch (spacetype) {
2011                         case SPACE_VIEW3D:
2012                                 if(redraws & TIME_ALL_3D_WIN)
2013                                         return 1;
2014                                 break;
2015                         case SPACE_IPO:
2016                         case SPACE_ACTION:
2017                         case SPACE_NLA:
2018                                 if(redraws & TIME_ALL_ANIM_WIN)
2019                                         return 1;
2020                                 break;
2021                         case SPACE_TIME:
2022                                 /* if only 1 window or 3d windows, we do timeline too */
2023                                 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2024                                         return 1;
2025                                 break;
2026                         case SPACE_BUTS:
2027                                 if(redraws & TIME_ALL_BUTS_WIN)
2028                                         return 1;
2029                                 break;
2030                         case SPACE_SEQ:
2031                                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2032                                         return 1;
2033                                 break;
2034                         case SPACE_IMAGE:
2035                                 if(redraws & TIME_ALL_IMAGE_WIN)
2036                                         return 1;
2037                                 break;
2038                                 
2039                 }
2040         }
2041         else if(regiontype==RGN_TYPE_UI) {
2042                 if(redraws & TIME_ALL_BUTS_WIN)
2043                         return 1;
2044         }
2045         else if(regiontype==RGN_TYPE_HEADER) {
2046                 if(spacetype==SPACE_TIME)
2047                         return 1;
2048         }
2049         return 0;
2050 }
2051
2052 static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
2053 {
2054         bScreen *screen= CTX_wm_screen(C);
2055         
2056         if(screen->animtimer==event->customdata) {
2057                 Scene *scene= CTX_data_scene(C);
2058                 wmTimer *wt= screen->animtimer;
2059                 ScreenAnimData *sad= wt->customdata;
2060                 ScrArea *sa;
2061                 
2062                 if(scene->audio.flag & AUDIO_SYNC) {
2063                         int step = floor(wt->duration * FPS);
2064                         scene->r.cfra += step;
2065                         wt->duration -= ((float)step)/FPS;
2066                 }
2067                 else
2068                         scene->r.cfra++;
2069                 
2070                 if (scene->r.psfra) {
2071                         if(scene->r.cfra > scene->r.pefra)
2072                                 scene->r.cfra= scene->r.psfra;
2073                 }
2074                 else {
2075                         if(scene->r.cfra > scene->r.efra)
2076                                 scene->r.cfra= scene->r.sfra;
2077                 }
2078
2079                 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2080                 ED_update_for_newframe(C, 1);
2081                 
2082                 for(sa= screen->areabase.first; sa; sa= sa->next) {
2083                         ARegion *ar;
2084                         for(ar= sa->regionbase.first; ar; ar= ar->next) {
2085                                 if(ar==sad->ar)
2086                                         ED_region_tag_redraw(ar);
2087                                 else
2088                                         if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2089                                                 ED_region_tag_redraw(ar);
2090                         }
2091                 }
2092                 
2093                 //WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2094                 
2095                 return OPERATOR_FINISHED;
2096         }
2097         return OPERATOR_PASS_THROUGH;
2098 }
2099
2100 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2101 {
2102         /* identifiers */
2103         ot->name= "Animation Step";
2104         ot->idname= "SCREEN_OT_animation_step";
2105         
2106         /* api callbacks */
2107         ot->invoke= screen_animation_step;
2108         
2109         ot->poll= ED_operator_screenactive;
2110         
2111 }
2112
2113 /* ****************** anim player, starts or ends timer ***************** */
2114
2115 /* toggle operator */
2116 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
2117 {
2118         bScreen *screen= CTX_wm_screen(C);
2119         
2120         if(screen->animtimer) {
2121                 ED_screen_animation_timer(C, 0, 0);
2122         }
2123         else {
2124                 /* todo: RNA properties to define play types */
2125                 ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, 1);
2126                 
2127                 if(screen->animtimer) {
2128                         wmTimer *wt= screen->animtimer;
2129                         ScreenAnimData *sad= wt->customdata;
2130                         
2131                         sad->ar= CTX_wm_region(C);
2132                 }
2133         }
2134         
2135         return OPERATOR_FINISHED;
2136 }
2137
2138 void SCREEN_OT_animation_play(wmOperatorType *ot)
2139 {
2140         /* identifiers */
2141         ot->name= "Animation player";
2142         ot->idname= "SCREEN_OT_animation_play";
2143         
2144         /* api callbacks */
2145         ot->invoke= screen_animation_play;
2146         
2147         ot->poll= ED_operator_screenactive;
2148         
2149         
2150 }
2151
2152 /* ************** border select operator (template) ***************************** */
2153
2154 /* operator state vars used: (added by default WM callbacks)   
2155         xmin, ymin     
2156         xmax, ymax     
2157
2158         customdata: the wmGesture pointer
2159
2160 callbacks:
2161
2162         exec()  has to be filled in by user
2163
2164         invoke() default WM function
2165                          adds modal handler
2166
2167         modal() default WM function 
2168                         accept modal events while doing it, calls exec(), handles ESC and border drawing
2169         
2170         poll()  has to be filled in by user for context
2171 */
2172 #if 0
2173 static int border_select_do(bContext *C, wmOperator *op)
2174 {
2175         int event_type= RNA_int_get(op->ptr, "event_type");
2176         
2177         if(event_type==LEFTMOUSE)
2178                 printf("border select do select\n");
2179         else if(event_type==RIGHTMOUSE)
2180                 printf("border select deselect\n");
2181         else 
2182                 printf("border select do something\n");
2183         
2184         return 1;
2185 }
2186
2187 void SCREEN_OT_border_select(wmOperatorType *ot)
2188 {
2189         /* identifiers */
2190         ot->name= "Border select";
2191         ot->idname= "SCREEN_OT_border_select";
2192         
2193         /* api callbacks */
2194         ot->exec= border_select_do;
2195         ot->invoke= WM_border_select_invoke;
2196         ot->modal= WM_border_select_modal;
2197         
2198         ot->poll= ED_operator_areaactive;
2199         
2200         /* rna */
2201         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2202         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2203         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2204         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2205         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2206
2207 }
2208 #endif
2209
2210 /* ****************************** render invoking ***************** */
2211
2212 /* set callbacks, exported to sequence render too. 
2213 Only call in foreground (UI) renders. */
2214
2215 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
2216 /* window as the last possible alternative.                                                                        */
2217 static ScrArea *biggest_non_image_area(bContext *C)
2218 {
2219         bScreen *sc= CTX_wm_screen(C);
2220         ScrArea *sa, *big= NULL;
2221         int size, maxsize= 0, bwmaxsize= 0;
2222         short foundwin= 0;
2223         
2224         for(sa= sc->areabase.first; sa; sa= sa->next) {
2225                 if(sa->winx > 30 && sa->winy > 30) {
2226                         size= sa->winx*sa->winy;
2227                         if(sa->spacetype == SPACE_BUTS) {
2228                                 if(foundwin == 0 && size > bwmaxsize) {
2229                                         bwmaxsize= size;
2230                                         big= sa;        
2231                                 }
2232                         }
2233                         else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
2234                                 maxsize= size;
2235                                 big= sa;
2236                                 foundwin= 1;
2237                         }
2238                 }
2239         }
2240         
2241         return big;
2242 }
2243
2244 static ScrArea *biggest_area(bContext *C)
2245 {
2246         bScreen *sc= CTX_wm_screen(C);
2247         ScrArea *sa, *big= NULL;
2248         int size, maxsize= 0;
2249         
2250         for(sa= sc->areabase.first; sa; sa= sa->next) {
2251                 size= sa->winx*sa->winy;
2252                 if(size > maxsize) {
2253                         maxsize= size;
2254                         big= sa;
2255                 }
2256         }
2257         return big;
2258 }
2259
2260
2261 static ScrArea *find_area_showing_r_result(bContext *C)
2262 {
2263         bScreen *sc= CTX_wm_screen(C);
2264         ScrArea *sa;
2265         SpaceImage *sima;
2266         
2267         /* find an imagewindow showing render result */
2268         for(sa=sc->areabase.first; sa; sa= sa->next) {
2269                 if(sa->spacetype==SPACE_IMAGE) {
2270                         sima= sa->spacedata.first;
2271                         if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
2272                                 break;
2273                 }
2274         }
2275         return sa;
2276 }
2277
2278 static void screen_set_image_output(bContext *C)
2279 {
2280         ScrArea *sa;
2281         SpaceImage *sima;
2282         
2283         sa= find_area_showing_r_result(C);
2284         
2285         if(sa==NULL) {
2286                 /* find largest open non-image area */
2287                 sa= biggest_non_image_area(C);
2288                 if(sa) {
2289                         ED_area_newspace(C, sa, SPACE_IMAGE);
2290                         sima= sa->spacedata.first;
2291                         
2292                         /* makes ESC go back to prev space */
2293                         sima->flag |= SI_PREVSPACE;
2294                 }
2295                 else {
2296                         /* use any area of decent size */
2297                         sa= biggest_area(C);
2298                         if(sa->spacetype!=SPACE_IMAGE) {
2299                                 // XXX newspace(sa, SPACE_IMAGE);
2300                                 sima= sa->spacedata.first;
2301                                 
2302                                 /* makes ESC go back to prev space */
2303                                 sima->flag |= SI_PREVSPACE;
2304                         }
2305                 }
2306         }
2307         
2308         sima= sa->spacedata.first;
2309         
2310         /* get the correct image, and scale it */
2311         sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2312         
2313         if(G.displaymode==2) { // XXX
2314                 if(sa->full==0) {
2315                         sima->flag |= SI_FULLWINDOW;
2316                         
2317                         ed_screen_fullarea(C, sa);
2318                 }
2319         }
2320         
2321 }
2322
2323 /* executes blocking render */
2324 static int screen_render_exec(bContext *C, wmOperator *op)
2325 {
2326         Scene *scene= CTX_data_scene(C);
2327         Render *re= RE_GetRender(scene->id.name);
2328         
2329         if(re==NULL) {
2330                 re= RE_NewRender(scene->id.name);
2331         }
2332         RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
2333         
2334         if(RNA_boolean_get(op->ptr, "anim"))
2335                 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
2336         else
2337                 RE_BlenderFrame(re, scene, scene->r.cfra);
2338         
2339         // no redraw needed, we leave state as we entered it
2340         ED_update_for_newframe(C, 1);
2341         
2342         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2343
2344         return OPERATOR_FINISHED;
2345 }
2346
2347 typedef struct RenderJob {
2348         Scene *scene;
2349         Render *re;
2350         wmWindow *win;
2351         int anim;
2352         Image *image;
2353         ImageUser iuser;
2354         short *stop;
2355         short *do_update;
2356 } RenderJob;
2357
2358 static void render_freejob(void *rjv)
2359 {
2360         RenderJob *rj= rjv;
2361         
2362         MEM_freeN(rj);
2363 }
2364
2365 /* called inside thread! */
2366 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2367 {
2368         RenderJob *rj= rjv;
2369         ImBuf *ibuf;
2370         float x1, y1, *rectf= NULL;
2371         int ymin, ymax, xmin, xmax;
2372         int rymin, rxmin;
2373         char *rectc;
2374         
2375         ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2376         if(ibuf==NULL) return;
2377
2378         /* if renrect argument, we only refresh scanlines */
2379         if(renrect) {
2380                 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2381                 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2382                         return;
2383                 
2384                 /* xmin here is first subrect x coord, xmax defines subrect width */
2385                 xmin = renrect->xmin + rr->crop;
2386                 xmax = renrect->xmax - xmin - rr->crop;
2387                 if (xmax<2) return;
2388                 
2389                 ymin= renrect->ymin + rr->crop;
2390                 ymax= renrect->ymax - ymin - rr->crop;
2391                 if(ymax<2)
2392                         return;
2393                 renrect->ymin= renrect->ymax;
2394                 
2395         }
2396         else {
2397                 xmin = ymin = rr->crop;
2398                 xmax = rr->rectx - 2*rr->crop;
2399                 ymax = rr->recty - 2*rr->crop;
2400         }
2401         
2402         /* xmin ymin is in tile coords. transform to ibuf */
2403         rxmin= rr->tilerect.xmin + xmin;
2404         if(rxmin >= ibuf->x) return;
2405         rymin= rr->tilerect.ymin + ymin;
2406         if(rymin >= ibuf->y) return;
2407         
2408         if(rxmin + xmax > ibuf->x)
2409                 xmax= ibuf->x - rxmin;
2410         if(rymin + ymax > ibuf->y)
2411                 ymax= ibuf->y - rymin;
2412         
2413         if(xmax < 1 || ymax < 1) return;
2414         
2415         /* find current float rect for display, first case is after composit... still weak */
2416         if(rr->rectf)
2417                 rectf= rr->rectf;
2418         else {
2419                 if(rr->rect32)
2420                         return;
2421                 else {
2422                         if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2423                         rectf= rr->renlay->rectf;
2424                 }
2425         }
2426         if(rectf==NULL) return;
2427         
2428         rectf+= 4*(rr->rectx*ymin + xmin);
2429         rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2430
2431         for(y1= 0; y1<ymax; y1++) {
2432                 float *rf= rectf;
2433                 char *rc= rectc;
2434                 
2435                 /* XXX temp. because crop offset */
2436                 if( rectc >= (char *)(ibuf->rect)) {
2437                         for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2438                                 rc[0]= FTOCHAR(rf[0]);
2439                                 rc[1]= FTOCHAR(rf[1]);
2440                                 rc[2]= FTOCHAR(rf[2]);
2441                                 rc[3]= FTOCHAR(rf[3]);
2442                         }
2443                 }
2444                 rectf += 4*rr->rectx;
2445                 rectc += 4*ibuf->x;
2446         }
2447         
2448         /* make jobs timer to send notifier */
2449         *(rj->do_update)= 1;
2450 }
2451
2452 static void render_startjob(void *rjv, short *stop, short *do_update)
2453 {
2454         RenderJob *rj= rjv;
2455         
2456         rj->stop= stop;
2457         rj->do_update= do_update;
2458         
2459         if(rj->anim)
2460                 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2461         else
2462                 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2463 }
2464
2465 /* called by render, check job 'stop' value or the global */
2466 static int render_breakjob(void *rjv)
2467 {
2468         RenderJob *rj= rjv;
2469         
2470         if(G.afbreek)
2471                 return 1;
2472         if(rj->stop && *(rj->stop))
2473                 return 1;
2474         return 0;
2475 }
2476
2477 /* catch esc */
2478 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2479 {
2480         /* no running blender, remove handler and pass through */
2481         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2482            return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2483         
2484         /* running render */
2485         switch (event->type) {
2486                 case ESCKEY:
2487                         return OPERATOR_RUNNING_MODAL;
2488                         break;
2489         }
2490         return OPERATOR_PASS_THROUGH;
2491 }
2492
2493 /* using context, starts job */
2494 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2495 {
2496         /* new render clears all callbacks */
2497         Scene *scene= CTX_data_scene(C);
2498         Render *re;
2499         wmJob *steve;
2500         RenderJob *rj;
2501         Image *ima;
2502         
2503         /* only one job at a time */
2504         if(WM_jobs_test(CTX_wm_manager(C), scene))
2505                 return OPERATOR_CANCELLED;
2506         
2507         /* handle UI stuff */
2508         WM_cursor_wait(1);
2509
2510         /* flush multires changes (for sculpt) */
2511         multires_force_update(CTX_data_active_object(C));
2512         
2513         // get editmode results
2514         // store spare
2515         // get view3d layer, local layer, make this nice api call to render
2516         // store spare
2517         
2518         /* ensure at least 1 area shows result */
2519         screen_set_image_output(C);
2520
2521         /* job custom data */
2522         rj= MEM_callocN(sizeof(RenderJob), "render job");
2523         rj->scene= scene;
2524         rj->win= CTX_wm_window(C);
2525         rj->anim= RNA_boolean_get(op->ptr, "anim");
2526         rj->iuser.scene= scene;
2527         rj->iuser.ok= 1;
2528         
2529         /* setup job */
2530         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2531         WM_jobs_customdata(steve, rj, render_freejob);
2532         WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2533         WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2534         
2535         /* get a render result image, and make sure it is empty */
2536         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2537         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2538         rj->image= ima;
2539         
2540         /* setup new render */
2541         re= RE_NewRender(scene->id.name);
2542         RE_test_break_cb(re, rj, render_breakjob);
2543         RE_display_draw_cb(re, rj, image_rect_update);
2544         rj->re= re;
2545         G.afbreek= 0;
2546         
2547         //      BKE_report in render!
2548         //      RE_error_cb(re, error_cb);
2549
2550         WM_jobs_start(CTX_wm_manager(C), steve);
2551         
2552         G.afbreek= 0;
2553         
2554         WM_cursor_wait(0);
2555         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2556
2557         /* add modal handler for ESC */
2558         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
2559         
2560         return OPERATOR_RUNNING_MODAL;
2561 }
2562
2563
2564 /* contextual render, using current scene, view3d? */
2565 void SCREEN_OT_render(wmOperatorType *ot)
2566 {
2567         /* identifiers */
2568         ot->name= "Render";
2569         ot->idname= "SCREEN_OT_render";
2570         
2571         /* api callbacks */
2572         ot->invoke= screen_render_invoke;
2573         ot->modal= screen_render_modal;
2574         ot->exec= screen_render_exec;
2575         
2576         ot->poll= ED_operator_screenactive;
2577         
2578         RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2579         RNA_def_boolean(ot->srna, "anim", 0, "Animation", "");
2580 }
2581
2582 /* *********************** cancel render viewer *************** */
2583
2584 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2585 {
2586         ScrArea *sa= CTX_wm_area(C);
2587         SpaceImage *sima= sa->spacedata.first;
2588         
2589         if(sima->flag & SI_PREVSPACE) {
2590                 sima->flag &= ~SI_PREVSPACE;
2591                 
2592                 if(sima->flag & SI_FULLWINDOW) {
2593                         sima->flag &= ~SI_FULLWINDOW;
2594                         ED_screen_full_prevspace(C);
2595                 }
2596                 else
2597                         ED_area_prevspace(C);
2598         }
2599         else if(sima->flag & SI_FULLWINDOW) {
2600                 sima->flag &= ~SI_FULLWINDOW;
2601                 ed_screen_fullarea(C, sa);
2602         }               
2603         
2604         return OPERATOR_FINISHED;
2605 }
2606
2607 void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2608 {
2609         /* identifiers */
2610         ot->name= "Cancel Render View";
2611         ot->idname= "SCREEN_OT_render_view_cancel";
2612         
2613         /* api callbacks */
2614         ot->exec= render_view_cancel_exec;
2615         ot->poll= ED_operator_image_active;
2616 }
2617
2618
2619 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
2620
2621 /* called in spacetypes.c */
2622 void ED_operatortypes_screen(void)
2623 {
2624         /* generic UI stuff */
2625         WM_operatortype_append(SCREEN_OT_actionzone);
2626         WM_operatortype_append(SCREEN_OT_repeat_last);
2627         WM_operatortype_append(SCREEN_OT_repeat_history);
2628         WM_operatortype_append(SCREEN_OT_redo_last);
2629         
2630         /* screen tools */
2631         WM_operatortype_append(SCREEN_OT_area_move);
2632         WM_operatortype_append(SCREEN_OT_area_split);
2633         WM_operatortype_append(SCREEN_OT_area_join);
2634         WM_operatortype_append(SCREEN_OT_area_dupli);
2635         WM_operatortype_append(SCREEN_OT_area_swap);
2636         WM_operatortype_append(SCREEN_OT_region_split);
2637         WM_operatortype_append(SCREEN_OT_region_foursplit);
2638         WM_operatortype_append(SCREEN_OT_region_flip);
2639         WM_operatortype_append(SCREEN_OT_region_scale);
2640         WM_operatortype_append(SCREEN_OT_screen_set);
2641         WM_operatortype_append(SCREEN_OT_screen_full_area);
2642         WM_operatortype_append(SCREEN_OT_screenshot);
2643         WM_operatortype_append(SCREEN_OT_screencast);
2644         
2645         /*frame changes*/
2646         WM_operatortype_append(SCREEN_OT_frame_offset);
2647         WM_operatortype_append(SCREEN_OT_animation_step);
2648         WM_operatortype_append(SCREEN_OT_animation_play);
2649         
2650         /* render */
2651         WM_operatortype_append(SCREEN_OT_render);
2652         WM_operatortype_append(SCREEN_OT_render_view_cancel);
2653         
2654         /* tools shared by more space types */
2655         WM_operatortype_append(ED_OT_undo);
2656         WM_operatortype_append(ED_OT_redo);     
2657         
2658 }
2659
2660 /* called in spacetypes.c */
2661 void ED_keymap_screen(wmWindowManager *wm)
2662 {
2663         ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
2664         
2665         /* standard timers */
2666         WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
2667         
2668         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
2669         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
2670         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2);
2671         
2672         /* screen tools */
2673         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
2674         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
2675         WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
2676         WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_ALT, 0);
2677         WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
2678                         /* area move after action zones */
2679         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2680         
2681         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2682         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2683         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2684         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2685         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
2686         WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
2687         WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
2688
2689          /* tests */
2690         WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2691         WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
2692         
2693         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
2694         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
2695         WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
2696         WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
2697         
2698         RNA_string_set(WM_keymap_add_item(keymap, "SCRIPT_OT_python_file_run", F7KEY, KM_PRESS, 0, 0)->ptr, "filename", "test.py");
2699         WM_keymap_verify_item(keymap, "SCRIPT_OT_python_run_ui_scripts", F8KEY, KM_PRESS, 0, 0);
2700
2701         /* files */
2702         WM_keymap_add_item(keymap, "FILE_OT_exec", RETKEY, KM_PRESS, 0, 0);
2703         WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
2704         
2705         /* undo */
2706         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
2707         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
2708         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2709         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2710                                                   
2711         /* render */
2712         WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
2713         WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
2714         
2715         /* frame offsets & play */
2716         keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
2717         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
2718         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
2719         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
2720         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
2721         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
2722         
2723 }
2724