2.5
[blender-staging.git] / source / blender / editors / screen / screen_ops.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include "MEM_guardedalloc.h"
28
29 #include "BLI_arithb.h"
30 #include "BLI_blenlib.h"
31 #include "BLI_editVert.h"
32
33 #include "DNA_armature_types.h"
34 #include "DNA_image_types.h"
35 #include "DNA_object_types.h"
36 #include "DNA_mesh_types.h"
37 #include "DNA_curve_types.h"
38 #include "DNA_scene_types.h"
39
40 #include "BKE_blender.h"
41 #include "BKE_context.h"
42 #include "BKE_customdata.h"
43 #include "BKE_global.h"
44 #include "BKE_image.h"
45 #include "BKE_idprop.h"
46 #include "BKE_library.h"
47 #include "BKE_main.h"
48 #include "BKE_multires.h"
49 #include "BKE_report.h"
50 #include "BKE_screen.h"
51 #include "BKE_utildefines.h"
52
53 #include "WM_api.h"
54 #include "WM_types.h"
55
56 #include "ED_util.h"
57 #include "ED_screen.h"
58 #include "ED_screen_types.h"
59
60 #include "RE_pipeline.h"
61 #include "IMB_imbuf.h"
62 #include "IMB_imbuf_types.h"
63
64 #include "RNA_access.h"
65 #include "RNA_define.h"
66
67 #include "UI_interface.h"
68 #include "UI_resources.h"
69
70 #include "screen_intern.h"      /* own module include */
71
72 /* ************** Exported Poll tests ********************** */
73
74 int ED_operator_areaactive(bContext *C)
75 {
76         if(CTX_wm_window(C)==NULL) return 0;
77         if(CTX_wm_screen(C)==NULL) return 0;
78         if(CTX_wm_area(C)==NULL) return 0;
79         return 1;
80 }
81
82 int ED_operator_screenactive(bContext *C)
83 {
84         if(CTX_wm_window(C)==NULL) return 0;
85         if(CTX_wm_screen(C)==NULL) return 0;
86         return 1;
87 }
88
89 /* when mouse is over area-edge */
90 int ED_operator_screen_mainwinactive(bContext *C)
91 {
92         if(CTX_wm_window(C)==NULL) return 0;
93         if(CTX_wm_screen(C)==NULL) return 0;
94         if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
95         return 1;
96 }
97
98 int ED_operator_scene_editable(bContext *C)
99 {
100         Scene *scene= CTX_data_scene(C);
101         if(scene && scene->id.lib==NULL)
102                 return 1;
103         return 0;
104 }
105
106 static int ed_spacetype_test(bContext *C, int type)
107 {
108         if(ED_operator_areaactive(C)) {
109                 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
110                 return sl && (sl->spacetype == type);
111         }
112         return 0;
113 }
114
115 int ED_operator_view3d_active(bContext *C)
116 {
117         return ed_spacetype_test(C, SPACE_VIEW3D);
118 }
119
120 int ED_operator_timeline_active(bContext *C)
121 {
122         return ed_spacetype_test(C, SPACE_TIME);
123 }
124
125 int ED_operator_outliner_active(bContext *C)
126 {
127         if(ed_spacetype_test(C, SPACE_OOPS)) {
128                 SpaceOops *so= (SpaceOops *)CTX_wm_space_data(C);
129                 return (so->type == SO_OUTLINER);
130         }
131         return 0;
132 }
133
134 int ED_operator_file_active(bContext *C)
135 {
136         return ed_spacetype_test(C, SPACE_FILE);
137 }
138
139 int ED_operator_action_active(bContext *C)
140 {
141         return ed_spacetype_test(C, SPACE_ACTION);
142 }
143
144 int ED_operator_buttons_active(bContext *C)
145 {
146         return ed_spacetype_test(C, SPACE_BUTS);
147 }
148
149 int ED_operator_node_active(bContext *C)
150 {
151         return ed_spacetype_test(C, SPACE_NODE);
152 }
153
154 int ED_operator_ipo_active(bContext *C)
155 {
156         return ed_spacetype_test(C, SPACE_IPO);
157 }
158
159 int ED_operator_sequencer_active(bContext *C)
160 {
161         return ed_spacetype_test(C, SPACE_SEQ);
162 }
163
164 int ED_operator_image_active(bContext *C)
165 {
166         return ed_spacetype_test(C, SPACE_IMAGE);
167 }
168
169 int ED_operator_object_active(bContext *C)
170 {
171         return NULL != CTX_data_active_object(C);
172 }
173
174 int ED_operator_editmesh(bContext *C)
175 {
176         Object *obedit= CTX_data_edit_object(C);
177         if(obedit && obedit->type==OB_MESH)
178                 return NULL != ((Mesh *)obedit->data)->edit_mesh;
179         return 0;
180 }
181
182 int ED_operator_editarmature(bContext *C)
183 {
184         Object *obedit= CTX_data_edit_object(C);
185         if(obedit && obedit->type==OB_ARMATURE)
186                 return NULL != ((bArmature *)obedit->data)->edbo;
187         return 0;
188 }
189
190 int ED_operator_posemode(bContext *C)
191 {
192         Object *obact= CTX_data_active_object(C);
193         if(obact && obact->type==OB_ARMATURE)
194                 return (obact->flag & OB_POSEMODE)!=0;
195         return 0;
196 }
197
198
199 int ED_operator_uvedit(bContext *C)
200 {
201         Object *obedit= CTX_data_edit_object(C);
202         EditMesh *em= NULL;
203
204         if(obedit && obedit->type==OB_MESH)
205                 em= ((Mesh *)obedit->data)->edit_mesh;
206
207     if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE)))
208                 return 1;
209
210         return 0;
211 }
212
213 int ED_operator_uvmap(bContext *C)
214 {
215         Object *obedit= CTX_data_edit_object(C);
216         EditMesh *em= NULL;
217
218         if(obedit && obedit->type==OB_MESH)
219                 em= ((Mesh *)obedit->data)->edit_mesh;
220
221     if(em && (em->faces.first))
222                 return 1;
223
224         return 0;
225 }
226
227 int ED_operator_editcurve(bContext *C)
228 {
229         Object *obedit= CTX_data_edit_object(C);
230         if(obedit && obedit->type==OB_CURVE)
231                 return NULL != ((Mesh *)obedit->data)->edit_mesh;
232         return 0;
233 }
234
235
236 /* *************************** action zone operator ************************** */
237
238 /* operator state vars used:  
239         none
240
241 functions:
242
243         apply() set actionzone event
244
245         exit()  free customdata
246         
247 callbacks:
248
249         exec()  never used
250
251         invoke() check if in zone  
252                 add customdata, put mouseco and area in it
253                 add modal handler
254
255         modal() accept modal events while doing it
256                 call apply() with gesture info, active window, nonactive window
257                 call exit() and remove handler when LMB confirm
258
259 */
260
261 typedef struct sActionzoneData {
262         ScrArea *sa1, *sa2;
263         AZone *az;
264         int x, y, gesture_dir;
265 } sActionzoneData;
266
267 /* used by other operators too */
268 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
269 {
270         ScrArea *sa= NULL;
271         sa= scr->areabase.first;
272         while(sa) {
273                 if(BLI_in_rcti(&sa->totrct, x, y)) break;
274                 sa= sa->next;
275         }
276         
277         return sa;
278 }
279
280
281 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
282 {
283         AZone *az= NULL;
284         int i= 0;
285         
286         for(az= sa->actionzones.first, i= 0; az; az= az->next, i++) {
287                 if(az->type == AZONE_TRI) {
288                         if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y)) 
289                                 break;
290                 }
291                 if(az->type == AZONE_QUAD) {
292                         if(az->x1 < x && x < az->x2 && az->y1 < y && y < az->y2) 
293                                 break;
294                 }
295         }
296         
297         return az;
298 }
299
300 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
301 {
302         AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
303         sActionzoneData *sad;
304         
305         /* quick escape */
306         if(az==NULL)
307                 return OPERATOR_PASS_THROUGH;
308         
309         /* ok we do the actionzone */
310         sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
311         sad->sa1= CTX_wm_area(C);
312         sad->az= az;
313         sad->x= event->x; sad->y= event->y;
314         
315         /* add modal handler */
316         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
317         
318         return OPERATOR_RUNNING_MODAL;
319 }
320
321 static void actionzone_exit(bContext *C, wmOperator *op)
322 {
323         if(op->customdata)
324                 MEM_freeN(op->customdata);
325         op->customdata= NULL;
326 }
327
328 /* send EVT_ACTIONZONE event */
329 static void actionzone_apply(bContext *C, wmOperator *op)
330 {
331         wmEvent event;
332         wmWindow *win= CTX_wm_window(C);
333         
334         event= *(win->eventstate);      /* XXX huh huh? make api call */
335         event.type= EVT_ACTIONZONE;
336         event.customdata= op->customdata;
337         event.customdatafree= TRUE;
338         op->customdata= NULL;
339         
340         wm_event_add(win, &event);
341 }
342
343 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
344 {
345         sActionzoneData *sad= op->customdata;
346         int deltax, deltay;
347         
348         switch(event->type) {
349                 case MOUSEMOVE:
350                         /* calculate gesture direction */
351                         deltax= (event->x - sad->x);
352                         deltay= (event->y - sad->y);
353                         
354                         if(deltay > ABS(deltax))
355                                 sad->gesture_dir= AZONE_N;
356                         else if(deltax > ABS(deltay))
357                                 sad->gesture_dir= AZONE_E;
358                         else if(deltay < -ABS(deltax))
359                                 sad->gesture_dir= AZONE_S;
360                         else
361                                 sad->gesture_dir= AZONE_W;
362                         
363                         /* gesture is large enough? */
364                         if(ABS(deltax) > 12 || ABS(deltay) > 12) {
365                                 
366                                 /* second area, for join */
367                                 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
368                                 /* apply sends event */
369                                 actionzone_apply(C, op);
370                                 actionzone_exit(C, op);
371                                 
372                                 return OPERATOR_FINISHED;
373                         }
374                                 break;
375                 case ESCKEY:
376                 case LEFTMOUSE:
377                         actionzone_exit(C, op);
378                         return OPERATOR_CANCELLED;
379         }
380         
381         return OPERATOR_RUNNING_MODAL;
382 }
383
384 void SCREEN_OT_actionzone(wmOperatorType *ot)
385 {
386         /* identifiers */
387         ot->name= "Handle area action zones";
388         ot->idname= "SCREEN_OT_actionzone";
389         
390         ot->invoke= actionzone_invoke;
391         ot->modal= actionzone_modal;
392         
393         ot->poll= ED_operator_areaactive;
394 }
395
396
397 /* *********** Rip area operator ****************** */
398
399
400 /* operator callback */
401 /* (ton) removed attempt to merge ripped area with another, don't think this is desired functionality.
402 conventions: 'atomic' and 'dont think for user' :) */
403 static int screen_area_rip_op(bContext *C, wmOperator *op)
404 {
405         wmWindow *newwin, *win;
406         bScreen *newsc, *sc;
407         ScrArea *sa;
408         rcti rect;
409         
410         win= CTX_wm_window(C);
411         sc= CTX_wm_screen(C);
412         sa= CTX_wm_area(C);
413
414         /*  poll() checks area context, but we don't accept full-area windows */
415         if(sc->full != SCREENNORMAL) 
416                 return OPERATOR_CANCELLED;
417         
418         /* adds window to WM */
419         rect= sa->totrct;
420         BLI_translate_rcti(&rect, win->posx, win->posy);
421         newwin= WM_window_open(C, &rect);
422         
423         /* allocs new screen and adds to newly created window, using window size */
424         newsc= screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
425         newwin->screen= newsc;
426         
427         /* copy area to new screen */
428         area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
429         
430         /* screen, areas init */
431         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
432         
433         return OPERATOR_FINISHED;
434 }
435
436 void SCREEN_OT_area_rip(wmOperatorType *ot)
437 {
438         ot->name= "Rip Area into New Window";
439         ot->idname= "SCREEN_OT_area_rip";
440         
441         ot->invoke= WM_operator_confirm;
442         ot->exec= screen_area_rip_op;
443         ot->poll= ED_operator_areaactive;
444 }
445
446
447 /* ************** move area edge operator *********************************** */
448
449 /* operator state vars used:  
450            x, y                         mouse coord near edge
451            delta            movement of edge
452
453         functions:
454
455         init()   set default property values, find edge based on mouse coords, test
456             if the edge can be moved, select edges, calculate min and max movement
457
458         apply() apply delta on selection
459
460         exit()  cleanup, send notifier
461
462         cancel() cancel moving
463
464         callbacks:
465
466         exec()   execute without any user interaction, based on properties
467             call init(), apply(), exit()
468
469         invoke() gets called on mouse click near edge
470             call init(), add handler
471
472         modal()  accept modal events while doing it
473                         call apply() with delta motion
474             call exit() and remove handler
475
476 */
477
478 typedef struct sAreaMoveData {
479         int bigger, smaller, origval;
480         char dir;
481 } sAreaMoveData;
482
483 /* helper call to move area-edge, sets limits */
484 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
485 {
486         ScrArea *sa;
487         
488         /* we check all areas and test for free space with MINSIZE */
489         *bigger= *smaller= 100000;
490         
491         for(sa= sc->areabase.first; sa; sa= sa->next) {
492                 if(dir=='h') {
493                         int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
494                         
495                         /* if top or down edge selected, test height */
496                         if(sa->v1->flag && sa->v4->flag)
497                                 *bigger= MIN2(*bigger, y1);
498                         else if(sa->v2->flag && sa->v3->flag)
499                                 *smaller= MIN2(*smaller, y1);
500                 }
501                 else {
502                         int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
503                         
504                         /* if left or right edge selected, test width */
505                         if(sa->v1->flag && sa->v2->flag)
506                                 *bigger= MIN2(*bigger, x1);
507                         else if(sa->v3->flag && sa->v4->flag)
508                                 *smaller= MIN2(*smaller, x1);
509                 }
510         }
511 }
512
513 /* validate selection inside screen, set variables OK */
514 /* return 0: init failed */
515 static int area_move_init (bContext *C, wmOperator *op)
516 {
517         bScreen *sc= CTX_wm_screen(C);
518         ScrEdge *actedge;
519         sAreaMoveData *md;
520         int x, y;
521
522         /* required properties */
523         x= RNA_int_get(op->ptr, "x");
524         y= RNA_int_get(op->ptr, "y");
525
526         /* setup */
527         actedge= screen_find_active_scredge(sc, x, y);
528         if(actedge==NULL) return 0;
529
530         md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
531         op->customdata= md;
532
533         md->dir= scredge_is_horizontal(actedge)?'h':'v';
534         if(md->dir=='h') md->origval= actedge->v1->vec.y;
535         else md->origval= actedge->v1->vec.x;
536         
537         select_connected_scredge(sc, actedge);
538         /* now all vertices with 'flag==1' are the ones that can be moved. */
539
540         area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
541         
542         return 1;
543 }
544
545 /* moves selected screen edge amount of delta, used by split & move */
546 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
547 {
548         wmWindow *win= CTX_wm_window(C);
549         bScreen *sc= CTX_wm_screen(C);
550         ScrVert *v1;
551         
552         delta= CLAMPIS(delta, -smaller, bigger);
553         
554         for (v1= sc->vertbase.first; v1; v1= v1->next) {
555                 if (v1->flag) {
556                         /* that way a nice AREAGRID  */
557                         if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
558                                 v1->vec.x= origval + delta;
559                                 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
560                         }
561                         if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
562                                 v1->vec.y= origval + delta;
563
564                                 v1->vec.y+= AREAGRID-1;
565                                 v1->vec.y-= (v1->vec.y % AREAGRID);
566                                 
567                                 /* prevent too small top header */
568                                 if(v1->vec.y > win->sizey-AREAMINY)
569                                         v1->vec.y= win->sizey-AREAMINY;
570                         }
571                 }
572         }
573
574         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
575 }
576
577 static void area_move_apply(bContext *C, wmOperator *op)
578 {
579         sAreaMoveData *md= op->customdata;
580         int delta;
581         
582         delta= RNA_int_get(op->ptr, "delta");
583         area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
584 }
585
586 static void area_move_exit(bContext *C, wmOperator *op)
587 {
588         if(op->customdata)
589                 MEM_freeN(op->customdata);
590         op->customdata= NULL;
591         
592         /* this makes sure aligned edges will result in aligned grabbing */
593         removedouble_scrverts(CTX_wm_screen(C));
594         removedouble_scredges(CTX_wm_screen(C));
595 }
596
597 static int area_move_exec(bContext *C, wmOperator *op)
598 {
599         if(!area_move_init(C, op))
600                 return OPERATOR_CANCELLED;
601         
602         area_move_apply(C, op);
603         area_move_exit(C, op);
604         
605         return OPERATOR_FINISHED;
606 }
607
608 /* interaction callback */
609 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
610 {
611         RNA_int_set(op->ptr, "x", event->x);
612         RNA_int_set(op->ptr, "y", event->y);
613
614         if(!area_move_init(C, op)) 
615                 return OPERATOR_PASS_THROUGH;
616         
617         /* add temp handler */
618         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
619         
620         return OPERATOR_RUNNING_MODAL;
621 }
622
623 static int area_move_cancel(bContext *C, wmOperator *op)
624 {
625
626         RNA_int_set(op->ptr, "delta", 0);
627         area_move_apply(C, op);
628         area_move_exit(C, op);
629
630         return OPERATOR_CANCELLED;
631 }
632
633 /* modal callback for while moving edges */
634 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
635 {
636         sAreaMoveData *md;
637         int delta, x, y;
638
639         md= op->customdata;
640
641         x= RNA_int_get(op->ptr, "x");
642         y= RNA_int_get(op->ptr, "y");
643
644         /* execute the events */
645         switch(event->type) {
646                 case MOUSEMOVE:
647                         delta= (md->dir == 'v')? event->x - x: event->y - y;
648                         RNA_int_set(op->ptr, "delta", delta);
649
650                         area_move_apply(C, op);
651                         break;
652                         
653                 case LEFTMOUSE:
654                         if(event->val==0) {
655                                 area_move_exit(C, op);
656                                 return OPERATOR_FINISHED;
657                         }
658                         break;
659                         
660                 case ESCKEY:
661                         return area_move_cancel(C, op);
662         }
663         
664         return OPERATOR_RUNNING_MODAL;
665 }
666
667 void SCREEN_OT_area_move(wmOperatorType *ot)
668 {
669         /* identifiers */
670         ot->name= "Move area edges";
671         ot->idname= "SCREEN_OT_area_move";
672
673         ot->exec= area_move_exec;
674         ot->invoke= area_move_invoke;
675         ot->cancel= area_move_cancel;
676         ot->modal= area_move_modal;
677
678         ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
679
680         /* rna */
681         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
682         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
683         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
684 }
685
686 /* ************** split area operator *********************************** */
687
688 /* 
689 operator state vars:  
690         fac              spit point
691         dir              direction 'v' or 'h'
692
693 operator customdata:
694         area                    pointer to (active) area
695         x, y                    last used mouse pos
696         (more, see below)
697
698 functions:
699
700         init()   set default property values, find area based on context
701
702         apply() split area based on state vars
703
704         exit()  cleanup, send notifier
705
706         cancel() remove duplicated area
707
708 callbacks:
709
710         exec()   execute without any user interaction, based on state vars
711             call init(), apply(), exit()
712
713         invoke() gets called on mouse click in action-widget
714             call init(), add modal handler
715                         call apply() with initial motion
716
717         modal()  accept modal events while doing it
718             call move-areas code with delta motion
719             call exit() or cancel() and remove handler
720
721 */
722
723 #define SPLIT_STARTED   1
724 #define SPLIT_PROGRESS  2
725
726 typedef struct sAreaSplitData
727 {
728         int x, y;       /* last used mouse position */
729         
730         int origval;                    /* for move areas */
731         int bigger, smaller;    /* constraints for moving new edge */
732         int delta;                              /* delta move edge */
733         int origmin, origsize;  /* to calculate fac, for property storage */
734
735         ScrEdge *nedge;                 /* new edge */
736         ScrArea *sarea;                 /* start area */
737         ScrArea *narea;                 /* new area */
738 } sAreaSplitData;
739
740 /* generic init, no UI stuff here */
741 static int area_split_init(bContext *C, wmOperator *op)
742 {
743         ScrArea *sa= CTX_wm_area(C);
744         sAreaSplitData *sd;
745         int dir;
746         
747         /* required context */
748         if(sa==NULL) return 0;
749         
750         /* required properties */
751         dir= RNA_enum_get(op->ptr, "direction");
752         
753         /* minimal size */
754         if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
755         if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
756            
757         /* custom data */
758         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
759         op->customdata= sd;
760         
761         sd->sarea= sa;
762         sd->origsize= dir=='v' ? sa->winx:sa->winy;
763         sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
764         
765         return 1;
766 }
767
768 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
769 /* used with split operator */
770 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
771 {
772         ScrVert *sav1= sa->v1;
773         ScrVert *sav2= sa->v2;
774         ScrVert *sav3= sa->v3;
775         ScrVert *sav4= sa->v4;
776         ScrVert *sbv1= sb->v1;
777         ScrVert *sbv2= sb->v2;
778         ScrVert *sbv3= sb->v3;
779         ScrVert *sbv4= sb->v4;
780         
781         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
782                 return screen_findedge(screen, sav1, sav2);
783         }
784         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
785                 return screen_findedge(screen, sav2, sav3);
786         }
787         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
788                 return screen_findedge(screen, sav3, sav4);
789         }
790         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
791                 return screen_findedge(screen, sav1, sav4);
792         }
793
794         return NULL;
795 }
796
797
798 /* do the split, return success */
799 static int area_split_apply(bContext *C, wmOperator *op)
800 {
801         bScreen *sc= CTX_wm_screen(C);
802         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
803         float fac;
804         int dir;
805         
806         fac= RNA_float_get(op->ptr, "factor");
807         dir= RNA_enum_get(op->ptr, "direction");
808
809         sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
810         
811         if(sd->narea) {
812                 ScrVert *sv;
813                 
814                 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
815         
816                 /* select newly created edge, prepare for moving edge */
817                 for(sv= sc->vertbase.first; sv; sv= sv->next)
818                         sv->flag = 0;
819                 
820                 sd->nedge->v1->flag= 1;
821                 sd->nedge->v2->flag= 1;
822
823                 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
824                 else sd->origval= sd->nedge->v1->vec.x;
825
826                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
827                 
828                 return 1;
829         }               
830         
831         return 0;
832 }
833
834 static void area_split_exit(bContext *C, wmOperator *op)
835 {
836         if (op->customdata) {
837                 MEM_freeN(op->customdata);
838                 op->customdata = NULL;
839         }
840         
841         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
842
843         /* this makes sure aligned edges will result in aligned grabbing */
844         removedouble_scrverts(CTX_wm_screen(C));
845         removedouble_scredges(CTX_wm_screen(C));
846 }
847
848
849 /* UI callback, adds new handler */
850 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
851 {
852         sAreaSplitData *sd;
853         
854         if(event->type==EVT_ACTIONZONE) {
855                 sActionzoneData *sad= event->customdata;
856                 int dir;
857                 
858                 /* verify *sad itself */
859                 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
860                         return OPERATOR_PASS_THROUGH;
861                 
862                 /* is this our *sad? if areas not equal it should be passed on */
863                 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
864                         return OPERATOR_PASS_THROUGH;
865                 
866                 /* prepare operator state vars */
867                 if(sad->gesture_dir==AZONE_N || sad->gesture_dir==AZONE_S) {
868                         dir= 'h';
869                         RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
870                 }
871                 else {
872                         dir= 'v';
873                         RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
874                 }
875                 RNA_enum_set(op->ptr, "direction", dir);
876
877                 /* general init, also non-UI case, adds customdata, sets area and defaults */
878                 if(!area_split_init(C, op))
879                         return OPERATOR_PASS_THROUGH;
880                 
881                 sd= (sAreaSplitData *)op->customdata;
882                 
883                 sd->x= event->x;
884                 sd->y= event->y;
885                 
886                 /* do the split */
887                 if(area_split_apply(C, op)) {
888                         area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
889                         
890                         /* add temp handler for edge move or cancel */
891                         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
892                         
893                         return OPERATOR_RUNNING_MODAL;
894                 }
895                 
896         }
897         else {
898                 /* nonmodal for now */
899                 return op->type->exec(C, op);
900         }
901         
902         return OPERATOR_PASS_THROUGH;
903 }
904
905 /* function to be called outside UI context, or for redo */
906 static int area_split_exec(bContext *C, wmOperator *op)
907 {
908         
909         if(!area_split_init(C, op))
910                 return OPERATOR_CANCELLED;
911         
912         area_split_apply(C, op);
913         area_split_exit(C, op);
914         
915         return OPERATOR_FINISHED;
916 }
917
918
919 static int area_split_cancel(bContext *C, wmOperator *op)
920 {
921         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
922
923         if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
924                 if (CTX_wm_area(C) == sd->narea) {
925                         CTX_wm_area_set(C, NULL);
926                         CTX_wm_region_set(C, NULL);
927                 }
928                 sd->narea = NULL;
929         }
930         area_split_exit(C, op);
931
932         return OPERATOR_CANCELLED;
933 }
934
935 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
936 {
937         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
938         float fac;
939         int dir;
940
941         /* execute the events */
942         switch(event->type) {
943                 case MOUSEMOVE:
944                         dir= RNA_enum_get(op->ptr, "direction");
945                         
946                         sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
947                         area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
948                         
949                         fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
950                         RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
951                         
952                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
953                         break;
954                         
955                 case LEFTMOUSE:
956                         if(event->val==0) { /* mouse up */
957                                 area_split_exit(C, op);
958                                 return OPERATOR_FINISHED;
959                         }
960                         break;
961                 case RIGHTMOUSE: /* cancel operation */
962                 case ESCKEY:
963                         return area_split_cancel(C, op);
964         }
965         
966         return OPERATOR_RUNNING_MODAL;
967 }
968
969 static EnumPropertyItem prop_direction_items[] = {
970         {'h', "HORIZONTAL", "Horizontal", ""},
971         {'v', "VERTICAL", "Vertical", ""},
972         {0, NULL, NULL, NULL}};
973
974 void SCREEN_OT_area_split(wmOperatorType *ot)
975 {
976         ot->name = "Split area";
977         ot->idname = "SCREEN_OT_area_split";
978         
979         ot->exec= area_split_exec;
980         ot->invoke= area_split_invoke;
981         ot->modal= area_split_modal;
982         
983         ot->poll= ED_operator_areaactive;
984         ot->flag= OPTYPE_REGISTER;
985         
986         /* rna */
987         RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
988         RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
989 }
990
991 /* ************** frame change operator ***************************** */
992
993
994 /* function to be called outside UI context, or for redo */
995 static int frame_offset_exec(bContext *C, wmOperator *op)
996 {
997         int delta;
998
999         delta = RNA_int_get(op->ptr, "delta");
1000
1001         CTX_data_scene(C)->r.cfra += delta;
1002         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1003
1004         return OPERATOR_FINISHED;
1005 }
1006
1007 void SCREEN_OT_frame_offset(wmOperatorType *ot)
1008 {
1009         ot->name = "Frame Offset";
1010         ot->idname = "SCREEN_OT_frame_offset";
1011
1012         ot->exec= frame_offset_exec;
1013
1014         ot->poll= ED_operator_screenactive;
1015         ot->flag= OPTYPE_REGISTER;
1016
1017         /* rna */
1018         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1019 }
1020
1021 /* ************** switch screen operator ***************************** */
1022
1023
1024 /* function to be called outside UI context, or for redo */
1025 static int screen_set_exec(bContext *C, wmOperator *op)
1026 {
1027         bScreen *screen= CTX_wm_screen(C);
1028         int tot= BLI_countlist(&CTX_data_main(C)->screen);
1029         int delta= RNA_int_get(op->ptr, "delta");
1030         
1031         /* this screen is 'fake', solve later XXX */
1032         if(CTX_wm_area(C)->full)
1033                 return OPERATOR_CANCELLED;
1034         
1035         if(delta==1) {
1036                 while(tot--) {
1037                         screen= screen->id.next;
1038                         if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1039                         if(screen->winid==0 && screen->full==0)
1040                                 break;
1041                 }
1042         }
1043         else if(delta== -1) {
1044                 while(tot--) {
1045                         screen= screen->id.prev;
1046                         if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1047                         if(screen->winid==0 && screen->full==0)
1048                                 break;
1049                 }
1050         }
1051         else {
1052                 screen= NULL;
1053         }
1054         
1055         if(screen) {
1056                 ED_screen_set(C, screen);
1057                 return OPERATOR_FINISHED;
1058         }
1059         return OPERATOR_CANCELLED;
1060 }
1061
1062 void SCREEN_OT_screen_set(wmOperatorType *ot)
1063 {
1064         ot->name = "Set Screen";
1065         ot->idname = "SCREEN_OT_screen_set";
1066         
1067         ot->exec= screen_set_exec;
1068         ot->poll= ED_operator_screenactive;
1069         
1070         /* rna */
1071         RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1072         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1073 }
1074
1075 /* ************** screen full-area operator ***************************** */
1076
1077
1078 /* function to be called outside UI context, or for redo */
1079 static int screen_full_area_exec(bContext *C, wmOperator *op)
1080 {
1081         ed_screen_fullarea(C, CTX_wm_area(C));
1082         return OPERATOR_FINISHED;
1083 }
1084
1085 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1086 {
1087         ot->name = "Toggle Make Area Fullscreen";
1088         ot->idname = "SCREEN_OT_screen_full_area";
1089         
1090         ot->exec= screen_full_area_exec;
1091         ot->poll= ED_operator_screenactive;
1092         ot->flag= OPTYPE_REGISTER;
1093
1094 }
1095
1096
1097
1098 /* ************** join area operator ********************************************** */
1099
1100 /* operator state vars used:  
1101                         x1, y1     mouse coord in first area, which will disappear
1102                         x2, y2     mouse coord in 2nd area, which will become joined
1103
1104 functions:
1105
1106    init()   find edge based on state vars 
1107                         test if the edge divides two areas, 
1108                         store active and nonactive area,
1109             
1110    apply()  do the actual join
1111
1112    exit()       cleanup, send notifier
1113
1114 callbacks:
1115
1116    exec()       calls init, apply, exit 
1117    
1118    invoke() sets mouse coords in x,y
1119             call init()
1120             add modal handler
1121
1122    modal()      accept modal events while doing it
1123                         call apply() with active window and nonactive window
1124             call exit() and remove handler when LMB confirm
1125
1126 */
1127
1128 typedef struct sAreaJoinData
1129 {
1130         ScrArea *sa1;   /* first area to be considered */
1131         ScrArea *sa2;   /* second area to be considered */
1132         ScrArea *scr;   /* designed for removal */
1133
1134 } sAreaJoinData;
1135
1136
1137 /* validate selection inside screen, set variables OK */
1138 /* return 0: init failed */
1139 /* XXX todo: find edge based on (x,y) and set other area? */
1140 static int area_join_init(bContext *C, wmOperator *op)
1141 {
1142         ScrArea *sa1, *sa2;
1143         sAreaJoinData* jd= NULL;
1144         int x1, y1;
1145         int x2, y2;
1146
1147         /* required properties, make negative to get return 0 if not set by caller */
1148         x1= RNA_int_get(op->ptr, "x1");
1149         y1= RNA_int_get(op->ptr, "y1");
1150         x2= RNA_int_get(op->ptr, "x2");
1151         y2= RNA_int_get(op->ptr, "y2");
1152         
1153         sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1154         sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1155         if(sa1==NULL || sa2==NULL || sa1==sa2)
1156                 return 0;
1157
1158         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1159                 
1160         jd->sa1 = sa1;
1161         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1162         jd->sa2 = sa2;
1163         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1164         
1165         op->customdata= jd;
1166         
1167         return 1;
1168 }
1169
1170 /* apply the join of the areas (space types) */
1171 static int area_join_apply(bContext *C, wmOperator *op)
1172 {
1173         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1174         if (!jd) return 0;
1175
1176         if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1177                 return 0;
1178         }
1179         if (CTX_wm_area(C) == jd->sa2) {
1180                 CTX_wm_area_set(C, NULL);
1181                 CTX_wm_region_set(C, NULL);
1182         }
1183
1184         return 1;
1185 }
1186
1187 /* finish operation */
1188 static void area_join_exit(bContext *C, wmOperator *op)
1189 {
1190         if (op->customdata) {
1191                 MEM_freeN(op->customdata);
1192                 op->customdata = NULL;
1193         }
1194
1195         /* this makes sure aligned edges will result in aligned grabbing */
1196         removedouble_scredges(CTX_wm_screen(C));
1197         removenotused_scredges(CTX_wm_screen(C));
1198         removenotused_scrverts(CTX_wm_screen(C));
1199 }
1200
1201 static int area_join_exec(bContext *C, wmOperator *op)
1202 {
1203         if(!area_join_init(C, op)) 
1204                 return OPERATOR_CANCELLED;
1205         
1206         area_join_apply(C, op);
1207         area_join_exit(C, op);
1208
1209         return OPERATOR_FINISHED;
1210 }
1211
1212 /* interaction callback */
1213 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1214 {
1215
1216         if(event->type==EVT_ACTIONZONE) {
1217                 sActionzoneData *sad= event->customdata;
1218                 
1219                 /* verify *sad itself */
1220                 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1221                         return OPERATOR_PASS_THROUGH;
1222                 
1223                 /* is this our *sad? if areas equal it should be passed on */
1224                 if(sad->sa1==sad->sa2)
1225                         return OPERATOR_PASS_THROUGH;
1226                 
1227                 /* prepare operator state vars */
1228                 RNA_int_set(op->ptr, "x1", sad->x);
1229                 RNA_int_set(op->ptr, "y1", sad->y);
1230                 RNA_int_set(op->ptr, "x2", event->x);
1231                 RNA_int_set(op->ptr, "y2", event->y);
1232
1233                 if(!area_join_init(C, op)) 
1234                         return OPERATOR_PASS_THROUGH;
1235         
1236                 /* add temp handler */
1237                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1238         
1239                 return OPERATOR_RUNNING_MODAL;
1240         }
1241         
1242         return OPERATOR_PASS_THROUGH;
1243 }
1244
1245 static int area_join_cancel(bContext *C, wmOperator *op)
1246 {
1247         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1248
1249         if (jd->sa1) {
1250                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1251                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1252         }
1253         if (jd->sa2) {
1254                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1255                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1256         }
1257
1258         WM_event_add_notifier(C, NC_WINDOW, NULL);
1259         
1260         area_join_exit(C, op);
1261
1262         return OPERATOR_CANCELLED;
1263 }
1264
1265 /* modal callback while selecting area (space) that will be removed */
1266 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1267 {
1268         bScreen *sc= CTX_wm_screen(C);
1269         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1270         
1271         /* execute the events */
1272         switch(event->type) {
1273                         
1274                 case MOUSEMOVE: 
1275                         {
1276                                 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1277                                 int dir;
1278                                 
1279                                 if (sa) {                                       
1280                                         if (jd->sa1 != sa) {
1281                                                 dir = area_getorientation(sc, jd->sa1, sa);
1282                                                 if (dir >= 0) {
1283                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1284                                                         jd->sa2 = sa;
1285                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1286                                                 } 
1287                                                 else {
1288                                                         /* we are not bordering on the previously selected area 
1289                                                            we check if area has common border with the one marked for removal
1290                                                            in this case we can swap areas.
1291                                                         */
1292                                                         dir = area_getorientation(sc, sa, jd->sa2);
1293                                                         if (dir >= 0) {
1294                                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1295                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1296                                                                 jd->sa1 = jd->sa2;
1297                                                                 jd->sa2 = sa;
1298                                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1299                                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1300                                                         } 
1301                                                         else {
1302                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1303                                                                 jd->sa2 = NULL;
1304                                                         }
1305                                                 }
1306                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1307                                         } 
1308                                         else {
1309                                                 /* we are back in the area previously selected for keeping 
1310                                                  * we swap the areas if possible to allow user to choose */
1311                                                 if (jd->sa2 != NULL) {
1312                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1313                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1314                                                         jd->sa1 = jd->sa2;
1315                                                         jd->sa2 = sa;
1316                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1317                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1318                                                         dir = area_getorientation(sc, jd->sa1, jd->sa2);
1319                                                         if (dir < 0) {
1320                                                                 printf("oops, didn't expect that!\n");
1321                                                         }
1322                                                 } 
1323                                                 else {
1324                                                         dir = area_getorientation(sc, jd->sa1, sa);
1325                                                         if (dir >= 0) {
1326                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1327                                                                 jd->sa2 = sa;
1328                                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1329                                                         }
1330                                                 }
1331                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1332                                         }
1333                                 }
1334                         }
1335                         break;
1336                 case LEFTMOUSE:
1337                         if(event->val==0) {
1338                                 area_join_apply(C, op);
1339                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1340                                 area_join_exit(C, op);
1341                                 return OPERATOR_FINISHED;
1342                         }
1343                         break;
1344                         
1345                 case ESCKEY:
1346                         return area_join_cancel(C, op);
1347         }
1348
1349         return OPERATOR_RUNNING_MODAL;
1350 }
1351
1352 /* Operator for joining two areas (space types) */
1353 void SCREEN_OT_area_join(wmOperatorType *ot)
1354 {
1355         /* identifiers */
1356         ot->name= "Join area";
1357         ot->idname= "SCREEN_OT_area_join";
1358         
1359         /* api callbacks */
1360         ot->exec= area_join_exec;
1361         ot->invoke= area_join_invoke;
1362         ot->modal= area_join_modal;
1363
1364         ot->poll= ED_operator_screenactive;
1365
1366         /* rna */
1367         RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1368         RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1369         RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1370         RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1371 }
1372
1373 /* ************** repeat last operator ***************************** */
1374
1375 static int repeat_last_exec(bContext *C, wmOperator *op)
1376 {
1377         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1378         
1379         if(lastop)
1380                 WM_operator_repeat(C, lastop);
1381         
1382         return OPERATOR_CANCELLED;
1383 }
1384
1385 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1386 {
1387         /* identifiers */
1388         ot->name= "Repeat Last";
1389         ot->idname= "SCREEN_OT_repeat_last";
1390         
1391         /* api callbacks */
1392         ot->exec= repeat_last_exec;
1393         
1394         ot->poll= ED_operator_screenactive;
1395         
1396 }
1397
1398 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1399 {
1400         wmWindowManager *wm= CTX_wm_manager(C);
1401         wmOperator *lastop;
1402         uiMenuItem *head;
1403         int items, i;
1404         
1405         items= BLI_countlist(&wm->operators);
1406         if(items==0)
1407                 return OPERATOR_CANCELLED;
1408         
1409         head= uiPupMenuBegin(op->type->name, 0);
1410
1411         for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1412                 uiMenuItemIntO(head, lastop->type->name, 0, op->type->idname, "index", i);
1413
1414         uiPupMenuEnd(C, head);
1415         
1416         return OPERATOR_CANCELLED;
1417 }
1418
1419 static int repeat_history_exec(bContext *C, wmOperator *op)
1420 {
1421         wmWindowManager *wm= CTX_wm_manager(C);
1422         
1423         op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1424         if(op) {
1425                 /* let's put it as last operator in list */
1426                 BLI_remlink(&wm->operators, op);
1427                 BLI_addtail(&wm->operators, op);
1428                 
1429                 WM_operator_repeat(C, op);
1430         }
1431                                          
1432         return OPERATOR_FINISHED;
1433 }
1434
1435 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1436 {
1437         /* identifiers */
1438         ot->name= "Repeat History";
1439         ot->idname= "SCREEN_OT_repeat_history";
1440         
1441         /* api callbacks */
1442         ot->invoke= repeat_history_invoke;
1443         ot->exec= repeat_history_exec;
1444         
1445         ot->poll= ED_operator_screenactive;
1446         
1447         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1448 }
1449
1450 /* ********************** redo operator ***************************** */
1451
1452 static int redo_last_exec(bContext *C, wmOperator *op)
1453 {
1454 #if 0
1455         /* XXX context is not correct after popup menu */
1456         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1457         
1458         if(lastop) {
1459                 ED_undo_pop(C);
1460                 WM_operator_repeat(C, lastop);
1461         }
1462 #endif
1463         
1464         return OPERATOR_CANCELLED;
1465 }
1466
1467 static void redo_last_cb(bContext *C, void *arg1, void *arg2)
1468 {
1469         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1470         
1471         if(lastop) {
1472                 ED_undo_pop(C);
1473                 WM_operator_repeat(C, lastop);
1474         }
1475         
1476 }
1477
1478 static uiBlock *ui_block_create_redo_last(bContext *C, ARegion *ar, void *arg_op)
1479 {
1480         wmWindowManager *wm= CTX_wm_manager(C);
1481         wmOperator *op= arg_op;
1482         PointerRNA ptr;
1483         uiBlock *block;
1484         int height;
1485         
1486         block= uiBeginBlock(C, ar, "redo_last_popup", UI_EMBOSS, UI_HELV);
1487         uiBlockSetFlag(block, UI_BLOCK_KEEP_OPEN|UI_BLOCK_RET_1);
1488         uiBlockSetFunc(block, redo_last_cb, NULL, NULL);
1489
1490         if(!op->properties) {
1491                 IDPropertyTemplate val = {0};
1492                 op->properties= IDP_New(IDP_GROUP, val, "wmOperatorProperties");
1493         }
1494
1495         RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr);
1496         height= uiDefAutoButsRNA(block, &ptr);
1497
1498         uiPopupBoundsBlock(block, 4.0f, 0, 0);
1499         uiEndBlock(C, block);
1500
1501         return block;
1502 }
1503
1504 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
1505 {
1506         wmWindowManager *wm= CTX_wm_manager(C);
1507         wmOperator *lastop= wm->operators.last;
1508
1509         if(!lastop)
1510                 return OPERATOR_CANCELLED;
1511
1512         /* only for operators that are registered and did an undo push */
1513         if(!(lastop->type->flag & OPTYPE_REGISTER) || !(lastop->type->flag & OPTYPE_UNDO))
1514                 return OPERATOR_CANCELLED;
1515
1516         uiPupBlockO(C, ui_block_create_redo_last, lastop, op->type->idname, WM_OP_EXEC_DEFAULT);
1517
1518         return OPERATOR_CANCELLED;
1519 }
1520
1521 void SCREEN_OT_redo_last(wmOperatorType *ot)
1522 {
1523         /* identifiers */
1524         ot->name= "Redo Last";
1525         ot->idname= "SCREEN_OT_redo_last";
1526         
1527         /* api callbacks */
1528         ot->invoke= redo_last_invoke;
1529         ot->exec= redo_last_exec;
1530         
1531         ot->poll= ED_operator_screenactive;
1532 }
1533
1534 /* ************** region split operator ***************************** */
1535
1536 /* insert a region in the area region list */
1537 static int region_split_exec(bContext *C, wmOperator *op)
1538 {
1539         ARegion *ar= CTX_wm_region(C);
1540         
1541         if(ar->regiontype==RGN_TYPE_HEADER)
1542                 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1543         else if(ar->alignment==RGN_ALIGN_QSPLIT)
1544                 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1545         else {
1546                 ScrArea *sa= CTX_wm_area(C);
1547                 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1548                 int dir= RNA_enum_get(op->ptr, "type");
1549         
1550                 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1551                 
1552                 newar->alignment= ar->alignment;
1553                 
1554                 if(dir=='h')
1555                         ar->alignment= RGN_ALIGN_HSPLIT;
1556                 else
1557                         ar->alignment= RGN_ALIGN_VSPLIT;
1558                 
1559                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1560         }
1561         
1562         return OPERATOR_FINISHED;
1563 }
1564
1565 void SCREEN_OT_region_split(wmOperatorType *ot)
1566 {
1567         /* identifiers */
1568         ot->name= "Split Region";
1569         ot->idname= "SCREEN_OT_region_split";
1570         
1571         /* api callbacks */
1572         ot->invoke= WM_menu_invoke;
1573         ot->exec= region_split_exec;
1574         ot->poll= ED_operator_areaactive;
1575         
1576         RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
1577 }
1578
1579 /* ************** region four-split operator ***************************** */
1580
1581 /* insert a region in the area region list */
1582 static int region_foursplit_exec(bContext *C, wmOperator *op)
1583 {
1584         ARegion *ar= CTX_wm_region(C);
1585         
1586         /* some rules... */
1587         if(ar->regiontype!=RGN_TYPE_WINDOW)
1588                 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
1589         else if(ar->alignment==RGN_ALIGN_QSPLIT) {
1590                 ScrArea *sa= CTX_wm_area(C);
1591                 ARegion *arn;
1592                 
1593                 /* keep current region */
1594                 ar->alignment= 0;
1595                 
1596                 if(sa->spacetype==SPACE_VIEW3D) {
1597                         RegionView3D *rv3d= ar->regiondata;
1598                         rv3d->viewlock= 0;
1599                 }
1600                 
1601                 for(ar= sa->regionbase.first; ar; ar= arn) {
1602                         arn= ar->next;
1603                         if(ar->alignment==RGN_ALIGN_QSPLIT) {
1604                                 ED_region_exit(C, ar);
1605                                 BKE_area_region_free(sa->type, ar);
1606                                 BLI_remlink(&sa->regionbase, ar);
1607                                 MEM_freeN(ar);
1608                         }
1609                 }
1610                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1611         }
1612         else if(ar->next)
1613                 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
1614         else {
1615                 ScrArea *sa= CTX_wm_area(C);
1616                 ARegion *newar;
1617                 int count;
1618                 
1619                 ar->alignment= RGN_ALIGN_QSPLIT;
1620                 
1621                 for(count=0; count<3; count++) {
1622                         newar= BKE_area_region_copy(sa->type, ar);
1623                         BLI_addtail(&sa->regionbase, newar);
1624                 }
1625                 
1626                 /* lock views and set them */
1627                 if(sa->spacetype==SPACE_VIEW3D) {
1628                         RegionView3D *rv3d;
1629                         
1630                         rv3d= ar->regiondata;
1631                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
1632                         
1633                         ar= ar->next;
1634                         rv3d= ar->regiondata;
1635                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
1636                         
1637                         ar= ar->next;
1638                         rv3d= ar->regiondata;
1639                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
1640                         
1641                         ar= ar->next;
1642                         rv3d= ar->regiondata;
1643                         rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
1644                 }
1645                 
1646                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1647         }
1648         
1649         
1650         return OPERATOR_FINISHED;
1651 }
1652
1653 void SCREEN_OT_region_foursplit(wmOperatorType *ot)
1654 {
1655         /* identifiers */
1656         ot->name= "Split Region in 4 Parts";
1657         ot->idname= "SCREEN_OT_region_foursplit";
1658         
1659         /* api callbacks */
1660         ot->invoke= WM_operator_confirm;
1661         ot->exec= region_foursplit_exec;
1662         ot->poll= ED_operator_areaactive;
1663         ot->flag= OPTYPE_REGISTER;
1664 }
1665
1666
1667
1668 /* ************** region flip operator ***************************** */
1669
1670 /* flip a region alignment */
1671 static int region_flip_exec(bContext *C, wmOperator *op)
1672 {
1673         ARegion *ar= CTX_wm_region(C);
1674
1675         if(ar->alignment==RGN_ALIGN_TOP)
1676                 ar->alignment= RGN_ALIGN_BOTTOM;
1677         else if(ar->alignment==RGN_ALIGN_BOTTOM)
1678                 ar->alignment= RGN_ALIGN_TOP;
1679         else if(ar->alignment==RGN_ALIGN_LEFT)
1680                 ar->alignment= RGN_ALIGN_RIGHT;
1681         else if(ar->alignment==RGN_ALIGN_RIGHT)
1682                 ar->alignment= RGN_ALIGN_LEFT;
1683         
1684         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1685         printf("executed region flip\n");
1686         
1687         return OPERATOR_FINISHED;
1688 }
1689
1690 static void testfunc(bContext *C, void *argv, int arg)
1691 {
1692         printf("arg %d\n", arg);
1693 }
1694
1695 static void newlevel1(bContext *C, uiMenuItem *head, void *arg)
1696 {
1697         uiMenuFunc(head, testfunc, NULL);
1698         
1699         uiMenuItemVal(head, "First", ICON_PROP_ON, 1);
1700         uiMenuItemVal(head, "Second", ICON_PROP_CON, 2);
1701         uiMenuItemVal(head, "Third", ICON_SMOOTHCURVE, 3);
1702         uiMenuItemVal(head, "Fourth", ICON_SHARPCURVE, 4);      
1703 }
1704
1705 static int testing123(bContext *C, wmOperator *op, wmEvent *event)
1706 {
1707         uiMenuItem *head= uiPupMenuBegin("Hello world", 0);
1708         
1709         uiMenuContext(head, WM_OP_EXEC_DEFAULT);
1710         uiMenuItemO(head, ICON_PROP_ON, "SCREEN_OT_region_flip");
1711         uiMenuItemO(head, ICON_PROP_CON, "SCREEN_OT_screen_full_area");
1712         uiMenuItemO(head, ICON_SMOOTHCURVE, "SCREEN_OT_region_foursplit");
1713         uiMenuLevel(head, "Submenu", newlevel1);
1714         uiMenuItemO(head, ICON_PROP_ON, "SCREEN_OT_area_rip");
1715         
1716         uiPupMenuEnd(C, head);
1717         
1718         /* this operator is only for a menu, not used further */
1719         return OPERATOR_CANCELLED;
1720 }
1721
1722 void SCREEN_OT_region_flip(wmOperatorType *ot)
1723 {
1724         /* identifiers */
1725         ot->name= "Flip Region";
1726         ot->idname= "SCREEN_OT_region_flip";
1727         
1728         /* api callbacks */
1729         ot->invoke= testing123; // XXX WM_operator_confirm;
1730         ot->exec= region_flip_exec;
1731         
1732         ot->poll= ED_operator_areaactive;
1733         ot->flag= OPTYPE_REGISTER;
1734         
1735         RNA_def_int(ot->srna, "test", 0, INT_MIN, INT_MAX, "test", "", INT_MIN, INT_MAX);
1736
1737 }
1738
1739 /* ****************** anim player, typically with timer ***************** */
1740
1741 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
1742 {
1743         bScreen *screen= CTX_wm_screen(C);
1744         
1745         if(screen->animtimer==event->customdata) {
1746                 Scene *scene= CTX_data_scene(C);
1747                 
1748                 scene->r.cfra++;
1749                 
1750                 if (scene->r.psfra) {
1751                         if(scene->r.cfra > scene->r.pefra)
1752                                 scene->r.cfra= scene->r.psfra;
1753                 }
1754                 else {
1755                         if(scene->r.cfra > scene->r.efra)
1756                                 scene->r.cfra= scene->r.sfra;
1757                 }
1758
1759                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1760                 
1761                 return OPERATOR_FINISHED;
1762         }
1763         return OPERATOR_PASS_THROUGH;
1764 }
1765
1766 void SCREEN_OT_animation_play(wmOperatorType *ot)
1767 {
1768         /* identifiers */
1769         ot->name= "Animation player";
1770         ot->idname= "SCREEN_OT_animation_play";
1771         
1772         /* api callbacks */
1773         ot->invoke= screen_animation_play;
1774         
1775         ot->poll= ED_operator_screenactive;
1776         
1777 }
1778
1779 /* ************** border select operator (template) ***************************** */
1780
1781 /* operator state vars used: (added by default WM callbacks)   
1782         xmin, ymin     
1783         xmax, ymax     
1784
1785         customdata: the wmGesture pointer
1786
1787 callbacks:
1788
1789         exec()  has to be filled in by user
1790
1791         invoke() default WM function
1792                          adds modal handler
1793
1794         modal() default WM function 
1795                         accept modal events while doing it, calls exec(), handles ESC and border drawing
1796         
1797         poll()  has to be filled in by user for context
1798 */
1799 #if 0
1800 static int border_select_do(bContext *C, wmOperator *op)
1801 {
1802         int event_type= RNA_int_get(op->ptr, "event_type");
1803         
1804         if(event_type==LEFTMOUSE)
1805                 printf("border select do select\n");
1806         else if(event_type==RIGHTMOUSE)
1807                 printf("border select deselect\n");
1808         else 
1809                 printf("border select do something\n");
1810         
1811         return 1;
1812 }
1813
1814 void SCREEN_OT_border_select(wmOperatorType *ot)
1815 {
1816         /* identifiers */
1817         ot->name= "Border select";
1818         ot->idname= "SCREEN_OT_border_select";
1819         
1820         /* api callbacks */
1821         ot->exec= border_select_do;
1822         ot->invoke= WM_border_select_invoke;
1823         ot->modal= WM_border_select_modal;
1824         
1825         ot->poll= ED_operator_areaactive;
1826         
1827         /* rna */
1828         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1829         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1830         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1831         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1832         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1833
1834 }
1835 #endif
1836
1837 /* ****************************** render invoking ***************** */
1838
1839 /* set callbacks, exported to sequence render too. 
1840 Only call in foreground (UI) renders. */
1841
1842 /* returns biggest area that is not uv/image editor. Note that it uses buttons */
1843 /* window as the last possible alternative.                                                                        */
1844 static ScrArea *biggest_non_image_area(bContext *C)
1845 {
1846         bScreen *sc= CTX_wm_screen(C);
1847         ScrArea *sa, *big= NULL;
1848         int size, maxsize= 0, bwmaxsize= 0;
1849         short foundwin= 0;
1850         
1851         for(sa= sc->areabase.first; sa; sa= sa->next) {
1852                 if(sa->winx > 10 && sa->winy > 10) {
1853                         size= sa->winx*sa->winy;
1854                         if(sa->spacetype == SPACE_BUTS) {
1855                                 if(foundwin == 0 && size > bwmaxsize) {
1856                                         bwmaxsize= size;
1857                                         big= sa;        
1858                                 }
1859                         }
1860                         else if(sa->spacetype != SPACE_IMAGE && size > maxsize) {
1861                                 maxsize= size;
1862                                 big= sa;
1863                                 foundwin= 1;
1864                         }
1865                 }
1866         }
1867         
1868         return big;
1869 }
1870
1871 static ScrArea *biggest_area(bContext *C)
1872 {
1873         bScreen *sc= CTX_wm_screen(C);
1874         ScrArea *sa, *big= NULL;
1875         int size, maxsize= 0;
1876         
1877         for(sa= sc->areabase.first; sa; sa= sa->next) {
1878                 size= sa->winx*sa->winy;
1879                 if(size > maxsize) {
1880                         maxsize= size;
1881                         big= sa;
1882                 }
1883         }
1884         return big;
1885 }
1886
1887
1888 static ScrArea *find_area_showing_r_result(bContext *C)
1889 {
1890         bScreen *sc= CTX_wm_screen(C);
1891         ScrArea *sa;
1892         SpaceImage *sima;
1893         
1894         /* find an imagewindow showing render result */
1895         for(sa=sc->areabase.first; sa; sa= sa->next) {
1896                 if(sa->spacetype==SPACE_IMAGE) {
1897                         sima= sa->spacedata.first;
1898                         if(sima->image && sima->image->type==IMA_TYPE_R_RESULT)
1899                                 break;
1900                 }
1901         }
1902         return sa;
1903 }
1904
1905 static void screen_set_image_output(bContext *C)
1906 {
1907         ScrArea *sa;
1908         SpaceImage *sima;
1909         
1910         sa= find_area_showing_r_result(C);
1911         
1912         if(sa==NULL) {
1913                 /* find largest open non-image area */
1914                 sa= biggest_non_image_area(C);
1915                 if(sa) {
1916                         ED_area_newspace(C, sa, SPACE_IMAGE);
1917                         sima= sa->spacedata.first;
1918                         
1919                         /* makes ESC go back to prev space */
1920                         sima->flag |= SI_PREVSPACE;
1921                 }
1922                 else {
1923                         /* use any area of decent size */
1924                         sa= biggest_area(C);
1925                         if(sa->spacetype!=SPACE_IMAGE) {
1926                                 // XXX newspace(sa, SPACE_IMAGE);
1927                                 sima= sa->spacedata.first;
1928                                 
1929                                 /* makes ESC go back to prev space */
1930                                 sima->flag |= SI_PREVSPACE;
1931                         }
1932                 }
1933         }
1934         
1935         sima= sa->spacedata.first;
1936         
1937         /* get the correct image, and scale it */
1938         sima->image= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
1939         
1940         if(G.displaymode==2) { // XXX
1941                 if(sa->full==0) {
1942                         sima->flag |= SI_FULLWINDOW;
1943                         
1944                         ed_screen_fullarea(C, sa);
1945                 }
1946         }
1947         
1948 }
1949
1950 /* executes blocking render */
1951 static int screen_render_exec(bContext *C, wmOperator *op)
1952 {
1953         Scene *scene= CTX_data_scene(C);
1954         Render *re= RE_GetRender(scene->id.name);
1955         
1956         if(re==NULL) {
1957                 re= RE_NewRender(scene->id.name);
1958         }
1959         RE_test_break_cb(re, NULL, (int (*)(void *)) blender_test_break);
1960         
1961         if(RNA_boolean_get(op->ptr, "anim"))
1962                 RE_BlenderAnim(re, scene, scene->r.sfra, scene->r.efra, scene->frame_step);
1963         else
1964                 RE_BlenderFrame(re, scene, scene->r.cfra);
1965         
1966         // no redraw needed, we leave state as we entered it
1967         ED_update_for_newframe(C, 1);
1968         
1969         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
1970
1971         return OPERATOR_FINISHED;
1972 }
1973
1974 typedef struct RenderJob {
1975         Scene *scene;
1976         Render *re;
1977         wmWindow *win;
1978         int anim;
1979         Image *image;
1980         ImageUser iuser;
1981         short *stop;
1982         short *do_update;
1983 } RenderJob;
1984
1985 static void render_freejob(void *rjv)
1986 {
1987         RenderJob *rj= rjv;
1988         
1989         MEM_freeN(rj);
1990 }
1991
1992 /* called inside thread! */
1993 static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect)
1994 {
1995         RenderJob *rj= rjv;
1996         ImBuf *ibuf;
1997         float x1, y1, *rectf= NULL;
1998         int ymin, ymax, xmin, xmax;
1999         int rymin, rxmin;
2000         char *rectc;
2001         
2002         ibuf= BKE_image_get_ibuf(rj->image, &rj->iuser);
2003         if(ibuf==NULL) return;
2004
2005         /* if renrect argument, we only refresh scanlines */
2006         if(renrect) {
2007                 /* if ymax==recty, rendering of layer is ready, we should not draw, other things happen... */
2008                 if(rr->renlay==NULL || renrect->ymax>=rr->recty)
2009                         return;
2010                 
2011                 /* xmin here is first subrect x coord, xmax defines subrect width */
2012                 xmin = renrect->xmin;
2013                 xmax = renrect->xmax - xmin;
2014                 if (xmax<2) return;
2015                 
2016                 ymin= renrect->ymin;
2017                 ymax= renrect->ymax - ymin;
2018                 if(ymax<2)
2019                         return;
2020                 renrect->ymin= renrect->ymax;
2021         }
2022         else {
2023                 xmin = ymin = rr->crop;
2024                 xmax = rr->rectx - 2*rr->crop;
2025                 ymax = rr->recty - 2*rr->crop;
2026         }
2027         
2028         /* xmin ymin is in tile coords. transform to ibuf */
2029         rxmin= rr->tilerect.xmin + xmin;
2030         if(rxmin >= ibuf->x) return;
2031         rymin= rr->tilerect.ymin + ymin;
2032         if(rymin >= ibuf->y) return;
2033         
2034         if(rxmin + xmax > ibuf->x)
2035                 xmax= ibuf->x - rxmin;
2036         if(rymin + ymax > ibuf->y)
2037                 ymax= ibuf->y - rymin;
2038         if(xmax < 1 || ymax < 1) return;
2039         
2040         /* find current float rect for display, first case is after composit... still weak */
2041         if(rr->rectf)
2042                 rectf= rr->rectf;
2043         else {
2044                 if(rr->rect32)
2045                         return;
2046                 else {
2047                         if(rr->renlay==NULL || rr->renlay->rectf==NULL) return;
2048                         rectf= rr->renlay->rectf;
2049                 }
2050         }
2051         if(rectf==NULL) return;
2052         
2053         rectf+= 4*(rr->rectx*ymin + xmin);
2054         rectc= (char *)(ibuf->rect + ibuf->x*rymin + rxmin);
2055
2056         for(y1= 0; y1<ymax; y1++) {
2057                 float *rf= rectf;
2058                 char *rc= rectc;
2059                 
2060                 for(x1= 0; x1<xmax; x1++, rf += 4, rc+=4) {
2061                         rc[0]= FTOCHAR(rf[0]);
2062                         rc[1]= FTOCHAR(rf[1]);
2063                         rc[2]= FTOCHAR(rf[2]);
2064                         rc[3]= FTOCHAR(rf[3]);
2065                 }
2066                 rectf += 4*rr->rectx;
2067                 rectc += 4*ibuf->x;
2068         }
2069         
2070         /* make jobs timer to send notifier */
2071         *(rj->do_update)= 1;
2072 }
2073
2074 static void render_startjob(void *rjv, short *stop, short *do_update)
2075 {
2076         RenderJob *rj= rjv;
2077         
2078         rj->stop= stop;
2079         rj->do_update= do_update;
2080         
2081         if(rj->anim)
2082                 RE_BlenderAnim(rj->re, rj->scene, rj->scene->r.sfra, rj->scene->r.efra, rj->scene->frame_step);
2083         else
2084                 RE_BlenderFrame(rj->re, rj->scene, rj->scene->r.cfra);
2085 }
2086
2087 /* called by render, check job 'stop' value or the global */
2088 static int render_breakjob(void *rjv)
2089 {
2090         RenderJob *rj= rjv;
2091         
2092         if(G.afbreek)
2093                 return 1;
2094         if(rj->stop && *(rj->stop))
2095                 return 1;
2096         return 0;
2097 }
2098
2099 /* using context, starts job */
2100 static int screen_render_invoke(bContext *C, wmOperator *op, wmEvent *event)
2101 {
2102         /* new render clears all callbacks */
2103         Scene *scene= CTX_data_scene(C);
2104         Render *re;
2105         wmJob *steve;
2106         RenderJob *rj;
2107         Image *ima;
2108         
2109         /* only one job at a time */
2110         if(WM_jobs_test(CTX_wm_manager(C), scene))
2111                 return OPERATOR_CANCELLED;
2112         
2113         /* handle UI stuff */
2114         WM_cursor_wait(1);
2115
2116         /* flush multires changes (for sculpt) */
2117         multires_force_update(CTX_data_active_object(C));
2118         
2119         // get editmode results
2120         // store spare
2121         // get view3d layer, local layer, make this nice api call to render
2122         // store spare
2123         
2124         /* ensure at least 1 area shows result */
2125         screen_set_image_output(C);
2126
2127         /* job custom data */
2128         rj= MEM_callocN(sizeof(RenderJob), "render job");
2129         rj->scene= scene;
2130         rj->win= CTX_wm_window(C);
2131         rj->anim= RNA_boolean_get(op->ptr, "anim");
2132         rj->iuser.scene= scene;
2133         rj->iuser.ok= 1;
2134         
2135         /* setup job */
2136         steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene);
2137         WM_jobs_customdata(steve, rj, render_freejob);
2138         WM_jobs_timer(steve, 0.2, NC_SCENE|ND_RENDER_RESULT, 0);
2139         WM_jobs_callbacks(steve, render_startjob, NULL, NULL);
2140         
2141         /* get a render result image, and make sure it is empty */
2142         ima= BKE_image_verify_viewer(IMA_TYPE_R_RESULT, "Render Result");
2143         BKE_image_signal(ima, NULL, IMA_SIGNAL_FREE);
2144         rj->image= ima;
2145         
2146         /* setup new render */
2147         re= RE_NewRender(scene->id.name);
2148         RE_test_break_cb(re, rj, render_breakjob);
2149         RE_display_draw_cb(re, rj, image_rect_update);
2150         rj->re= re;
2151         G.afbreek= 0;
2152         
2153         //      BKE_report in render!
2154         //      RE_error_cb(re, error_cb);
2155
2156         WM_jobs_start(steve);
2157         
2158         G.afbreek= 0;
2159         
2160         WM_cursor_wait(0);
2161         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_RESULT, scene);
2162
2163         return OPERATOR_FINISHED;
2164 }
2165
2166
2167 /* contextual render, using current scene, view3d? */
2168 void SCREEN_OT_render(wmOperatorType *ot)
2169 {
2170         /* identifiers */
2171         ot->name= "Render";
2172         ot->idname= "SCREEN_OT_render";
2173         
2174         /* api callbacks */
2175         ot->invoke= screen_render_invoke;
2176         ot->exec= screen_render_exec;
2177         
2178         ot->poll= ED_operator_screenactive;
2179         
2180         RNA_def_int(ot->srna, "layers", 0, 0, INT_MAX, "Layers", "", 0, INT_MAX);
2181         RNA_def_boolean(ot->srna, "anim", 0, "Animation", "");
2182 }
2183
2184 /* *********************** cancel render viewer *************** */
2185
2186 static int render_view_cancel_exec(bContext *C, wmOperator *unused)
2187 {
2188         ScrArea *sa= CTX_wm_area(C);
2189         SpaceImage *sima= sa->spacedata.first;
2190         
2191         if(sima->flag & SI_PREVSPACE) {
2192                 sima->flag &= ~SI_PREVSPACE;
2193                 ED_area_prevspace(C);
2194         }
2195         else if(sima->flag & SI_FULLWINDOW) {
2196                 sima->flag &= ~SI_FULLWINDOW;
2197                 ED_screen_full_prevspace(C);
2198         }
2199         
2200         return OPERATOR_FINISHED;
2201 }
2202
2203 void SCREEN_OT_render_view_cancel(struct wmOperatorType *ot)
2204 {
2205         /* identifiers */
2206         ot->name= "Cancel Render View";
2207         ot->idname= "SCREEN_OT_render_view_cancel";
2208         
2209         /* api callbacks */
2210         ot->exec= render_view_cancel_exec;
2211         ot->poll= ED_operator_image_active;
2212 }
2213
2214
2215 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
2216
2217 /* called in spacetypes.c */
2218 void ED_operatortypes_screen(void)
2219 {
2220         /* generic UI stuff */
2221         WM_operatortype_append(SCREEN_OT_actionzone);
2222         WM_operatortype_append(SCREEN_OT_repeat_last);
2223         WM_operatortype_append(SCREEN_OT_repeat_history);
2224         WM_operatortype_append(SCREEN_OT_redo_last);
2225         
2226         /* screen tools */
2227         WM_operatortype_append(SCREEN_OT_area_move);
2228         WM_operatortype_append(SCREEN_OT_area_split);
2229         WM_operatortype_append(SCREEN_OT_area_join);
2230         WM_operatortype_append(SCREEN_OT_area_rip);
2231         WM_operatortype_append(SCREEN_OT_region_split);
2232         WM_operatortype_append(SCREEN_OT_region_foursplit);
2233         WM_operatortype_append(SCREEN_OT_region_flip);
2234         WM_operatortype_append(SCREEN_OT_screen_set);
2235         WM_operatortype_append(SCREEN_OT_screen_full_area);
2236         
2237         /*frame changes*/
2238         WM_operatortype_append(SCREEN_OT_frame_offset);
2239         WM_operatortype_append(SCREEN_OT_animation_play);
2240         
2241         /* render */
2242         WM_operatortype_append(SCREEN_OT_render);
2243         WM_operatortype_append(SCREEN_OT_render_view_cancel);
2244         
2245         /* tools shared by more space types */
2246         WM_operatortype_append(ED_OT_undo);
2247         WM_operatortype_append(ED_OT_redo);     
2248         
2249 }
2250
2251 /* called in spacetypes.c */
2252 void ED_keymap_screen(wmWindowManager *wm)
2253 {
2254         ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
2255         
2256         /* standard timers */
2257         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", TIMER0, KM_ANY, KM_ANY, 0);
2258         
2259         WM_keymap_verify_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0);
2260         
2261         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2262         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE, 0, 0, 0);
2263         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE, 0, 0, 0);
2264         WM_keymap_verify_item(keymap, "SCREEN_OT_area_rip", RKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2265         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2266         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2267         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2268         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2269         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
2270
2271          /* tests */
2272         WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2273         WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
2274         
2275         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
2276         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
2277         WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
2278         WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
2279
2280         /* files */
2281         WM_keymap_add_item(keymap, "ED_FILE_OT_load", RETKEY, KM_PRESS, 0, 0);
2282         WM_keymap_add_item(keymap, "ED_FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
2283         
2284         /* undo */
2285         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
2286         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
2287         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
2288         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
2289                                                   
2290         /* render */
2291         WM_keymap_add_item(keymap, "SCREEN_OT_render", F12KEY, KM_PRESS, 0, 0);
2292         WM_keymap_add_item(keymap, "SCREEN_OT_render_view_cancel", ESCKEY, KM_PRESS, 0, 0);
2293         
2294         /* frame offsets */
2295         keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
2296         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
2297         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
2298         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
2299         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
2300         
2301 }
2302