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