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