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