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