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