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