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