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