2.5: Fix timeline space redraw properties, these were not RNA wrapped
[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_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1586         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1587 }
1588
1589 /* ************** screen full-area operator ***************************** */
1590
1591
1592 /* function to be called outside UI context, or for redo */
1593 static int screen_full_area_exec(bContext *C, wmOperator *op)
1594 {
1595         ed_screen_fullarea(C, CTX_wm_area(C));
1596         return OPERATOR_FINISHED;
1597 }
1598
1599 static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1600 {
1601         ot->name = "Toggle Make Area Fullscreen";
1602         ot->idname = "SCREEN_OT_screen_full_area";
1603         
1604         ot->exec= screen_full_area_exec;
1605         ot->poll= ED_operator_areaactive;
1606         ot->flag= 0;
1607
1608 }
1609
1610
1611
1612 /* ************** join area operator ********************************************** */
1613
1614 /* operator state vars used:  
1615                         x1, y1     mouse coord in first area, which will disappear
1616                         x2, y2     mouse coord in 2nd area, which will become joined
1617
1618 functions:
1619
1620    init()   find edge based on state vars 
1621                         test if the edge divides two areas, 
1622                         store active and nonactive area,
1623             
1624    apply()  do the actual join
1625
1626    exit()       cleanup, send notifier
1627
1628 callbacks:
1629
1630    exec()       calls init, apply, exit 
1631    
1632    invoke() sets mouse coords in x,y
1633             call init()
1634             add modal handler
1635
1636    modal()      accept modal events while doing it
1637                         call apply() with active window and nonactive window
1638             call exit() and remove handler when LMB confirm
1639
1640 */
1641
1642 typedef struct sAreaJoinData
1643 {
1644         ScrArea *sa1;   /* first area to be considered */
1645         ScrArea *sa2;   /* second area to be considered */
1646         ScrArea *scr;   /* designed for removal */
1647
1648 } sAreaJoinData;
1649
1650
1651 /* validate selection inside screen, set variables OK */
1652 /* return 0: init failed */
1653 /* XXX todo: find edge based on (x,y) and set other area? */
1654 static int area_join_init(bContext *C, wmOperator *op)
1655 {
1656         ScrArea *sa1, *sa2;
1657         sAreaJoinData* jd= NULL;
1658         int x1, y1;
1659         int x2, y2;
1660
1661         /* required properties, make negative to get return 0 if not set by caller */
1662         x1= RNA_int_get(op->ptr, "x1");
1663         y1= RNA_int_get(op->ptr, "y1");
1664         x2= RNA_int_get(op->ptr, "x2");
1665         y2= RNA_int_get(op->ptr, "y2");
1666         
1667         sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1668         sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1669         if(sa1==NULL || sa2==NULL || sa1==sa2)
1670                 return 0;
1671
1672         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1673                 
1674         jd->sa1 = sa1;
1675         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1676         jd->sa2 = sa2;
1677         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1678         
1679         op->customdata= jd;
1680         
1681         return 1;
1682 }
1683
1684 /* apply the join of the areas (space types) */
1685 static int area_join_apply(bContext *C, wmOperator *op)
1686 {
1687         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1688         if (!jd) return 0;
1689
1690         if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1691                 return 0;
1692         }
1693         if (CTX_wm_area(C) == jd->sa2) {
1694                 CTX_wm_area_set(C, NULL);
1695                 CTX_wm_region_set(C, NULL);
1696         }
1697
1698         return 1;
1699 }
1700
1701 /* finish operation */
1702 static void area_join_exit(bContext *C, wmOperator *op)
1703 {
1704         if (op->customdata) {
1705                 MEM_freeN(op->customdata);
1706                 op->customdata = NULL;
1707         }
1708
1709         /* this makes sure aligned edges will result in aligned grabbing */
1710         removedouble_scredges(CTX_wm_screen(C));
1711         removenotused_scredges(CTX_wm_screen(C));
1712         removenotused_scrverts(CTX_wm_screen(C));
1713 }
1714
1715 static int area_join_exec(bContext *C, wmOperator *op)
1716 {
1717         if(!area_join_init(C, op)) 
1718                 return OPERATOR_CANCELLED;
1719         
1720         area_join_apply(C, op);
1721         area_join_exit(C, op);
1722
1723         return OPERATOR_FINISHED;
1724 }
1725
1726 /* interaction callback */
1727 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1728 {
1729
1730         if(event->type==EVT_ACTIONZONE_AREA) {
1731                 sActionzoneData *sad= event->customdata;
1732
1733                 if(sad->modifier>0) {
1734                         return OPERATOR_PASS_THROUGH;
1735                 }
1736                 
1737                 /* verify *sad itself */
1738                 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1739                         return OPERATOR_PASS_THROUGH;
1740                 
1741                 /* is this our *sad? if areas equal it should be passed on */
1742                 if(sad->sa1==sad->sa2)
1743                         return OPERATOR_PASS_THROUGH;
1744                 
1745                 /* prepare operator state vars */
1746                 RNA_int_set(op->ptr, "x1", sad->x);
1747                 RNA_int_set(op->ptr, "y1", sad->y);
1748                 RNA_int_set(op->ptr, "x2", event->x);
1749                 RNA_int_set(op->ptr, "y2", event->y);
1750
1751                 if(!area_join_init(C, op)) 
1752                         return OPERATOR_PASS_THROUGH;
1753         
1754                 /* add temp handler */
1755                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1756         
1757                 return OPERATOR_RUNNING_MODAL;
1758         }
1759         
1760         return OPERATOR_PASS_THROUGH;
1761 }
1762
1763 static int area_join_cancel(bContext *C, wmOperator *op)
1764 {
1765         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1766
1767         if (jd->sa1) {
1768                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1769                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1770         }
1771         if (jd->sa2) {
1772                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1773                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1774         }
1775
1776         WM_event_add_notifier(C, NC_WINDOW, NULL);
1777         
1778         area_join_exit(C, op);
1779
1780         return OPERATOR_CANCELLED;
1781 }
1782
1783 /* modal callback while selecting area (space) that will be removed */
1784 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1785 {
1786         bScreen *sc= CTX_wm_screen(C);
1787         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1788         
1789         /* execute the events */
1790         switch(event->type) {
1791                         
1792                 case MOUSEMOVE: 
1793                         {
1794                                 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1795                                 int dir;
1796                                 
1797                                 if (sa) {                                       
1798                                         if (jd->sa1 != sa) {
1799                                                 dir = area_getorientation(sc, jd->sa1, sa);
1800                                                 if (dir >= 0) {
1801                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1802                                                         jd->sa2 = sa;
1803                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1804                                                 } 
1805                                                 else {
1806                                                         /* we are not bordering on the previously selected area 
1807                                                            we check if area has common border with the one marked for removal
1808                                                            in this case we can swap areas.
1809                                                         */
1810                                                         dir = area_getorientation(sc, sa, jd->sa2);
1811                                                         if (dir >= 0) {
1812                                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1813                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1814                                                                 jd->sa1 = jd->sa2;
1815                                                                 jd->sa2 = sa;
1816                                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1817                                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1818                                                         } 
1819                                                         else {
1820                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1821                                                                 jd->sa2 = NULL;
1822                                                         }
1823                                                 }
1824                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1825                                         } 
1826                                         else {
1827                                                 /* we are back in the area previously selected for keeping 
1828                                                  * we swap the areas if possible to allow user to choose */
1829                                                 if (jd->sa2 != NULL) {
1830                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1831                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1832                                                         jd->sa1 = jd->sa2;
1833                                                         jd->sa2 = sa;
1834                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1835                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1836                                                         dir = area_getorientation(sc, jd->sa1, jd->sa2);
1837                                                         if (dir < 0) {
1838                                                                 printf("oops, didn't expect that!\n");
1839                                                         }
1840                                                 } 
1841                                                 else {
1842                                                         dir = area_getorientation(sc, jd->sa1, sa);
1843                                                         if (dir >= 0) {
1844                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1845                                                                 jd->sa2 = sa;
1846                                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1847                                                         }
1848                                                 }
1849                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1850                                         }
1851                                 }
1852                         }
1853                         break;
1854                 case LEFTMOUSE:
1855                         if(event->val==0) {
1856                                 area_join_apply(C, op);
1857                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1858                                 area_join_exit(C, op);
1859                                 return OPERATOR_FINISHED;
1860                         }
1861                         break;
1862                         
1863                 case ESCKEY:
1864                         return area_join_cancel(C, op);
1865         }
1866
1867         return OPERATOR_RUNNING_MODAL;
1868 }
1869
1870 /* Operator for joining two areas (space types) */
1871 static void SCREEN_OT_area_join(wmOperatorType *ot)
1872 {
1873         /* identifiers */
1874         ot->name= "Join area";
1875         ot->idname= "SCREEN_OT_area_join";
1876         
1877         /* api callbacks */
1878         ot->exec= area_join_exec;
1879         ot->invoke= area_join_invoke;
1880         ot->modal= area_join_modal;
1881         ot->poll= ED_operator_areaactive;
1882
1883         ot->flag= OPTYPE_BLOCKING;
1884
1885         /* rna */
1886         RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1887         RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1888         RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1889         RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1890 }
1891
1892 /* ************** repeat last operator ***************************** */
1893
1894 static int repeat_last_exec(bContext *C, wmOperator *op)
1895 {
1896         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1897         
1898         if(lastop)
1899                 WM_operator_repeat(C, lastop);
1900         
1901         return OPERATOR_CANCELLED;
1902 }
1903
1904 static void SCREEN_OT_repeat_last(wmOperatorType *ot)
1905 {
1906         /* identifiers */
1907         ot->name= "Repeat Last";
1908         ot->idname= "SCREEN_OT_repeat_last";
1909         
1910         /* api callbacks */
1911         ot->exec= repeat_last_exec;
1912         
1913         ot->poll= ED_operator_screenactive;
1914         
1915 }
1916
1917 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1918 {
1919         wmWindowManager *wm= CTX_wm_manager(C);
1920         wmOperator *lastop;
1921         uiPopupMenu *pup;
1922         uiLayout *layout;
1923         int items, i;
1924         
1925         items= BLI_countlist(&wm->operators);
1926         if(items==0)
1927                 return OPERATOR_CANCELLED;
1928         
1929         pup= uiPupMenuBegin(C, op->type->name, 0);
1930         layout= uiPupMenuLayout(pup);
1931
1932         for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1933                 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
1934
1935         uiPupMenuEnd(C, pup);
1936         
1937         return OPERATOR_CANCELLED;
1938 }
1939
1940 static int repeat_history_exec(bContext *C, wmOperator *op)
1941 {
1942         wmWindowManager *wm= CTX_wm_manager(C);
1943         
1944         op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1945         if(op) {
1946                 /* let's put it as last operator in list */
1947                 BLI_remlink(&wm->operators, op);
1948                 BLI_addtail(&wm->operators, op);
1949                 
1950                 WM_operator_repeat(C, op);
1951         }
1952                                          
1953         return OPERATOR_FINISHED;
1954 }
1955
1956 static void SCREEN_OT_repeat_history(wmOperatorType *ot)
1957 {
1958         /* identifiers */
1959         ot->name= "Repeat History";
1960         ot->idname= "SCREEN_OT_repeat_history";
1961         
1962         /* api callbacks */
1963         ot->invoke= repeat_history_invoke;
1964         ot->exec= repeat_history_exec;
1965         
1966         ot->poll= ED_operator_screenactive;
1967         
1968         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1969 }
1970
1971 /* ********************** redo operator ***************************** */
1972
1973 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1974 {
1975         wmWindowManager *wm= CTX_wm_manager(C);
1976         wmOperator *lastop;
1977
1978         /* only for operators that are registered and did an undo push */
1979         for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
1980                 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
1981                         break;
1982         
1983         if(lastop)
1984                 WM_operator_redo_popup(C, lastop);
1985
1986         return OPERATOR_CANCELLED;
1987 }
1988
1989 static void SCREEN_OT_redo_last(wmOperatorType *ot)
1990 {
1991         /* identifiers */
1992         ot->name= "Redo Last";
1993         ot->idname= "SCREEN_OT_redo_last";
1994         
1995         /* api callbacks */
1996         ot->invoke= redo_last_invoke;
1997         
1998         ot->poll= ED_operator_screenactive;
1999 }
2000
2001 /* ************** region split operator ***************************** */
2002
2003 /* insert a region in the area region list */
2004 static int region_split_exec(bContext *C, wmOperator *op)
2005 {
2006         ARegion *ar= CTX_wm_region(C);
2007         
2008         if(ar->regiontype==RGN_TYPE_HEADER)
2009                 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
2010         else if(ar->alignment==RGN_ALIGN_QSPLIT)
2011                 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
2012         else {
2013                 ScrArea *sa= CTX_wm_area(C);
2014                 ARegion *newar= BKE_area_region_copy(sa->type, ar);
2015                 int dir= RNA_enum_get(op->ptr, "type");
2016         
2017                 BLI_insertlinkafter(&sa->regionbase, ar, newar);
2018                 
2019                 newar->alignment= ar->alignment;
2020                 
2021                 if(dir=='h')
2022                         ar->alignment= RGN_ALIGN_HSPLIT;
2023                 else
2024                         ar->alignment= RGN_ALIGN_VSPLIT;
2025                 
2026                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2027         }
2028         
2029         return OPERATOR_FINISHED;
2030 }
2031
2032 static void SCREEN_OT_region_split(wmOperatorType *ot)
2033 {
2034         /* identifiers */
2035         ot->name= "Split Region";
2036         ot->idname= "SCREEN_OT_region_split";
2037         
2038         /* api callbacks */
2039         ot->invoke= WM_menu_invoke;
2040         ot->exec= region_split_exec;
2041         ot->poll= ED_operator_areaactive;
2042         
2043         RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
2044 }
2045
2046 /* ************** region four-split operator ***************************** */
2047
2048 /* insert a region in the area region list */
2049 static int region_foursplit_exec(bContext *C, wmOperator *op)
2050 {
2051         ARegion *ar= CTX_wm_region(C);
2052         
2053         /* some rules... */
2054         if(ar->regiontype!=RGN_TYPE_WINDOW)
2055                 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
2056         else if(ar->alignment==RGN_ALIGN_QSPLIT) {
2057                 ScrArea *sa= CTX_wm_area(C);
2058                 ARegion *arn;
2059                 
2060                 /* keep current region */
2061                 ar->alignment= 0;
2062                 
2063                 if(sa->spacetype==SPACE_VIEW3D) {
2064                         RegionView3D *rv3d= ar->regiondata;
2065                         rv3d->viewlock= 0;
2066                         rv3d->rflag &= ~RV3D_CLIPPING;
2067                 }
2068                 
2069                 for(ar= sa->regionbase.first; ar; ar= arn) {
2070                         arn= ar->next;
2071                         if(ar->alignment==RGN_ALIGN_QSPLIT) {
2072                                 ED_region_exit(C, ar);
2073                                 BKE_area_region_free(sa->type, ar);
2074                                 BLI_remlink(&sa->regionbase, ar);
2075                                 MEM_freeN(ar);
2076                         }
2077                 }
2078                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2079         }
2080         else if(ar->next)
2081                 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
2082         else {
2083                 ScrArea *sa= CTX_wm_area(C);
2084                 ARegion *newar;
2085                 int count;
2086                 
2087                 ar->alignment= RGN_ALIGN_QSPLIT;
2088                 
2089                 for(count=0; count<3; count++) {
2090                         newar= BKE_area_region_copy(sa->type, ar);
2091                         BLI_addtail(&sa->regionbase, newar);
2092                 }
2093                 
2094                 /* lock views and set them */
2095                 if(sa->spacetype==SPACE_VIEW3D) {
2096                         RegionView3D *rv3d;
2097                         
2098                         rv3d= ar->regiondata;
2099                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
2100                         
2101                         ar= ar->next;
2102                         rv3d= ar->regiondata;
2103                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
2104                         
2105                         ar= ar->next;
2106                         rv3d= ar->regiondata;
2107                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
2108                         
2109                         ar= ar->next;
2110                         rv3d= ar->regiondata;
2111                         rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
2112                 }
2113                 
2114                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2115         }
2116         
2117         
2118         return OPERATOR_FINISHED;
2119 }
2120
2121 static void SCREEN_OT_region_foursplit(wmOperatorType *ot)
2122 {
2123         /* identifiers */
2124         ot->name= "Split Region in 4 Parts";
2125         ot->idname= "SCREEN_OT_region_foursplit";
2126         
2127         /* api callbacks */
2128 //      ot->invoke= WM_operator_confirm;
2129         ot->exec= region_foursplit_exec;
2130         ot->poll= ED_operator_areaactive;
2131         ot->flag= OPTYPE_REGISTER;
2132 }
2133
2134
2135
2136 /* ************** region flip operator ***************************** */
2137
2138 /* flip a region alignment */
2139 static int region_flip_exec(bContext *C, wmOperator *op)
2140 {
2141         ARegion *ar= CTX_wm_region(C);
2142
2143         if(ar->alignment==RGN_ALIGN_TOP)
2144                 ar->alignment= RGN_ALIGN_BOTTOM;
2145         else if(ar->alignment==RGN_ALIGN_BOTTOM)
2146                 ar->alignment= RGN_ALIGN_TOP;
2147         else if(ar->alignment==RGN_ALIGN_LEFT)
2148                 ar->alignment= RGN_ALIGN_RIGHT;
2149         else if(ar->alignment==RGN_ALIGN_RIGHT)
2150                 ar->alignment= RGN_ALIGN_LEFT;
2151         
2152         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2153         printf("executed region flip\n");
2154         
2155         return OPERATOR_FINISHED;
2156 }
2157
2158
2159 static void SCREEN_OT_region_flip(wmOperatorType *ot)
2160 {
2161         /* identifiers */
2162         ot->name= "Flip Region";
2163         ot->idname= "SCREEN_OT_region_flip";
2164         
2165         /* api callbacks */
2166         ot->exec= region_flip_exec;
2167         
2168         ot->poll= ED_operator_areaactive;
2169         ot->flag= OPTYPE_REGISTER;
2170
2171 }
2172
2173 /* ****************** anim player, with timer ***************** */
2174
2175 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2176 {
2177         if(regiontype==RGN_TYPE_WINDOW) {
2178
2179                 switch (spacetype) {
2180                         case SPACE_VIEW3D:
2181                                 if(redraws & TIME_ALL_3D_WIN)
2182                                         return 1;
2183                                 break;
2184                         case SPACE_IPO:
2185                         case SPACE_ACTION:
2186                         case SPACE_NLA:
2187                                 if(redraws & TIME_ALL_ANIM_WIN)
2188                                         return 1;
2189                                 break;
2190                         case SPACE_TIME:
2191                                 /* if only 1 window or 3d windows, we do timeline too */
2192                                 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2193                                         return 1;
2194                                 break;
2195                         case SPACE_BUTS:
2196                                 if(redraws & TIME_ALL_BUTS_WIN)
2197                                         return 1;
2198                                 break;
2199                         case SPACE_SEQ:
2200                                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2201                                         return 1;
2202                                 break;
2203                         case SPACE_IMAGE:
2204                                 if(redraws & TIME_ALL_IMAGE_WIN)
2205                                         return 1;
2206                                 break;
2207                                 
2208                 }
2209         }
2210         else if(regiontype==RGN_TYPE_UI) {
2211                 if(redraws & TIME_ALL_BUTS_WIN)
2212                         return 1;
2213         }
2214         else if(regiontype==RGN_TYPE_HEADER) {
2215                 if(spacetype==SPACE_TIME)
2216                         return 1;
2217         }
2218         return 0;
2219 }
2220
2221 static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
2222 {
2223         bScreen *screen= CTX_wm_screen(C);
2224         
2225         if(screen->animtimer==event->customdata) {
2226                 Scene *scene= CTX_data_scene(C);
2227                 wmTimer *wt= screen->animtimer;
2228                 ScreenAnimData *sad= wt->customdata;
2229                 ScrArea *sa;
2230                 int sync;
2231
2232                 /* sync, don't sync, or follow scene setting */
2233                 if(sad->flag & ANIMPLAY_FLAG_SYNC) sync= 1;
2234                 else if(sad->flag & ANIMPLAY_FLAG_NO_SYNC) sync= 0;
2235                 else sync= (scene->r.audio.flag & AUDIO_SYNC);
2236                 
2237                 if(sync) {
2238                         /* skip frames */
2239                         int step = floor(wt->duration * FPS);
2240                         if(sad->flag & ANIMPLAY_FLAG_REVERSE) // XXX does this option work with audio?
2241                                 scene->r.cfra -= step;
2242                         else
2243                                 scene->r.cfra += step;
2244                         wt->duration -= ((float)step)/FPS;
2245                 }
2246                 else {
2247                         /* one frame +/- */
2248                         if(sad->flag & ANIMPLAY_FLAG_REVERSE)
2249                                 scene->r.cfra--;
2250                         else
2251                                 scene->r.cfra++;
2252                 }
2253                 
2254                 /* reset 'jumped' flag before checking if we need to jump... */
2255                 sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
2256                 
2257                 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
2258                         /* jump back to end? */
2259                         if (scene->r.psfra) {
2260                                 if (scene->r.cfra < scene->r.psfra) {
2261                                         scene->r.cfra= scene->r.pefra;
2262                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2263                                 }
2264                         }
2265                         else {
2266                                 if (scene->r.cfra < scene->r.sfra) {
2267                                         scene->r.cfra= scene->r.efra;
2268                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2269                                 }
2270                         }
2271                 }
2272                 else {
2273                         /* jump back to start? */
2274                         if (scene->r.psfra) {
2275                                 if (scene->r.cfra > scene->r.pefra) {
2276                                         scene->r.cfra= scene->r.psfra;
2277                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2278                                 }
2279                         }
2280                         else {
2281                                 if (scene->r.cfra > scene->r.efra) {
2282                                         scene->r.cfra= scene->r.sfra;
2283                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2284                                 }
2285                         }
2286                 }
2287
2288                 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2289                 ED_update_for_newframe(C, 1);
2290
2291                 sound_update_playing(C);
2292
2293                 for(sa= screen->areabase.first; sa; sa= sa->next) {
2294                         ARegion *ar;
2295                         for(ar= sa->regionbase.first; ar; ar= ar->next) {
2296                                 if(ar==sad->ar)
2297                                         ED_region_tag_redraw(ar);
2298                                 else
2299                                         if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2300                                                 ED_region_tag_redraw(ar);
2301                         }
2302                 }
2303                 
2304                 //WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2305                 
2306                 return OPERATOR_FINISHED;
2307         }
2308         return OPERATOR_PASS_THROUGH;
2309 }
2310
2311 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2312 {
2313         /* identifiers */
2314         ot->name= "Animation Step";
2315         ot->idname= "SCREEN_OT_animation_step";
2316         
2317         /* api callbacks */
2318         ot->invoke= screen_animation_step;
2319         
2320         ot->poll= ED_operator_screenactive;
2321         
2322 }
2323
2324 /* ****************** anim player, starts or ends timer ***************** */
2325
2326 /* toggle operator */
2327 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
2328 {
2329         bScreen *screen= CTX_wm_screen(C);
2330         
2331         if(screen->animtimer) {
2332                 ED_screen_animation_timer(C, 0, 0, 0);
2333                 sound_stop_all(C);
2334         }
2335         else {
2336                 ScrArea *sa= CTX_wm_area(C);
2337                 int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2338                 int sync= -1;
2339
2340                 if(RNA_property_is_set(op->ptr, "sync"))
2341                         sync= (RNA_boolean_get(op->ptr, "sync"));
2342                 
2343                 /* timeline gets special treatment since it has it's own menu for determining redraws */
2344                 if ((sa) && (sa->spacetype == SPACE_TIME)) {
2345                         SpaceTime *stime= (SpaceTime *)sa->spacedata.first;
2346                         
2347                         ED_screen_animation_timer(C, stime->redraws, sync, mode);
2348                         
2349                         /* update region if TIME_REGION was set, to leftmost 3d window */
2350                         ED_screen_animation_timer_update(C, stime->redraws);
2351                 }
2352                 else {
2353                         ED_screen_animation_timer(C, TIME_REGION|TIME_ALL_3D_WIN, sync, mode);
2354                         
2355                         if(screen->animtimer) {
2356                                 wmTimer *wt= screen->animtimer;
2357                                 ScreenAnimData *sad= wt->customdata;
2358                                 
2359                                 sad->ar= CTX_wm_region(C);
2360                         }
2361                 }
2362         }
2363         
2364         return OPERATOR_FINISHED;
2365 }
2366
2367 static void SCREEN_OT_animation_play(wmOperatorType *ot)
2368 {
2369         /* identifiers */
2370         ot->name= "Animation player";
2371         ot->idname= "SCREEN_OT_animation_play";
2372         
2373         /* api callbacks */
2374         ot->invoke= screen_animation_play;
2375         
2376         ot->poll= ED_operator_screenactive;
2377         
2378         RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2379         RNA_def_boolean(ot->srna, "sync", 0, "Sync", "Drop frames to maintain framerate and stay in sync with audio.");
2380 }
2381
2382 /* ************** border select operator (template) ***************************** */
2383
2384 /* operator state vars used: (added by default WM callbacks)   
2385         xmin, ymin     
2386         xmax, ymax     
2387
2388         customdata: the wmGesture pointer
2389
2390 callbacks:
2391
2392         exec()  has to be filled in by user
2393
2394         invoke() default WM function
2395                          adds modal handler
2396
2397         modal() default WM function 
2398                         accept modal events while doing it, calls exec(), handles ESC and border drawing
2399         
2400         poll()  has to be filled in by user for context
2401 */
2402 #if 0
2403 static int border_select_do(bContext *C, wmOperator *op)
2404 {
2405         int event_type= RNA_int_get(op->ptr, "event_type");
2406         
2407         if(event_type==LEFTMOUSE)
2408                 printf("border select do select\n");
2409         else if(event_type==RIGHTMOUSE)
2410                 printf("border select deselect\n");
2411         else 
2412                 printf("border select do something\n");
2413         
2414         return 1;
2415 }
2416
2417 static void SCREEN_OT_border_select(wmOperatorType *ot)
2418 {
2419         /* identifiers */
2420         ot->name= "Border select";
2421         ot->idname= "SCREEN_OT_border_select";
2422         
2423         /* api callbacks */
2424         ot->exec= border_select_do;
2425         ot->invoke= WM_border_select_invoke;
2426         ot->modal= WM_border_select_modal;
2427         
2428         ot->poll= ED_operator_areaactive;
2429         
2430         /* rna */
2431         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2432         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2433         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2434         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2435         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2436
2437 }
2438 #endif
2439
2440 /* ****************************** render invoking ***************** */
2441
2442 /* set callbacks, exported to sequence render too. 
2443 Only call in foreground (UI) renders. */
2444
2445 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
2446 /* window as the last possible alternative.                                                                        */
2447 static ScrArea *biggest_non_image_area(bContext *C)
2448 {
2449         bScreen *sc= CTX_wm_screen(C);
2450         ScrArea *sa, *big= NULL;
2451         int size, maxsize= 0, bwmaxsize= 0;
2452         short foundwin= 0;
2453         
2454         for(sa= sc->areabase.first; sa; sa= sa->next) {
2455                 if(sa->winx > 30 && sa->winy > 30) {
2456                         size= sa->winx*sa->winy;
2457                         if(sa->spacetype == SPACE_BUTS) {
2458                                 if(foundwin == 0 && size > bwmaxsize) {
2459                                         bwmaxsize= size;
2460                                         big= sa;        
2461                                 }
2462                         }
2463                         else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
2464                                 maxsize= size;
2465                                 big= sa;
2466                                 foundwin= 1;
2467                         }
2468                 }
2469         }
2470         
2471         return big;
2472 }
2473
2474 static ScrArea *biggest_area(bContext *C)
2475 {
2476         bScreen *sc= CTX_wm_screen(C);
2477         ScrArea *sa, *big= NULL;
2478         int size, maxsize= 0;
2479         
2480         for(sa= sc->areabase.first; sa; sa= sa->next) {
2481                 size= sa->winx*sa->winy;
2482                 if(size > maxsize) {
2483                         maxsize= size;
2484                         big= sa;
2485                 }
2486         }
2487         return big;
2488 }
2489
2490
2491 static ScrArea *find_area_showing_r_result(bContext *C)
2492 {
2493         bScreen *sc= CTX_wm_screen(C);
2494         ScrArea *sa;
2495         SpaceImage *sima;
2496         
2497         /* find an imagewindow showing render result */
2498         for(sa=sc->areabase.first; sa; sa= sa->next) {
2499                 if(sa->spacetype==SPACE_IMAGE) {
2500                         sima= sa->spacedata.first;
2501                         if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
2502                                 break;
2503                 }
2504         }
2505         return sa;
2506 }
2507
2508 static ScrArea *find_area_image_empty(bContext *C)
2509 {
2510         bScreen *sc= CTX_wm_screen(C);
2511         ScrArea *sa;
2512         SpaceImage *sima;
2513         
2514         /* find an imagewindow showing render result */
2515         for(sa=sc->areabase.first; sa; sa= sa->next) {
2516                 if(sa->spacetype==SPACE_IMAGE) {
2517                         sima= sa->spacedata.first;
2518                         if(!sima->image)
2519                                 break;
2520                 }
2521         }
2522         return sa;
2523 }
2524
2525 #if 0 // XXX not used
2526 static ScrArea *find_empty_image_area(bContext *C)
2527 {
2528         bScreen *sc= CTX_wm_screen(C);
2529         ScrArea *sa;
2530         SpaceImage *sima;
2531         
2532         /* find an imagewindow showing render result */
2533         for(sa=sc->areabase.first; sa; sa= sa->next) {
2534                 if(sa->spacetype==SPACE_IMAGE) {
2535                         sima= sa->spacedata.first;
2536                         if(!sima->image)
2537                                 break;
2538                 }
2539         }
2540         return sa;
2541 }
2542 #endif // XXX not used
2543
2544 /* new window uses x,y to set position */
2545 static void screen_set_image_output(bContext *C, int mx, int my)
2546 {
2547         Scene *scene= CTX_data_scene(C);
2548         ScrArea *sa;
2549         SpaceImage *sima;
2550         
2551         if(scene->r.displaymode==R_OUTPUT_WINDOW) {
2552                 rcti rect;
2553                 int sizex, sizey;
2554                 
2555                 sizex= 10 + (scene->r.xsch*scene->r.size)/100;
2556                 sizey= 40 + (scene->r.ysch*scene->r.size)/100;
2557                 
2558                 /* arbitrary... miniature image window views don't make much sense */
2559                 if(sizex < 320) sizex= 320;
2560                 if(sizey < 256) sizey= 256;
2561                 
2562                 /* XXX some magic to calculate postition */
2563                 rect.xmin= mx + CTX_wm_window(C)->posx - sizex/2;
2564                 rect.ymin= my + CTX_wm_window(C)->posy - sizey/2;
2565                 rect.xmax= rect.xmin + sizex;
2566                 rect.ymax= rect.ymin + sizey;
2567                 
2568                 /* changes context! */
2569                 WM_window_open_temp(C, &rect, WM_WINDOW_RENDER);
2570                 
2571                 sa= CTX_wm_area(C);
2572         }
2573         else if(scene->r.displaymode==R_OUTPUT_SCREEN) {
2574                 /* this function returns with changed context */
2575                 ED_screen_full_newspace(C, CTX_wm_area(C), SPACE_IMAGE);
2576                 sa= CTX_wm_area(C);
2577         }
2578         else {
2579         
2580                 sa= find_area_showing_r_result(C);
2581                 if(sa==NULL)
2582                         sa= find_area_image_empty(C);
2583                 
2584                 if(sa==NULL) {
2585                         /* find largest open non-image area */
2586                         sa= biggest_non_image_area(C);
2587                         if(sa) {
2588                                 ED_area_newspace(C, sa, SPACE_IMAGE);
2589                                 sima= sa->spacedata.first;
2590                                 
2591                                 /* makes ESC go back to prev space */
2592                                 sima->flag |= SI_PREVSPACE;
2593                         }
2594                         else {
2595                                 /* use any area of decent size */
2596                                 sa= biggest_area(C);
2597                                 if(sa->spacetype!=SPACE_IMAGE) {
2598                                         // XXX newspace(sa, SPACE_IMAGE);
2599                                         sima= sa->spacedata.first;
2600                                         
2601                                         /* makes ESC go back to prev space */
2602                                         sima->flag |= SI_PREVSPACE;
2603                                 }
2604                         }
2605                 }
2606         }       
2607         sima= sa->spacedata.first;
2608         
2609         /* get the correct image, and scale it */
2610         sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2611         
2612 //      if(G.displaymode==2) { // XXX
2613                 if(sa->full) {
2614                         sima->flag |= SI_FULLWINDOW|SI_PREVSPACE;
2615                         
2616 //                      ed_screen_fullarea(C, sa);
2617                 }
2618 //      }
2619         
2620 }
2621
2622 /* executes blocking render */
2623 static int screen_render_exec(bContext *C, wmOperator *op)
2624 {
2625         Scene *scene= CTX_data_scene(C);
2626         Render *re= RE_GetRender(scene->id.name);
2627         
2628         if(re==NULL) {
2629                 re= RE_NewRender(scene->id.name);
2630         }
2631         RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
2632         
2633         if(RNA_boolean_get(op->ptr, "animation"))
2634                 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
2635         else
2636                 RE_BlenderFrame(re, scene, scene->r.cfra);
2637         
2638         // no redraw needed, we leave state as we entered it
2639         ED_update_for_newframe(C, 1);
2640         
2641         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2642
2643         return OPERATOR_FINISHED;
2644 }
2645
2646 typedef struct RenderJob {
2647         Scene *scene;
2648         Render *re;
2649         wmWindow *win;
2650         int anim;
2651         Image *image;
2652         ImageUser iuser;
2653         short *stop;
2654         short *do_update;
2655 } RenderJob;
2656
2657 static void render_freejob(void *rjv)
2658 {
2659         RenderJob *rj= rjv;
2660         
2661         MEM_freeN(rj);
2662 }
2663
2664 /* str is IMA_RW_MAXTEXT in size */
2665 static void make_renderinfo_string(RenderStats *rs, Scene *scene, char *str)
2666 {
2667         char info_time_str[32]; // used to be extern to header_info.c
2668         uintptr_t mem_in_use, mmap_in_use;
2669         float megs_used_memory, mmap_used_memory;
2670         char *spos= str;
2671         
2672         mem_in_use= MEM_get_memory_in_use();
2673         mmap_in_use= MEM_get_mapped_memory_in_use();
2674         
2675         megs_used_memory= (mem_in_use-mmap_in_use)/(1024.0*1024.0);
2676         mmap_used_memory= (mmap_in_use)/(1024.0*1024.0);
2677         
2678         if(scene->lay & 0xFF000000)
2679                 spos+= sprintf(spos, "Localview | ");
2680         else if(scene->r.scemode & R_SINGLE_LAYER)
2681                 spos+= sprintf(spos, "Single Layer | ");
2682         
2683         if(rs->statstr) {
2684                 spos+= sprintf(spos, "%s ", rs->statstr);
2685         }
2686         else {
2687                 spos+= sprintf(spos, "Fra:%d  Ve:%d Fa:%d ", (scene->r.cfra), rs->totvert, rs->totface);
2688                 if(rs->tothalo) spos+= sprintf(spos, "Ha:%d ", rs->tothalo);
2689                 if(rs->totstrand) spos+= sprintf(spos, "St:%d ", rs->totstrand);
2690                 spos+= sprintf(spos, "La:%d Mem:%.2fM (%.2fM) ", rs->totlamp, megs_used_memory, mmap_used_memory);
2691                 
2692                 if(rs->curfield)
2693                         spos+= sprintf(spos, "Field %d ", rs->curfield);
2694                 if(rs->curblur)
2695                         spos+= sprintf(spos, "Blur %d ", rs->curblur);
2696         }
2697         
2698         BLI_timestr(rs->lastframetime, info_time_str);
2699         spos+= sprintf(spos, "Time:%s ", info_time_str);
2700         
2701         if(rs->infostr && rs->infostr[0])
2702                 spos+= sprintf(spos, "| %s ", rs->infostr);
2703         
2704         /* very weak... but 512 characters is quite safe */
2705         if(spos >= str+IMA_RW_MAXTEXT)
2706                 printf("WARNING! renderwin text beyond limit \n");
2707         
2708 }
2709
2710 static void image_renderinfo_cb(void *rjv, RenderStats *rs)
2711 {
2712         RenderJob *rj= rjv;
2713         
2714         /* malloc OK here, stats_draw is not in tile threads */
2715         if(rj->image->render_text==NULL)
2716                 rj->image->render_text= MEM_callocN(IMA_RW_MAXTEXT, "rendertext");
2717         
2718         make_renderinfo_string(rs, rj->scene, rj->image->render_text);
2719         
2720         /* make jobs timer to send notifier */
2721         *(rj->do_update)= 1;
2722
2723 }
2724
2725 /* called inside thread! */
2726 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
2727 {
2728         RenderJob *rj= rjv;
2729         ImBuf *ibuf;
2730         float x1, y1, *rectf= NULL;
2731         int ymin, ymax, xmin, xmax;
2732         int rymin, rxmin;
2733         char *rectc;
2734         
2735         ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2736         if(ibuf==NULL) return;
2737
2738         /* if renrect argument, we only refresh scanlines */
2739         if(renrect) {
2740                 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2741                 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2742                         return;
2743                 
2744                 /* xmin here is first subrect x coord, xmax defines subrect width */
2745                 xmin = renrect->xmin + rr->crop;
2746                 xmax = renrect->xmax - xmin - rr->crop;
2747                 if (xmax<2) return;
2748                 
2749                 ymin= renrect->ymin + rr->crop;
2750                 ymax= renrect->ymax - ymin - rr->crop;
2751                 if(ymax<2)
2752                         return;
2753                 renrect->ymin= renrect->ymax;
2754                 
2755         }
2756         else {
2757                 xmin = ymin = rr->crop;
2758                 xmax = rr->rectx - 2*rr->crop;
2759                 ymax = rr->recty - 2*rr->crop;
2760         }
2761         
2762         /* xmin ymin is in tile coords. transform to ibuf */
2763         rxmin= rr->tilerect.xmin + xmin;
2764         if(rxmin >= ibuf->x) return;
2765         rymin= rr->tilerect.ymin + ymin;
2766         if(rymin >= ibuf->y) return;
2767         
2768         if(rxmin + xmax > ibuf->x)
2769                 xmax= ibuf->x - rxmin;
2770         if(rymin + ymax > ibuf->y)
2771                 ymax= ibuf->y - rymin;
2772         
2773         if(xmax < 1 || ymax < 1) return;
2774         
2775         /* find current float rect for display, first case is after composit... still weak */
2776         if(rr->rectf)
2777                 rectf= rr->rectf;
2778         else {
2779                 if(rr->rect32)
2780                         return;
2781                 else {
2782                         if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2783                         rectf= rr->renlay->rectf;
2784                 }
2785         }
2786         if(rectf==NULL) return;
2787         
2788         rectf+= 4*(rr->rectx*ymin + xmin);
2789         rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2790
2791         /* XXX make nice consistent functions for this */
2792         if (rj->scene->r.color_mgt_flag & R_COLOR_MANAGEMENT) {
2793                 for(y1= 0; y1<ymax; y1++) {
2794                         float *rf= rectf;
2795                         float srgb[3];
2796                         char *rc= rectc;
2797                         
2798                         /* XXX temp. because crop offset */
2799                         if( rectc >= (char *)(ibuf->rect)) {
2800                                 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2801                                         srgb[0]= linearrgb_to_srgb(rf[0]);
2802                                         srgb[1]= linearrgb_to_srgb(rf[1]);
2803                                         srgb[2]= linearrgb_to_srgb(rf[2]);
2804
2805                                         rc[0]= FTOCHAR(srgb[0]);
2806                                         rc[1]= FTOCHAR(srgb[1]);
2807                                         rc[2]= FTOCHAR(srgb[2]);
2808                                         rc[3]= FTOCHAR(rf[3]);
2809                                 }
2810                         }
2811                         rectf += 4*rr->rectx;
2812                         rectc += 4*ibuf->x;
2813                 }
2814         } else {
2815                 for(y1= 0; y1<ymax; y1++) {
2816                         float *rf= rectf;
2817                         char *rc= rectc;
2818                         
2819                         /* XXX temp. because crop offset */
2820                         if( rectc >= (char *)(ibuf->rect)) {
2821                                 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2822                                         rc[0]= FTOCHAR(rf[0]);
2823                                         rc[1]= FTOCHAR(rf[1]);
2824                                         rc[2]= FTOCHAR(rf[2]);
2825                                         rc[3]= FTOCHAR(rf[3]);
2826                                 }
2827                         }
2828                         rectf += 4*rr->rectx;
2829                         rectc += 4*ibuf->x;
2830                 }
2831         }
2832         
2833         /* make jobs timer to send notifier */
2834         *(rj->do_update)= 1;
2835 }
2836
2837 static void render_startjob(void *rjv, short *stop, short *do_update)
2838 {
2839         RenderJob *rj= rjv;
2840         
2841         rj->stop= stop;
2842         rj->do_update= do_update;
2843         
2844         if(rj->anim)
2845                 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2846         else
2847                 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2848 }
2849
2850 /* called by render, check job 'stop' value or the global */
2851 static int render_breakjob(void *rjv)
2852 {
2853         RenderJob *rj= rjv;
2854         
2855         if(G.afbreek)
2856                 return 1;
2857         if(rj->stop && *(rj->stop))
2858                 return 1;
2859         return 0;
2860 }
2861
2862 /* catch esc */
2863 static int screen_render_modal(bContext *C, wmOperator *op, wmEvent *event)
2864 {
2865         /* no running blender, remove handler and pass through */
2866         if(0==WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C)))
2867            return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
2868         
2869         /* running render */
2870         switch (event->type) {
2871                 case ESCKEY:
2872                         return OPERATOR_RUNNING_MODAL;
2873                         break;
2874         }
2875         return OPERATOR_PASS_THROUGH;
2876 }
2877
2878 /* using context, starts job */
2879 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2880 {
2881         /* new render clears all callbacks */
2882         Scene *scene= CTX_data_scene(C);
2883         Render *re;
2884         wmJob *steve;
2885         RenderJob *rj;
2886         Image *ima;
2887         
2888         /* only one job at a time */
2889         if(WM_jobs_test(CTX_wm_manager(C), scene))
2890                 return OPERATOR_CANCELLED;
2891         
2892         /* handle UI stuff */
2893         WM_cursor_wait(1);
2894
2895         /* flush multires changes (for sculpt) */
2896         multires_force_update(CTX_data_active_object(C));
2897         
2898         /* get editmode results */
2899         ED_object_exit_editmode(C, 0);  /* 0 = does not exit editmode */
2900         
2901         // store spare
2902         // get view3d layer, local layer, make this nice api call to render
2903         // store spare
2904         
2905         /* ensure at least 1 area shows result */
2906         screen_set_image_output(C, event->x, event->y);
2907
2908         /* job custom data */
2909         rj= MEM_callocN(sizeof(RenderJob), "render job");
2910         rj->scene= scene;
2911         rj->win= CTX_wm_window(C);
2912         rj->anim= RNA_boolean_get(op->ptr, "animation");
2913         rj->iuser.scene= scene;
2914         rj->iuser.ok= 1;
2915         
2916         /* setup job */
2917         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2918         WM_jobs_customdata(steve, rj, render_freejob);
2919         WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2920         WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2921         
2922         /* get a render result image, and make sure it is empty */
2923         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2924         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2925         rj->image= ima;
2926         
2927         /* setup new render */
2928         re= RE_NewRender(scene->id.name);
2929         RE_test_break_cb(re, rj, render_breakjob);
2930         RE_display_draw_cb(re, rj, image_rect_update);
2931         RE_stats_draw_cb(re, rj, image_renderinfo_cb);
2932         
2933         rj->re= re;
2934         G.afbreek= 0;
2935         
2936         //      BKE_report in render!
2937         //      RE_error_cb(re, error_cb);
2938
2939         WM_jobs_start(CTX_wm_manager(C), steve);
2940         
2941         G.afbreek= 0;
2942         
2943         WM_cursor_wait(0);
2944         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2945
2946         /* add modal handler for ESC */
2947         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
2948         
2949         return OPERATOR_RUNNING_MODAL;
2950 }
2951
2952
2953 /* contextual render, using current scene, view3d? */
2954 static void SCREEN_OT_render(wmOperatorType *ot)
2955 {
2956         /* identifiers */
2957         ot->name= "Render";
2958         ot->idname= "SCREEN_OT_render";
2959         
2960         /* api callbacks */
2961         ot->invoke= screen_render_invoke;
2962         ot->modal= screen_render_modal;
2963         ot->exec= screen_render_exec;
2964         
2965         ot->poll= ED_operator_screenactive;
2966         
2967         RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2968         RNA_def_boolean(ot->srna, "animation", 0, "Animation", "");
2969 }
2970
2971 /* *********************** cancel render viewer *************** */
2972
2973 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2974 {
2975         ScrArea *sa= CTX_wm_area(C);
2976         SpaceImage *sima= sa->spacedata.first;
2977         
2978         /* test if we have a temp screen in front */
2979         if(CTX_wm_window(C)->screen->full==SCREENTEMP) {
2980                 wm_window_lower(CTX_wm_window(C));
2981         }
2982         /* determine if render already shows */
2983         else if(sima->flag & SI_PREVSPACE) {
2984                 sima->flag &= ~SI_PREVSPACE;
2985                 
2986                 if(sima->flag & SI_FULLWINDOW) {
2987                         sima->flag &= ~SI_FULLWINDOW;
2988                         ED_screen_full_prevspace(C);
2989                 }
2990                 else
2991                         ED_area_prevspace(C);
2992         }
2993         else if(sima->flag & SI_FULLWINDOW) {
2994                 sima->flag &= ~SI_FULLWINDOW;
2995                 ed_screen_fullarea(C, sa);
2996         }               
2997         
2998         return OPERATOR_FINISHED;
2999 }
3000
3001 static void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
3002 {
3003         /* identifiers */
3004         ot->name= "Cancel Render View";
3005         ot->idname= "SCREEN_OT_render_view_cancel";
3006         
3007         /* api callbacks */
3008         ot->exec= render_view_cancel_exec;
3009         ot->poll= ED_operator_image_active;
3010 }
3011
3012 /* *********************** show render viewer *************** */
3013
3014 static int render_view_show_invoke(bContext *C, wmOperator *unused, wmEvent *event)
3015 {
3016         ScrArea *sa= find_area_showing_r_result(C);
3017
3018         /* test if we have a temp screen in front */
3019         if(CTX_wm_window(C)->screen->full==SCREENTEMP) {
3020                 wm_window_lower(CTX_wm_window(C));
3021         }
3022         /* determine if render already shows */
3023         else if(sa) {
3024                 SpaceImage *sima= sa->spacedata.first;
3025                 
3026                 if(sima->flag & SI_PREVSPACE) {
3027                         sima->flag &= ~SI_PREVSPACE;
3028                         
3029                         if(sima->flag & SI_FULLWINDOW) {
3030                                 sima->flag &= ~SI_FULLWINDOW;
3031                                 ED_screen_full_prevspace(C);
3032                         }
3033                         else if(sima->next) {
3034                                 ED_area_newspace(C, sa, sima->next->spacetype);
3035                                 ED_area_tag_redraw(sa);
3036                         }
3037                 }
3038         }
3039         else {
3040                 screen_set_image_output(C, event->x, event->y);
3041         }
3042         
3043         return OPERATOR_FINISHED;
3044 }
3045
3046 static void SCREEN_OT_render_view_show(struct wmOperatorType *ot)
3047 {
3048         /* identifiers */
3049         ot->name= "Show/Hide Render View";
3050         ot->idname= "SCREEN_OT_render_view_show";
3051         
3052         /* api callbacks */
3053         ot->invoke= render_view_show_invoke;
3054         ot->poll= ED_operator_screenactive;
3055 }
3056
3057 /* *********** show user pref window ****** */
3058
3059 static int userpref_show_invoke(bContext *C, wmOperator *unused, wmEvent *event)
3060 {
3061         ScrArea *sa;
3062         rcti rect;
3063         int sizex, sizey;
3064         
3065         sizex= 800;
3066         sizey= 480;
3067         
3068         /* some magic to calculate postition */
3069         rect.xmin= event->x + CTX_wm_window(C)->posx - sizex/2;
3070         rect.ymin= event->y + CTX_wm_window(C)->posy - sizey/2;
3071         rect.xmax= rect.xmin + sizex;
3072         rect.ymax= rect.ymin + sizey;
3073         
3074         /* changes context! */
3075         WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS);
3076         
3077         sa= CTX_wm_area(C);
3078         
3079         
3080         return OPERATOR_FINISHED;
3081 }
3082
3083
3084 static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
3085 {
3086         /* identifiers */
3087         ot->name= "Show/Hide User Preferences";
3088         ot->idname= "SCREEN_OT_userpref_show";
3089         
3090         /* api callbacks */
3091         ot->invoke= userpref_show_invoke;
3092         ot->poll= ED_operator_screenactive;
3093 }
3094
3095 /********************* new screen operator *********************/
3096
3097 static int screen_new_exec(bContext *C, wmOperator *op)
3098 {
3099         wmWindow *win= CTX_wm_window(C);
3100         bScreen *sc= CTX_wm_screen(C);
3101
3102         sc= ED_screen_duplicate(win, sc);
3103         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENBROWSE, sc);
3104
3105         return OPERATOR_FINISHED;
3106 }
3107
3108 void SCREEN_OT_new(wmOperatorType *ot)
3109 {
3110         /* identifiers */
3111         ot->name= "New Screen";
3112         ot->idname= "SCREEN_OT_new";
3113         
3114         /* api callbacks */
3115         ot->exec= screen_new_exec;
3116
3117         /* flags */
3118         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3119 }
3120
3121 /********************* delete screen operator *********************/
3122
3123 static int screen_delete_exec(bContext *C, wmOperator *op)
3124 {
3125         bScreen *sc= CTX_wm_screen(C);
3126
3127         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENDELETE, sc);
3128
3129         return OPERATOR_FINISHED;
3130 }
3131
3132 void SCREEN_OT_delete(wmOperatorType *ot)
3133 {
3134         /* identifiers */
3135         ot->name= "Delete Scene";
3136         ot->idname= "SCREEN_OT_delete";
3137         
3138         /* api callbacks */
3139         ot->exec= screen_delete_exec;
3140
3141         /* flags */
3142         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3143 }
3144
3145 /********************* new scene operator *********************/
3146
3147 static int scene_new_exec(bContext *C, wmOperator *op)
3148 {
3149         Scene *newscene, *scene= CTX_data_scene(C);
3150         Main *bmain= CTX_data_main(C);
3151         int type= RNA_enum_get(op->ptr, "type");
3152
3153         newscene= copy_scene(bmain, scene, type);
3154
3155         /* these can't be handled in blenkernel curently, so do them here */
3156         if(type == SCE_COPY_LINK_DATA)
3157                 ED_object_single_users(newscene, 0);
3158         else if(type == SCE_COPY_FULL)
3159                 ED_object_single_users(newscene, 1);
3160
3161         WM_event_add_notifier(C, NC_SCENE|ND_SCENEBROWSE, newscene);
3162
3163         return OPERATOR_FINISHED;
3164 }
3165
3166 void SCENE_OT_new(wmOperatorType *ot)
3167 {
3168         static EnumPropertyItem type_items[]= {
3169                 {SCE_COPY_EMPTY, "EMPTY", 0, "Empty", "Add empty scene."},
3170                 {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene."},
3171                 {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene."},
3172                 {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene."},
3173                 {0, NULL, 0, NULL, NULL}};
3174
3175         /* identifiers */
3176         ot->name= "New Scene";
3177         ot->idname= "SCENE_OT_new";
3178         
3179         /* api callbacks */
3180         ot->exec= scene_new_exec;
3181         ot->invoke= WM_menu_invoke;
3182
3183         /* flags */
3184         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3185
3186         /* properties */
3187         RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
3188 }
3189
3190 /********************* delete scene operator *********************/
3191
3192 static int scene_delete_exec(bContext *C, wmOperator *op)
3193 {
3194         Scene *scene= CTX_data_scene(C);
3195
3196         WM_event_add_notifier(C, NC_SCENE|ND_SCENEDELETE, scene);
3197
3198         return OPERATOR_FINISHED;
3199 }
3200
3201 void SCENE_OT_delete(wmOperatorType *ot)
3202 {
3203         /* identifiers */
3204         ot->name= "Delete Scene";
3205         ot->idname= "SCENE_OT_delete";
3206         
3207         /* api callbacks */
3208         ot->exec= scene_delete_exec;
3209
3210         /* flags */
3211         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3212 }
3213
3214 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
3215
3216 /* called in spacetypes.c */
3217 void ED_operatortypes_screen(void)
3218 {
3219         /* generic UI stuff */
3220         WM_operatortype_append(SCREEN_OT_actionzone);
3221         WM_operatortype_append(SCREEN_OT_repeat_last);
3222         WM_operatortype_append(SCREEN_OT_repeat_history);
3223         WM_operatortype_append(SCREEN_OT_redo_last);
3224         
3225         /* screen tools */
3226         WM_operatortype_append(SCREEN_OT_area_move);
3227         WM_operatortype_append(SCREEN_OT_area_split);
3228         WM_operatortype_append(SCREEN_OT_area_join);
3229         WM_operatortype_append(SCREEN_OT_area_dupli);
3230         WM_operatortype_append(SCREEN_OT_area_swap);
3231         WM_operatortype_append(SCREEN_OT_region_split);
3232         WM_operatortype_append(SCREEN_OT_region_foursplit);
3233         WM_operatortype_append(SCREEN_OT_region_flip);
3234         WM_operatortype_append(SCREEN_OT_region_scale);
3235         WM_operatortype_append(SCREEN_OT_screen_set);
3236         WM_operatortype_append(SCREEN_OT_screen_full_area);
3237         WM_operatortype_append(SCREEN_OT_screenshot);
3238         WM_operatortype_append(SCREEN_OT_screencast);
3239         WM_operatortype_append(SCREEN_OT_userpref_show);
3240         
3241         /*frame changes*/
3242         WM_operatortype_append(SCREEN_OT_frame_offset);
3243         WM_operatortype_append(SCREEN_OT_frame_jump);
3244         WM_operatortype_append(SCREEN_OT_keyframe_jump);
3245         
3246         WM_operatortype_append(SCREEN_OT_animation_step);
3247         WM_operatortype_append(SCREEN_OT_animation_play);
3248         
3249         /* render */
3250         WM_operatortype_append(SCREEN_OT_render);
3251         WM_operatortype_append(SCREEN_OT_render_view_cancel);
3252         WM_operatortype_append(SCREEN_OT_render_view_show);
3253
3254         /* new/delete */
3255         WM_operatortype_append(SCREEN_OT_new);
3256         WM_operatortype_append(SCREEN_OT_delete);
3257         WM_operatortype_append(SCENE_OT_new);
3258         WM_operatortype_append(SCENE_OT_delete);
3259
3260         /* tools shared by more space types */
3261         WM_operatortype_append(ED_OT_undo);
3262         WM_operatortype_append(ED_OT_redo);     
3263         
3264 }
3265
3266 static void keymap_modal_set(wmWindowManager *wm)
3267 {
3268         static EnumPropertyItem modal_items[] = {
3269                 {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
3270                 {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
3271                 {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""},
3272                 {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""},
3273                 {0, NULL, 0, NULL, NULL}};
3274         wmKeyMap *keymap;
3275         
3276         /* Standard Modal keymap ------------------------------------------------ */
3277         keymap= WM_modalkeymap_add(wm, "Standard Modal Map", modal_items);
3278         
3279         WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, KM_MODAL_CANCEL);
3280         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KM_MODAL_APPLY);
3281         WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
3282         WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
3283
3284         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10);
3285         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF);
3286         
3287         WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
3288
3289 }
3290
3291 /* called in spacetypes.c */
3292 void ED_keymap_screen(wmWindowManager *wm)
3293 {
3294         ListBase *keymap;
3295         
3296         /* Screen General ------------------------------------------------ */
3297         keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
3298         
3299         /* standard timers */
3300         WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
3301         
3302         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
3303         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
3304         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2);
3305         
3306         /* screen tools */
3307         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
3308         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
3309         WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
3310         WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_ALT, 0);
3311         WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
3312                         /* area move after action zones */
3313         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
3314         
3315         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
3316         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
3317         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
3318         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
3319         WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);