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