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