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