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