2.5
[blender-staging.git] / source / blender / editors / screen / screen_ops.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include "MEM_guardedalloc.h"
28
29 #include "BLI_blenlib.h"
30 #include "BLI_arithb.h"
31
32 #include "BKE_context.h"
33 #include "BKE_library.h"
34 #include "BKE_main.h"
35 #include "BKE_screen.h"
36 #include "BKE_utildefines.h"
37
38 #include "DNA_scene_types.h"
39
40 #include "WM_api.h"
41 #include "WM_types.h"
42
43 #include "ED_markers.h"
44 #include "ED_screen.h"
45 #include "ED_screen_types.h"
46
47 #include "RNA_access.h"
48 #include "RNA_define.h"
49
50 #include "screen_intern.h"      /* own module include */
51
52 /* ************** Exported Poll tests ********************** */
53
54 int ED_operator_areaactive(bContext *C)
55 {
56         if(CTX_wm_window(C)==NULL) return 0;
57         if(CTX_wm_screen(C)==NULL) return 0;
58         if(CTX_wm_area(C)==NULL) return 0;
59         return 1;
60 }
61
62 int ED_operator_screenactive(bContext *C)
63 {
64         if(CTX_wm_window(C)==NULL) return 0;
65         if(CTX_wm_screen(C)==NULL) return 0;
66         return 1;
67 }
68
69 /* when mouse is over area-edge */
70 int ED_operator_screen_mainwinactive(bContext *C)
71 {
72         if(CTX_wm_window(C)==NULL) return 0;
73         if(CTX_wm_screen(C)==NULL) return 0;
74         if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
75         return 1;
76 }
77
78 static int ed_spacetype_test(bContext *C, int type)
79 {
80         if(ED_operator_areaactive(C)) {
81                 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
82                 return sl && (sl->spacetype == type);
83         }
84         return 0;
85 }
86
87 int ED_operator_view3d_active(bContext *C)
88 {
89         return ed_spacetype_test(C, SPACE_VIEW3D);
90 }
91
92 int ED_operator_timeline_active(bContext *C)
93 {
94         return ed_spacetype_test(C, SPACE_TIME);
95 }
96
97 int ED_operator_outliner_active(bContext *C)
98 {
99         if(ed_spacetype_test(C, SPACE_OOPS)) {
100                 SpaceOops *so= (SpaceOops *)CTX_wm_space_data(C);
101                 return so->spacetype == SO_OUTLINER;
102         }
103         return 0;
104 }
105
106 int ED_operator_file_active(bContext *C)
107 {
108         return ed_spacetype_test(C, SPACE_FILE);
109 }
110
111 int ED_operator_action_active(bContext *C)
112 {
113         return ed_spacetype_test(C, SPACE_ACTION);
114 }
115
116 int ED_operator_buttons_active(bContext *C)
117 {
118         return ed_spacetype_test(C, SPACE_BUTS);
119 }
120
121 int ED_operator_node_active(bContext *C)
122 {
123         return ed_spacetype_test(C, SPACE_NODE);
124 }
125
126 int ED_operator_ipo_active(bContext *C)
127 {
128         return ed_spacetype_test(C, SPACE_IPO);
129 }
130
131 int ED_operator_sequencer_active(bContext *C)
132 {
133         return ed_spacetype_test(C, SPACE_SEQ);
134 }
135
136
137
138 /* *************************** action zone operator ************************** */
139
140 /* operator state vars used:  
141         none
142
143 functions:
144
145         apply() set actionzone event
146
147         exit()  free customdata
148         
149 callbacks:
150
151         exec()  never used
152
153         invoke() check if in zone  
154                 add customdata, put mouseco and area in it
155                 add modal handler
156
157         modal() accept modal events while doing it
158                 call apply() with gesture info, active window, nonactive window
159                 call exit() and remove handler when LMB confirm
160
161 */
162
163 typedef struct sActionzoneData {
164         ScrArea *sa1, *sa2;
165         AZone *az;
166         int x, y, gesture_dir;
167 } sActionzoneData;
168
169 /* used by other operators too */
170 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
171 {
172         ScrArea *sa= NULL;
173         sa= scr->areabase.first;
174         while(sa) {
175                 if(BLI_in_rcti(&sa->totrct, x, y)) break;
176                 sa= sa->next;
177         }
178         
179         return sa;
180 }
181
182
183 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
184 {
185         AZone *az= NULL;
186         int i= 0;
187         
188         for(az= sa->actionzones.first, i= 0; az; az= az->next, i++) {
189                 if(az->type == AZONE_TRI) {
190                         if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y)) 
191                                 break;
192                 }
193                 if(az->type == AZONE_QUAD) {
194                         if(az->x1 < x && x < az->x2 && az->y1 < y && y < az->y2) 
195                                 break;
196                 }
197         }
198         
199         return az;
200 }
201
202 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
203 {
204         AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
205         sActionzoneData *sad;
206         
207         /* quick escape */
208         if(az==NULL)
209                 return OPERATOR_PASS_THROUGH;
210         
211         /* ok we do the actionzone */
212         sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
213         sad->sa1= CTX_wm_area(C);
214         sad->az= az;
215         sad->x= event->x; sad->y= event->y;
216         
217         /* add modal handler */
218         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
219         
220         return OPERATOR_RUNNING_MODAL;
221 }
222
223 static void actionzone_exit(bContext *C, wmOperator *op)
224 {
225         if(op->customdata)
226                 MEM_freeN(op->customdata);
227         op->customdata= NULL;
228 }
229
230 /* send EVT_ACTIONZONE event */
231 static void actionzone_apply(bContext *C, wmOperator *op)
232 {
233         wmEvent event;
234         wmWindow *win= CTX_wm_window(C);
235         
236         event= *(win->eventstate);      /* XXX huh huh? make api call */
237         event.type= EVT_ACTIONZONE;
238         event.customdata= op->customdata;
239         event.customdatafree= TRUE;
240         op->customdata= NULL;
241         
242         wm_event_add(win, &event);
243 }
244
245 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
246 {
247         sActionzoneData *sad= op->customdata;
248         int deltax, deltay;
249         
250         switch(event->type) {
251                 case MOUSEMOVE:
252                         /* calculate gesture direction */
253                         deltax= (event->x - sad->x);
254                         deltay= (event->y - sad->y);
255                         
256                         if(deltay > ABS(deltax))
257                                 sad->gesture_dir= AZONE_N;
258                         else if(deltax > ABS(deltay))
259                                 sad->gesture_dir= AZONE_E;
260                         else if(deltay < -ABS(deltax))
261                                 sad->gesture_dir= AZONE_S;
262                         else
263                                 sad->gesture_dir= AZONE_W;
264                         
265                         /* gesture is large enough? */
266                         if(ABS(deltax) > 12 || ABS(deltay) > 12) {
267                                 
268                                 /* second area, for join */
269                                 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
270                                 /* apply sends event */
271                                 actionzone_apply(C, op);
272                                 actionzone_exit(C, op);
273                                 
274                                 return OPERATOR_FINISHED;
275                         }
276                                 break;
277                 case ESCKEY:
278                 case LEFTMOUSE:
279                         actionzone_exit(C, op);
280                         return OPERATOR_CANCELLED;
281         }
282         
283         return OPERATOR_RUNNING_MODAL;
284 }
285
286 void SCREEN_OT_actionzone(wmOperatorType *ot)
287 {
288         /* identifiers */
289         ot->name= "Handle area action zones";
290         ot->idname= "SCREEN_OT_actionzone";
291         
292         ot->invoke= actionzone_invoke;
293         ot->modal= actionzone_modal;
294         
295         ot->poll= ED_operator_areaactive;
296 }
297
298
299 /* *********** Rip area operator ****************** */
300
301
302 /* operator callback */
303 /* (ton) removed attempt to merge ripped area with another, don't think this is desired functionality.
304 conventions: 'atomic' and 'dont think for user' :) */
305 static int screen_area_rip_op(bContext *C, wmOperator *op)
306 {
307         wmWindow *newwin, *win;
308         bScreen *newsc, *sc;
309         ScrArea *sa;
310         rcti rect;
311         
312         win= CTX_wm_window(C);
313         sc= CTX_wm_screen(C);
314         sa= CTX_wm_area(C);
315
316         /*  poll() checks area context, but we don't accept full-area windows */
317         if(sc->full != SCREENNORMAL) 
318                 return OPERATOR_CANCELLED;
319         
320         /* adds window to WM */
321         rect= sa->totrct;
322         BLI_translate_rcti(&rect, win->posx, win->posy);
323         newwin= WM_window_open(C, &rect);
324         
325         /* allocs new screen and adds to newly created window, using window size */
326         newsc= screen_add(newwin, sc->id.name+2);
327         newwin->screen= newsc;
328         
329         /* copy area to new screen */
330         area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
331         
332         /* screen, areas init */
333         WM_event_add_notifier(C, WM_NOTE_SCREEN_CHANGED, 0, NULL);
334         
335         return OPERATOR_FINISHED;
336 }
337
338 void SCREEN_OT_area_rip(wmOperatorType *ot)
339 {
340         ot->name= "Rip Area into New Window";
341         ot->idname= "SCREEN_OT_area_rip";
342         
343         ot->invoke= WM_operator_confirm;
344         ot->exec= screen_area_rip_op;
345         ot->poll= ED_operator_areaactive;
346 }
347
348
349 /* ************** move area edge operator *********************************** */
350
351 /* operator state vars used:  
352            x, y                         mouse coord near edge
353            delta            movement of edge
354
355         functions:
356
357         init()   set default property values, find edge based on mouse coords, test
358             if the edge can be moved, select edges, calculate min and max movement
359
360         apply() apply delta on selection
361
362         exit()  cleanup, send notifier
363
364         cancel() cancel moving
365
366         callbacks:
367
368         exec()   execute without any user interaction, based on properties
369             call init(), apply(), exit()
370
371         invoke() gets called on mouse click near edge
372             call init(), add handler
373
374         modal()  accept modal events while doing it
375                         call apply() with delta motion
376             call exit() and remove handler
377
378 */
379
380 typedef struct sAreaMoveData {
381         int bigger, smaller, origval;
382         char dir;
383 } sAreaMoveData;
384
385 /* helper call to move area-edge, sets limits */
386 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
387 {
388         ScrArea *sa;
389         
390         /* we check all areas and test for free space with MINSIZE */
391         *bigger= *smaller= 100000;
392         
393         for(sa= sc->areabase.first; sa; sa= sa->next) {
394                 if(dir=='h') {
395                         int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
396                         
397                         /* if top or down edge selected, test height */
398                         if(sa->v1->flag && sa->v4->flag)
399                                 *bigger= MIN2(*bigger, y1);
400                         else if(sa->v2->flag && sa->v3->flag)
401                                 *smaller= MIN2(*smaller, y1);
402                 }
403                 else {
404                         int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
405                         
406                         /* if left or right edge selected, test width */
407                         if(sa->v1->flag && sa->v2->flag)
408                                 *bigger= MIN2(*bigger, x1);
409                         else if(sa->v3->flag && sa->v4->flag)
410                                 *smaller= MIN2(*smaller, x1);
411                 }
412         }
413 }
414
415 /* validate selection inside screen, set variables OK */
416 /* return 0: init failed */
417 static int area_move_init (bContext *C, wmOperator *op)
418 {
419         bScreen *sc= CTX_wm_screen(C);
420         ScrEdge *actedge;
421         sAreaMoveData *md;
422         int x, y;
423
424         /* required properties */
425         x= RNA_int_get(op->ptr, "x");
426         y= RNA_int_get(op->ptr, "y");
427
428         /* setup */
429         actedge= screen_find_active_scredge(sc, x, y);
430         if(actedge==NULL) return 0;
431
432         md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
433         op->customdata= md;
434
435         md->dir= scredge_is_horizontal(actedge)?'h':'v';
436         if(md->dir=='h') md->origval= actedge->v1->vec.y;
437         else md->origval= actedge->v1->vec.x;
438         
439         select_connected_scredge(sc, actedge);
440         /* now all vertices with 'flag==1' are the ones that can be moved. */
441
442         area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
443         
444         return 1;
445 }
446
447 /* moves selected screen edge amount of delta, used by split & move */
448 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
449 {
450         wmWindow *win= CTX_wm_window(C);
451         bScreen *sc= CTX_wm_screen(C);
452         ScrVert *v1;
453         
454         delta= CLAMPIS(delta, -smaller, bigger);
455         
456         for (v1= sc->vertbase.first; v1; v1= v1->next) {
457                 if (v1->flag) {
458                         /* that way a nice AREAGRID  */
459                         if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
460                                 v1->vec.x= origval + delta;
461                                 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
462                         }
463                         if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
464                                 v1->vec.y= origval + delta;
465
466                                 v1->vec.y+= AREAGRID-1;
467                                 v1->vec.y-= (v1->vec.y % AREAGRID);
468                                 
469                                 /* prevent too small top header */
470                                 if(v1->vec.y > win->sizey-AREAMINY)
471                                         v1->vec.y= win->sizey-AREAMINY;
472                         }
473                 }
474         }
475
476         WM_event_add_notifier(C, WM_NOTE_SCREEN_CHANGED, 0, NULL);
477 }
478
479 static void area_move_apply(bContext *C, wmOperator *op)
480 {
481         sAreaMoveData *md= op->customdata;
482         int delta;
483         
484         delta= RNA_int_get(op->ptr, "delta");
485         area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
486 }
487
488 static void area_move_exit(bContext *C, wmOperator *op)
489 {
490         if(op->customdata)
491                 MEM_freeN(op->customdata);
492         op->customdata= NULL;
493         
494         /* this makes sure aligned edges will result in aligned grabbing */
495         removedouble_scrverts(CTX_wm_screen(C));
496         removedouble_scredges(CTX_wm_screen(C));
497 }
498
499 static int area_move_exec(bContext *C, wmOperator *op)
500 {
501         if(!area_move_init(C, op))
502                 return OPERATOR_CANCELLED;
503         
504         area_move_apply(C, op);
505         area_move_exit(C, op);
506         
507         return OPERATOR_FINISHED;
508 }
509
510 /* interaction callback */
511 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
512 {
513         RNA_int_set(op->ptr, "x", event->x);
514         RNA_int_set(op->ptr, "y", event->y);
515
516         if(!area_move_init(C, op)) 
517                 return OPERATOR_PASS_THROUGH;
518         
519         /* add temp handler */
520         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
521         
522         return OPERATOR_RUNNING_MODAL;
523 }
524
525 static int area_move_cancel(bContext *C, wmOperator *op)
526 {
527
528         RNA_int_set(op->ptr, "delta", 0);
529         area_move_apply(C, op);
530         area_move_exit(C, op);
531
532         return OPERATOR_CANCELLED;
533 }
534
535 /* modal callback for while moving edges */
536 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
537 {
538         sAreaMoveData *md;
539         int delta, x, y;
540
541         md= op->customdata;
542
543         x= RNA_int_get(op->ptr, "x");
544         y= RNA_int_get(op->ptr, "y");
545
546         /* execute the events */
547         switch(event->type) {
548                 case MOUSEMOVE:
549                         delta= (md->dir == 'v')? event->x - x: event->y - y;
550                         RNA_int_set(op->ptr, "delta", delta);
551
552                         area_move_apply(C, op);
553                         break;
554                         
555                 case LEFTMOUSE:
556                         if(event->val==0) {
557                                 area_move_exit(C, op);
558                                 return OPERATOR_FINISHED;
559                         }
560                         break;
561                         
562                 case ESCKEY:
563                         return area_move_cancel(C, op);
564         }
565         
566         return OPERATOR_RUNNING_MODAL;
567 }
568
569 void SCREEN_OT_area_move(wmOperatorType *ot)
570 {
571         PropertyRNA *prop;
572
573         /* identifiers */
574         ot->name= "Move area edges";
575         ot->idname= "SCREEN_OT_area_move";
576
577         ot->exec= area_move_exec;
578         ot->invoke= area_move_invoke;
579         ot->cancel= area_move_cancel;
580         ot->modal= area_move_modal;
581
582         ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
583
584         /* rna */
585         prop= RNA_def_property(ot->srna, "x", PROP_INT, PROP_NONE);
586         prop= RNA_def_property(ot->srna, "y", PROP_INT, PROP_NONE);
587         prop= RNA_def_property(ot->srna, "delta", PROP_INT, PROP_NONE);
588 }
589
590 /* ************** split area operator *********************************** */
591
592 /* 
593 operator state vars:  
594         fac              spit point
595         dir              direction 'v' or 'h'
596
597 operator customdata:
598         area                    pointer to (active) area
599         x, y                    last used mouse pos
600         (more, see below)
601
602 functions:
603
604         init()   set default property values, find area based on context
605
606         apply() split area based on state vars
607
608         exit()  cleanup, send notifier
609
610         cancel() remove duplicated area
611
612 callbacks:
613
614         exec()   execute without any user interaction, based on state vars
615             call init(), apply(), exit()
616
617         invoke() gets called on mouse click in action-widget
618             call init(), add modal handler
619                         call apply() with initial motion
620
621         modal()  accept modal events while doing it
622             call move-areas code with delta motion
623             call exit() or cancel() and remove handler
624
625 */
626
627 #define SPLIT_STARTED   1
628 #define SPLIT_PROGRESS  2
629
630 typedef struct sAreaSplitData
631 {
632         int x, y;       /* last used mouse position */
633         
634         int origval;                    /* for move areas */
635         int bigger, smaller;    /* constraints for moving new edge */
636         int delta;                              /* delta move edge */
637         int origmin, origsize;  /* to calculate fac, for property storage */
638
639         ScrEdge *nedge;                 /* new edge */
640         ScrArea *sarea;                 /* start area */
641         ScrArea *narea;                 /* new area */
642 } sAreaSplitData;
643
644 /* generic init, no UI stuff here */
645 static int area_split_init(bContext *C, wmOperator *op)
646 {
647         ScrArea *sa= CTX_wm_area(C);
648         sAreaSplitData *sd;
649         int dir;
650         
651         /* required context */
652         if(sa==NULL) return 0;
653         
654         /* required properties */
655         dir= RNA_enum_get(op->ptr, "dir");
656         
657         /* minimal size */
658         if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
659         if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
660            
661         /* custom data */
662         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
663         op->customdata= sd;
664         
665         sd->sarea= sa;
666         sd->origsize= dir=='v' ? sa->winx:sa->winy;
667         sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
668         
669         return 1;
670 }
671
672 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
673 /* used with split operator */
674 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
675 {
676         ScrVert *sav1= sa->v1;
677         ScrVert *sav2= sa->v2;
678         ScrVert *sav3= sa->v3;
679         ScrVert *sav4= sa->v4;
680         ScrVert *sbv1= sb->v1;
681         ScrVert *sbv2= sb->v2;
682         ScrVert *sbv3= sb->v3;
683         ScrVert *sbv4= sb->v4;
684         
685         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
686                 return screen_findedge(screen, sav1, sav2);
687         }
688         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
689                 return screen_findedge(screen, sav2, sav3);
690         }
691         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
692                 return screen_findedge(screen, sav3, sav4);
693         }
694         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
695                 return screen_findedge(screen, sav1, sav4);
696         }
697
698         return NULL;
699 }
700
701
702 /* do the split, return success */
703 static int area_split_apply(bContext *C, wmOperator *op)
704 {
705         bScreen *sc= CTX_wm_screen(C);
706         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
707         float fac;
708         int dir;
709         
710         fac= RNA_float_get(op->ptr, "fac");
711         dir= RNA_enum_get(op->ptr, "dir");
712
713         sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
714         
715         if(sd->narea) {
716                 ScrVert *sv;
717                 
718                 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
719         
720                 /* select newly created edge, prepare for moving edge */
721                 for(sv= sc->vertbase.first; sv; sv= sv->next)
722                         sv->flag = 0;
723                 
724                 sd->nedge->v1->flag= 1;
725                 sd->nedge->v2->flag= 1;
726
727                 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
728                 else sd->origval= sd->nedge->v1->vec.x;
729
730                 WM_event_add_notifier(C, WM_NOTE_SCREEN_CHANGED, 0, NULL);
731                 
732                 return 1;
733         }               
734         
735         return 0;
736 }
737
738 static void area_split_exit(bContext *C, wmOperator *op)
739 {
740         if (op->customdata) {
741                 MEM_freeN(op->customdata);
742                 op->customdata = NULL;
743         }
744         
745         WM_event_add_notifier(C, WM_NOTE_SCREEN_CHANGED, 0, NULL);
746
747         /* this makes sure aligned edges will result in aligned grabbing */
748         removedouble_scrverts(CTX_wm_screen(C));
749         removedouble_scredges(CTX_wm_screen(C));
750 }
751
752
753 /* UI callback, adds new handler */
754 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
755 {
756         sAreaSplitData *sd;
757         
758         if(event->type==EVT_ACTIONZONE) {
759                 sActionzoneData *sad= event->customdata;
760                 int dir;
761                 
762                 /* verify *sad itself */
763                 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
764                         return OPERATOR_PASS_THROUGH;
765                 
766                 /* is this our *sad? if areas not equal it should be passed on */
767                 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
768                         return OPERATOR_PASS_THROUGH;
769                 
770                 /* prepare operator state vars */
771                 if(sad->gesture_dir==AZONE_N || sad->gesture_dir==AZONE_S) {
772                         dir= 'h';
773                         RNA_float_set(op->ptr, "fac", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
774                 }
775                 else {
776                         dir= 'v';
777                         RNA_float_set(op->ptr, "fac", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
778                 }
779                 RNA_enum_set(op->ptr, "dir", dir);
780
781                 /* general init, also non-UI case, adds customdata, sets area and defaults */
782                 if(!area_split_init(C, op))
783                         return OPERATOR_PASS_THROUGH;
784                 
785                 sd= (sAreaSplitData *)op->customdata;
786                 
787                 sd->x= event->x;
788                 sd->y= event->y;
789                 
790                 /* do the split */
791                 if(area_split_apply(C, op)) {
792                         area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
793                         
794                         /* add temp handler for edge move or cancel */
795                         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
796                         
797                         return OPERATOR_RUNNING_MODAL;
798                 }
799                 
800         }
801         else {
802                 /* nonmodal for now */
803                 return op->type->exec(C, op);
804         }
805         
806         return OPERATOR_PASS_THROUGH;
807 }
808
809 /* function to be called outside UI context, or for redo */
810 static int area_split_exec(bContext *C, wmOperator *op)
811 {
812         
813         if(!area_split_init(C, op))
814                 return OPERATOR_CANCELLED;
815         
816         area_split_apply(C, op);
817         area_split_exit(C, op);
818         
819         return OPERATOR_FINISHED;
820 }
821
822
823 static int area_split_cancel(bContext *C, wmOperator *op)
824 {
825         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
826
827         if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
828                 if (CTX_wm_area(C) == sd->narea) {
829                         CTX_wm_area_set(C, NULL);
830                         CTX_wm_region_set(C, NULL);
831                 }
832                 sd->narea = NULL;
833         }
834         area_split_exit(C, op);
835
836         return OPERATOR_CANCELLED;
837 }
838
839 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
840 {
841         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
842         float fac;
843         int dir;
844
845         /* execute the events */
846         switch(event->type) {
847                 case MOUSEMOVE:
848                         dir= RNA_enum_get(op->ptr, "dir");
849                         
850                         sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
851                         area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
852                         
853                         fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
854                         RNA_float_set(op->ptr, "fac", fac / (float)sd->origsize);
855                         
856                         WM_event_add_notifier(C, WM_NOTE_SCREEN_CHANGED, 0, NULL);
857                         break;
858                         
859                 case LEFTMOUSE:
860                         if(event->val==0) { /* mouse up */
861                                 area_split_exit(C, op);
862                                 return OPERATOR_FINISHED;
863                         }
864                         break;
865                 case RIGHTMOUSE: /* cancel operation */
866                 case ESCKEY:
867                         return area_split_cancel(C, op);
868         }
869         
870         return OPERATOR_RUNNING_MODAL;
871 }
872
873 static EnumPropertyItem prop_direction_items[] = {
874         {'h', "HORIZONTAL", "Horizontal", ""},
875         {'v', "VERTICAL", "Vertical", ""},
876         {0, NULL, NULL, NULL}};
877
878 void SCREEN_OT_area_split(wmOperatorType *ot)
879 {
880         PropertyRNA *prop;
881
882         ot->name = "Split area";
883         ot->idname = "SCREEN_OT_area_split";
884         
885         ot->exec= area_split_exec;
886         ot->invoke= area_split_invoke;
887         ot->modal= area_split_modal;
888         
889         ot->poll= ED_operator_areaactive;
890         ot->flag= OPTYPE_REGISTER;
891         
892         /* rna */
893         prop= RNA_def_property(ot->srna, "dir", PROP_ENUM, PROP_NONE);
894         RNA_def_property_enum_items(prop, prop_direction_items);
895         RNA_def_property_enum_default(prop, 'h');
896
897         prop= RNA_def_property(ot->srna, "fac", PROP_FLOAT, PROP_NONE);
898         RNA_def_property_range(prop, 0.0, 1.0);
899         RNA_def_property_float_default(prop, 0.5f);
900 }
901
902 /* ************** frame change operator ***************************** */
903
904
905 /* function to be called outside UI context, or for redo */
906 static int frame_offset_exec(bContext *C, wmOperator *op)
907 {
908         int delta;
909
910         delta = RNA_int_get(op->ptr, "delta");
911
912         CTX_data_scene(C)->r.cfra += delta;
913         WM_event_add_notifier(C, WM_NOTE_WINDOW_REDRAW, 0, NULL);
914         /* XXX: add WM_NOTE_TIME_CHANGED? */
915
916         return OPERATOR_FINISHED;
917 }
918
919 void SCREEN_OT_frame_offset(wmOperatorType *ot)
920 {
921         ot->name = "Frame Offset";
922         ot->idname = "SCREEN_OT_frame_offset";
923
924         ot->exec= frame_offset_exec;
925
926         ot->poll= ED_operator_screenactive;
927         ot->flag= OPTYPE_REGISTER;
928
929         /* rna */
930         RNA_def_property(ot->srna, "delta", PROP_INT, PROP_NONE);
931 }
932
933 /* ************** switch screen operator ***************************** */
934
935
936 /* function to be called outside UI context, or for redo */
937 static int screen_set_exec(bContext *C, wmOperator *op)
938 {
939         bScreen *screen= CTX_wm_screen(C);
940         int delta= RNA_int_get(op->ptr, "delta");
941         
942         /* this screen is 'fake', solve later XXX */
943         if(CTX_wm_area(C)->full)
944                 return OPERATOR_CANCELLED;
945         
946         if(delta==1) {
947                 screen= screen->id.next;
948                 if(screen==NULL) screen= CTX_data_main(C)->screen.first;
949         }
950         else if(delta== -1) {
951                 screen= screen->id.prev;
952                 if(screen==NULL) screen= CTX_data_main(C)->screen.last;
953         }
954         else {
955                 screen= NULL;
956         }
957         
958         if(screen) {
959                 ed_screen_set(C, screen);
960                 return OPERATOR_FINISHED;
961         }
962         return OPERATOR_CANCELLED;
963 }
964
965 void SCREEN_OT_screen_set(wmOperatorType *ot)
966 {
967         ot->name = "Set Screen";
968         ot->idname = "SCREEN_OT_screen_set";
969         
970         ot->exec= screen_set_exec;
971         ot->poll= ED_operator_screenactive;
972         
973         /* rna */
974         RNA_def_property(ot->srna, "screen", PROP_POINTER, PROP_NONE);
975         RNA_def_property(ot->srna, "delta", PROP_INT, PROP_NONE);
976 }
977
978 /* ************** screen full-area operator ***************************** */
979
980
981 /* function to be called outside UI context, or for redo */
982 static int screen_full_area_exec(bContext *C, wmOperator *op)
983 {
984         ed_screen_fullarea(C);
985         return OPERATOR_FINISHED;
986 }
987
988 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
989 {
990         ot->name = "Toggle Full Area in Screen";
991         ot->idname = "SCREEN_OT_screen_full_area";
992         
993         ot->exec= screen_full_area_exec;
994         ot->poll= ED_operator_screenactive;
995 }
996
997
998
999 /* ************** join area operator ********************************************** */
1000
1001 /* operator state vars used:  
1002                         x1, y1     mouse coord in first area, which will disappear
1003                         x2, y2     mouse coord in 2nd area, which will become joined
1004
1005 functions:
1006
1007    init()   find edge based on state vars 
1008                         test if the edge divides two areas, 
1009                         store active and nonactive area,
1010             
1011    apply()  do the actual join
1012
1013    exit()       cleanup, send notifier
1014
1015 callbacks:
1016
1017    exec()       calls init, apply, exit 
1018    
1019    invoke() sets mouse coords in x,y
1020             call init()
1021             add modal handler
1022
1023    modal()      accept modal events while doing it
1024                         call apply() with active window and nonactive window
1025             call exit() and remove handler when LMB confirm
1026
1027 */
1028
1029 typedef struct sAreaJoinData
1030 {
1031         ScrArea *sa1;   /* first area to be considered */
1032         ScrArea *sa2;   /* second area to be considered */
1033         ScrArea *scr;   /* designed for removal */
1034
1035 } sAreaJoinData;
1036
1037
1038 /* validate selection inside screen, set variables OK */
1039 /* return 0: init failed */
1040 /* XXX todo: find edge based on (x,y) and set other area? */
1041 static int area_join_init(bContext *C, wmOperator *op)
1042 {
1043         ScrArea *sa1, *sa2;
1044         sAreaJoinData* jd= NULL;
1045         int x1, y1;
1046         int x2, y2;
1047
1048         /* required properties, make negative to get return 0 if not set by caller */
1049         x1= RNA_int_get(op->ptr, "x1");
1050         y1= RNA_int_get(op->ptr, "y1");
1051         x2= RNA_int_get(op->ptr, "x2");
1052         y2= RNA_int_get(op->ptr, "y2");
1053         
1054         sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1055         sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1056         if(sa1==NULL || sa2==NULL || sa1==sa2)
1057                 return 0;
1058
1059         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1060                 
1061         jd->sa1 = sa1;
1062         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1063         jd->sa2 = sa2;
1064         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1065         
1066         op->customdata= jd;
1067         
1068         return 1;
1069 }
1070
1071 /* apply the join of the areas (space types) */
1072 static int area_join_apply(bContext *C, wmOperator *op)
1073 {
1074         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1075         if (!jd) return 0;
1076
1077         if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1078                 return 0;
1079         }
1080         if (CTX_wm_area(C) == jd->sa2) {
1081                 CTX_wm_area_set(C, NULL);
1082                 CTX_wm_region_set(C, NULL);
1083         }
1084
1085         return 1;
1086 }
1087
1088 /* finish operation */
1089 static void area_join_exit(bContext *C, wmOperator *op)
1090 {
1091         if (op->customdata) {
1092                 MEM_freeN(op->customdata);
1093                 op->customdata = NULL;
1094         }
1095
1096         /* this makes sure aligned edges will result in aligned grabbing */
1097         removedouble_scredges(CTX_wm_screen(C));
1098         removenotused_scredges(CTX_wm_screen(C));
1099         removenotused_scrverts(CTX_wm_screen(C));
1100 }
1101
1102 static int area_join_exec(bContext *C, wmOperator *op)
1103 {
1104         if(!area_join_init(C, op)) 
1105                 return OPERATOR_CANCELLED;
1106         
1107         area_join_apply(C, op);
1108         area_join_exit(C, op);
1109
1110         return OPERATOR_FINISHED;
1111 }
1112
1113 /* interaction callback */
1114 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1115 {
1116
1117         if(event->type==EVT_ACTIONZONE) {
1118                 sActionzoneData *sad= event->customdata;
1119                 
1120                 /* verify *sad itself */
1121                 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1122                         return OPERATOR_PASS_THROUGH;
1123                 
1124                 /* is this our *sad? if areas equal it should be passed on */
1125                 if(sad->sa1==sad->sa2)
1126                         return OPERATOR_PASS_THROUGH;
1127                 
1128                 /* prepare operator state vars */
1129                 RNA_int_set(op->ptr, "x1", sad->x);
1130                 RNA_int_set(op->ptr, "y1", sad->y);
1131                 RNA_int_set(op->ptr, "x2", event->x);
1132                 RNA_int_set(op->ptr, "y2", event->y);
1133
1134                 if(!area_join_init(C, op)) 
1135                         return OPERATOR_PASS_THROUGH;
1136         
1137                 /* add temp handler */
1138                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1139         
1140                 return OPERATOR_RUNNING_MODAL;
1141         }
1142         
1143         return OPERATOR_PASS_THROUGH;
1144 }
1145
1146 static int area_join_cancel(bContext *C, wmOperator *op)
1147 {
1148         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1149
1150         if (jd->sa1) {
1151                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1152                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1153         }
1154         if (jd->sa2) {
1155                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1156                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1157         }
1158
1159         WM_event_add_notifier(C, WM_NOTE_WINDOW_REDRAW, 0, NULL);
1160         
1161         area_join_exit(C, op);
1162
1163         return OPERATOR_CANCELLED;
1164 }
1165
1166 /* modal callback while selecting area (space) that will be removed */
1167 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1168 {
1169         bScreen *sc= CTX_wm_screen(C);
1170         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1171         
1172         /* execute the events */
1173         switch(event->type) {
1174                         
1175                 case MOUSEMOVE: 
1176                         {
1177                                 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1178                                 int dir;
1179                                 
1180                                 if (sa) {                                       
1181                                         if (jd->sa1 != sa) {
1182                                                 dir = area_getorientation(sc, jd->sa1, sa);
1183                                                 if (dir >= 0) {
1184                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1185                                                         jd->sa2 = sa;
1186                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1187                                                 } 
1188                                                 else {
1189                                                         /* we are not bordering on the previously selected area 
1190                                                            we check if area has common border with the one marked for removal
1191                                                            in this case we can swap areas.
1192                                                         */
1193                                                         dir = area_getorientation(sc, sa, jd->sa2);
1194                                                         if (dir >= 0) {
1195                                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1196                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1197                                                                 jd->sa1 = jd->sa2;
1198                                                                 jd->sa2 = sa;
1199                                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1200                                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1201                                                         } 
1202                                                         else {
1203                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1204                                                                 jd->sa2 = NULL;
1205                                                         }
1206                                                 }
1207                                                 WM_event_add_notifier(C, WM_NOTE_WINDOW_REDRAW, 0, NULL);
1208                                         } 
1209                                         else {
1210                                                 /* we are back in the area previously selected for keeping 
1211                                                  * we swap the areas if possible to allow user to choose */
1212                                                 if (jd->sa2 != NULL) {
1213                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1214                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1215                                                         jd->sa1 = jd->sa2;
1216                                                         jd->sa2 = sa;
1217                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1218                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1219                                                         dir = area_getorientation(sc, jd->sa1, jd->sa2);
1220                                                         if (dir < 0) {
1221                                                                 printf("oops, didn't expect that!\n");
1222                                                         }
1223                                                 } 
1224                                                 else {
1225                                                         dir = area_getorientation(sc, jd->sa1, sa);
1226                                                         if (dir >= 0) {
1227                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1228                                                                 jd->sa2 = sa;
1229                                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1230                                                         }
1231                                                 }
1232                                                 WM_event_add_notifier(C, WM_NOTE_WINDOW_REDRAW, 0, NULL);
1233                                         }
1234                                 }
1235                         }
1236                         break;
1237                 case LEFTMOUSE:
1238                         if(event->val==0) {
1239                                 area_join_apply(C, op);
1240                                 WM_event_add_notifier(C, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1241                                 area_join_exit(C, op);
1242                                 return OPERATOR_FINISHED;
1243                         }
1244                         break;
1245                         
1246                 case ESCKEY:
1247                         return area_join_cancel(C, op);
1248         }
1249
1250         return OPERATOR_RUNNING_MODAL;
1251 }
1252
1253 /* Operator for joining two areas (space types) */
1254 void SCREEN_OT_area_join(wmOperatorType *ot)
1255 {
1256         PropertyRNA *prop;
1257
1258         /* identifiers */
1259         ot->name= "Join area";
1260         ot->idname= "SCREEN_OT_area_join";
1261         
1262         /* api callbacks */
1263         ot->exec= area_join_exec;
1264         ot->invoke= area_join_invoke;
1265         ot->modal= area_join_modal;
1266
1267         ot->poll= ED_operator_screenactive;
1268
1269         /* rna */
1270         prop= RNA_def_property(ot->srna, "x1", PROP_INT, PROP_NONE);
1271         RNA_def_property_int_default(prop, -100);
1272         prop= RNA_def_property(ot->srna, "y1", PROP_INT, PROP_NONE);
1273         RNA_def_property_int_default(prop, -100);
1274         prop= RNA_def_property(ot->srna, "x2", PROP_INT, PROP_NONE);
1275         RNA_def_property_int_default(prop, -100);
1276         prop= RNA_def_property(ot->srna, "y2", PROP_INT, PROP_NONE);
1277         RNA_def_property_int_default(prop, -100);
1278 }
1279
1280 /* ************** repeat last operator ***************************** */
1281
1282 static int repeat_last_exec(bContext *C, wmOperator *op)
1283 {
1284         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1285         
1286         if(lastop) {
1287                 printf("repeat %s\n", lastop->type->idname);
1288                 lastop->type->exec(C, lastop);
1289         }
1290         
1291         return OPERATOR_FINISHED;
1292 }
1293
1294 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1295 {
1296         /* identifiers */
1297         ot->name= "Repeat Last";
1298         ot->idname= "SCREEN_OT_repeat_last";
1299         
1300         /* api callbacks */
1301         ot->invoke= WM_operator_confirm;        
1302         ot->exec= repeat_last_exec;
1303         
1304         ot->poll= ED_operator_screenactive;
1305         
1306 }
1307
1308 /* ************** region split operator ***************************** */
1309
1310 /* insert a region in the area region list */
1311 static int region_split_exec(bContext *C, wmOperator *op)
1312 {
1313         ScrArea *sa= CTX_wm_area(C);
1314         ARegion *ar= CTX_wm_region(C);
1315         ARegion *newar= BKE_area_region_copy(ar);
1316         int dir= RNA_enum_get(op->ptr, "dir");
1317         
1318         BLI_insertlinkafter(&sa->regionbase, CTX_wm_region(C), newar);
1319         
1320         newar->alignment= ar->alignment;
1321         
1322         if(dir=='h')
1323                 ar->alignment= RGN_ALIGN_HSPLIT;
1324         else
1325                 ar->alignment= RGN_ALIGN_VSPLIT;
1326         
1327         WM_event_add_notifier(C, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1328         
1329         return OPERATOR_FINISHED;
1330 }
1331
1332 void SCREEN_OT_region_split(wmOperatorType *ot)
1333 {
1334         PropertyRNA *prop;
1335         
1336         /* identifiers */
1337         ot->name= "Split Region";
1338         ot->idname= "SCREEN_OT_region_split";
1339         
1340         /* api callbacks */
1341         ot->invoke= WM_operator_confirm;
1342         ot->exec= region_split_exec;
1343         ot->poll= ED_operator_areaactive;
1344         
1345         prop= RNA_def_property(ot->srna, "dir", PROP_ENUM, PROP_NONE);
1346         RNA_def_property_enum_items(prop, prop_direction_items);
1347         RNA_def_property_enum_default(prop, 'h');
1348 }
1349
1350 /* ************** region flip operator ***************************** */
1351
1352 /* flip a region alignment */
1353 static int region_flip_exec(bContext *C, wmOperator *op)
1354 {
1355         ARegion *ar= CTX_wm_region(C);
1356
1357         if(ar->alignment==RGN_ALIGN_TOP)
1358                 ar->alignment= RGN_ALIGN_BOTTOM;
1359         else if(ar->alignment==RGN_ALIGN_BOTTOM)
1360                 ar->alignment= RGN_ALIGN_TOP;
1361         else if(ar->alignment==RGN_ALIGN_LEFT)
1362                 ar->alignment= RGN_ALIGN_RIGHT;
1363         else if(ar->alignment==RGN_ALIGN_RIGHT)
1364                 ar->alignment= RGN_ALIGN_LEFT;
1365         
1366         WM_event_add_notifier(C, WM_NOTE_SCREEN_CHANGED, 0, NULL);
1367         
1368         return OPERATOR_FINISHED;
1369 }
1370
1371 void SCREEN_OT_region_flip(wmOperatorType *ot)
1372 {
1373         /* identifiers */
1374         ot->name= "Flip Region";
1375         ot->idname= "SCREEN_OT_region_flip";
1376         
1377         /* api callbacks */
1378         ot->invoke= WM_operator_confirm;
1379         ot->exec= region_flip_exec;
1380         
1381         ot->poll= ED_operator_areaactive;
1382 }
1383
1384 /* ****************** anim player, typically with timer ***************** */
1385
1386 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
1387 {
1388         bScreen *screen= CTX_wm_screen(C);
1389         
1390         if(screen->animtimer==event->customdata) {
1391                 Scene *scene= CTX_data_scene(C);
1392                 
1393                 scene->r.cfra++;
1394                 
1395                 if (scene->r.psfra) {
1396                         if(scene->r.cfra > scene->r.pefra)
1397                                 scene->r.cfra= scene->r.psfra;
1398                 }
1399                 else {
1400                         if(scene->r.cfra > scene->r.efra)
1401                                 scene->r.cfra= scene->r.sfra;
1402                 }
1403
1404                 WM_event_add_notifier(C, WM_NOTE_WINDOW_REDRAW, 0, NULL);
1405                 
1406                 return OPERATOR_FINISHED;
1407         }
1408         return OPERATOR_PASS_THROUGH;
1409 }
1410
1411 void SCREEN_OT_animation_play(wmOperatorType *ot)
1412 {
1413         /* identifiers */
1414         ot->name= "Animation player";
1415         ot->idname= "SCREEN_OT_animation_play";
1416         
1417         /* api callbacks */
1418         ot->invoke= screen_animation_play;
1419         
1420         ot->poll= ED_operator_screenactive;
1421         
1422 }
1423
1424 /* ************** border select operator (template) ***************************** */
1425
1426 /* operator state vars used: (added by default WM callbacks)   
1427         xmin, ymin     
1428         xmax, ymax     
1429
1430         customdata: the wmGesture pointer
1431
1432 callbacks:
1433
1434         exec()  has to be filled in by user
1435
1436         invoke() default WM function
1437                          adds modal handler
1438
1439         modal() default WM function 
1440                         accept modal events while doing it, calls exec(), handles ESC and border drawing
1441         
1442         poll()  has to be filled in by user for context
1443 */
1444 #if 0
1445 static int border_select_do(bContext *C, wmOperator *op)
1446 {
1447         int event_type= RNA_int_get(op->ptr, "event_type");
1448         
1449         if(event_type==LEFTMOUSE)
1450                 printf("border select do select\n");
1451         else if(event_type==RIGHTMOUSE)
1452                 printf("border select deselect\n");
1453         else 
1454                 printf("border select do something\n");
1455         
1456         return 1;
1457 }
1458
1459 void SCREEN_OT_border_select(wmOperatorType *ot)
1460 {
1461         /* identifiers */
1462         ot->name= "Border select";
1463         ot->idname= "SCREEN_OT_border_select";
1464         
1465         /* api callbacks */
1466         ot->exec= border_select_do;
1467         ot->invoke= WM_border_select_invoke;
1468         ot->modal= WM_border_select_modal;
1469         
1470         ot->poll= ED_operator_areaactive;
1471         
1472         /* rna */
1473         RNA_def_property(ot->srna, "event_type", PROP_INT, PROP_NONE);
1474         RNA_def_property(ot->srna, "xmin", PROP_INT, PROP_NONE);
1475         RNA_def_property(ot->srna, "xmax", PROP_INT, PROP_NONE);
1476         RNA_def_property(ot->srna, "ymin", PROP_INT, PROP_NONE);
1477         RNA_def_property(ot->srna, "ymax", PROP_INT, PROP_NONE);
1478
1479 }
1480 #endif
1481
1482 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
1483
1484 /* called in spacetypes.c */
1485 void ED_operatortypes_screen(void)
1486 {
1487         /* generic UI stuff */
1488         WM_operatortype_append(SCREEN_OT_actionzone);
1489         WM_operatortype_append(SCREEN_OT_repeat_last);
1490         
1491         /* screen tools */
1492         WM_operatortype_append(SCREEN_OT_area_move);
1493         WM_operatortype_append(SCREEN_OT_area_split);
1494         WM_operatortype_append(SCREEN_OT_area_join);
1495         WM_operatortype_append(SCREEN_OT_area_rip);
1496         WM_operatortype_append(SCREEN_OT_region_split);
1497         WM_operatortype_append(SCREEN_OT_region_flip);
1498         WM_operatortype_append(SCREEN_OT_screen_set);
1499         WM_operatortype_append(SCREEN_OT_screen_full_area);
1500         
1501         /*frame changes*/
1502         WM_operatortype_append(SCREEN_OT_frame_offset);
1503         WM_operatortype_append(SCREEN_OT_animation_play);
1504         
1505         /* tools shared by more space types */
1506         ED_marker_operatortypes();      
1507         
1508 }
1509
1510 /* called in spacetypes.c */
1511 void ED_keymap_screen(wmWindowManager *wm)
1512 {
1513         ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
1514         
1515         WM_keymap_verify_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0);
1516         
1517         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
1518         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE, 0, 0, 0); /* action tria */
1519         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE, 0, 0, 0);  /* action tria */ 
1520         WM_keymap_verify_item(keymap, "SCREEN_OT_area_rip", RKEY, KM_PRESS, KM_ALT, 0);
1521         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
1522         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
1523         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
1524         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
1525         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
1526
1527          /* tests */
1528         RNA_enum_set(WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, 0, 0)->ptr, "dir", 'h');
1529         RNA_enum_set(WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "dir", 'v');
1530                                                   
1531         /*frame offsets*/
1532         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", TIMER0, KM_ANY, KM_ANY, 0);
1533         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
1534         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
1535         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
1536         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
1537
1538         WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
1539         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
1540         
1541         /* screen level global keymaps */
1542         // err...
1543         ED_marker_keymap(wm);
1544 }
1545