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