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