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