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