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_util.h"
45 #include "ED_screen.h"
46 #include "ED_screen_types.h"
47
48 #include "RNA_access.h"
49 #include "RNA_define.h"
50
51 #include "screen_intern.h"      /* own module include */
52
53 /* ************** Exported Poll tests ********************** */
54
55 int ED_operator_areaactive(bContext *C)
56 {
57         if(CTX_wm_window(C)==NULL) return 0;
58         if(CTX_wm_screen(C)==NULL) return 0;
59         if(CTX_wm_area(C)==NULL) return 0;
60         return 1;
61 }
62
63 int ED_operator_screenactive(bContext *C)
64 {
65         if(CTX_wm_window(C)==NULL) return 0;
66         if(CTX_wm_screen(C)==NULL) return 0;
67         return 1;
68 }
69
70 /* when mouse is over area-edge */
71 int ED_operator_screen_mainwinactive(bContext *C)
72 {
73         if(CTX_wm_window(C)==NULL) return 0;
74         if(CTX_wm_screen(C)==NULL) return 0;
75         if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
76         return 1;
77 }
78
79 static int ed_spacetype_test(bContext *C, int type)
80 {
81         if(ED_operator_areaactive(C)) {
82                 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
83                 return sl && (sl->spacetype == type);
84         }
85         return 0;
86 }
87
88 int ED_operator_view3d_active(bContext *C)
89 {
90         return ed_spacetype_test(C, SPACE_VIEW3D);
91 }
92
93 int ED_operator_timeline_active(bContext *C)
94 {
95         return ed_spacetype_test(C, SPACE_TIME);
96 }
97
98 int ED_operator_outliner_active(bContext *C)
99 {
100         if(ed_spacetype_test(C, SPACE_OOPS)) {
101                 SpaceOops *so= (SpaceOops *)CTX_wm_space_data(C);
102                 return (so->type == SO_OUTLINER);
103         }
104         return 0;
105 }
106
107 int ED_operator_file_active(bContext *C)
108 {
109         return ed_spacetype_test(C, SPACE_FILE);
110 }
111
112 int ED_operator_action_active(bContext *C)
113 {
114         return ed_spacetype_test(C, SPACE_ACTION);
115 }
116
117 int ED_operator_buttons_active(bContext *C)
118 {
119         return ed_spacetype_test(C, SPACE_BUTS);
120 }
121
122 int ED_operator_node_active(bContext *C)
123 {
124         return ed_spacetype_test(C, SPACE_NODE);
125 }
126
127 int ED_operator_ipo_active(bContext *C)
128 {
129         return ed_spacetype_test(C, SPACE_IPO);
130 }
131
132 int ED_operator_sequencer_active(bContext *C)
133 {
134         return ed_spacetype_test(C, SPACE_SEQ);
135 }
136
137
138
139 /* *************************** action zone operator ************************** */
140
141 /* operator state vars used:  
142         none
143
144 functions:
145
146         apply() set actionzone event
147
148         exit()  free customdata
149         
150 callbacks:
151
152         exec()  never used
153
154         invoke() check if in zone  
155                 add customdata, put mouseco and area in it
156                 add modal handler
157
158         modal() accept modal events while doing it
159                 call apply() with gesture info, active window, nonactive window
160                 call exit() and remove handler when LMB confirm
161
162 */
163
164 typedef struct sActionzoneData {
165         ScrArea *sa1, *sa2;
166         AZone *az;
167         int x, y, gesture_dir;
168 } sActionzoneData;
169
170 /* used by other operators too */
171 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
172 {
173         ScrArea *sa= NULL;
174         sa= scr->areabase.first;
175         while(sa) {
176                 if(BLI_in_rcti(&sa->totrct, x, y)) break;
177                 sa= sa->next;
178         }
179         
180         return sa;
181 }
182
183
184 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
185 {
186         AZone *az= NULL;
187         int i= 0;
188         
189         for(az= sa->actionzones.first, i= 0; az; az= az->next, i++) {
190                 if(az->type == AZONE_TRI) {
191                         if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y)) 
192                                 break;
193                 }
194                 if(az->type == AZONE_QUAD) {
195                         if(az->x1 < x && x < az->x2 && az->y1 < y && y < az->y2) 
196                                 break;
197                 }
198         }
199         
200         return az;
201 }
202
203 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
204 {
205         AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
206         sActionzoneData *sad;
207         
208         /* quick escape */
209         if(az==NULL)
210                 return OPERATOR_PASS_THROUGH;
211         
212         /* ok we do the actionzone */
213         sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
214         sad->sa1= CTX_wm_area(C);
215         sad->az= az;
216         sad->x= event->x; sad->y= event->y;
217         
218         /* add modal handler */
219         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
220         
221         return OPERATOR_RUNNING_MODAL;
222 }
223
224 static void actionzone_exit(bContext *C, wmOperator *op)
225 {
226         if(op->customdata)
227                 MEM_freeN(op->customdata);
228         op->customdata= NULL;
229 }
230
231 /* send EVT_ACTIONZONE event */
232 static void actionzone_apply(bContext *C, wmOperator *op)
233 {
234         wmEvent event;
235         wmWindow *win= CTX_wm_window(C);
236         
237         event= *(win->eventstate);      /* XXX huh huh? make api call */
238         event.type= EVT_ACTIONZONE;
239         event.customdata= op->customdata;
240         event.customdatafree= TRUE;
241         op->customdata= NULL;
242         
243         wm_event_add(win, &event);
244 }
245
246 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
247 {
248         sActionzoneData *sad= op->customdata;
249         int deltax, deltay;
250         
251         switch(event->type) {
252                 case MOUSEMOVE:
253                         /* calculate gesture direction */
254                         deltax= (event->x - sad->x);
255                         deltay= (event->y - sad->y);
256                         
257                         if(deltay > ABS(deltax))
258                                 sad->gesture_dir= AZONE_N;
259                         else if(deltax > ABS(deltay))
260                                 sad->gesture_dir= AZONE_E;
261                         else if(deltay < -ABS(deltax))
262                                 sad->gesture_dir= AZONE_S;
263                         else
264                                 sad->gesture_dir= AZONE_W;
265                         
266                         /* gesture is large enough? */
267                         if(ABS(deltax) > 12 || ABS(deltay) > 12) {
268                                 
269                                 /* second area, for join */
270                                 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
271                                 /* apply sends event */
272                                 actionzone_apply(C, op);
273                                 actionzone_exit(C, op);
274                                 
275                                 return OPERATOR_FINISHED;
276                         }
277                                 break;
278                 case ESCKEY:
279                 case LEFTMOUSE:
280                         actionzone_exit(C, op);
281                         return OPERATOR_CANCELLED;
282         }
283         
284         return OPERATOR_RUNNING_MODAL;
285 }
286
287 void SCREEN_OT_actionzone(wmOperatorType *ot)
288 {
289         /* identifiers */
290         ot->name= "Handle area action zones";
291         ot->idname= "SCREEN_OT_actionzone";
292         
293         ot->invoke= actionzone_invoke;
294         ot->modal= actionzone_modal;
295         
296         ot->poll= ED_operator_areaactive;
297 }
298
299
300 /* *********** Rip area operator ****************** */
301
302
303 /* operator callback */
304 /* (ton) removed attempt to merge ripped area with another, don't think this is desired functionality.
305 conventions: 'atomic' and 'dont think for user' :) */
306 static int screen_area_rip_op(bContext *C, wmOperator *op)
307 {
308         wmWindow *newwin, *win;
309         bScreen *newsc, *sc;
310         ScrArea *sa;
311         rcti rect;
312         
313         win= CTX_wm_window(C);
314         sc= CTX_wm_screen(C);
315         sa= CTX_wm_area(C);
316
317         /*  poll() checks area context, but we don't accept full-area windows */
318         if(sc->full != SCREENNORMAL) 
319                 return OPERATOR_CANCELLED;
320         
321         /* adds window to WM */
322         rect= sa->totrct;
323         BLI_translate_rcti(&rect, win->posx, win->posy);
324         newwin= WM_window_open(C, &rect);
325         
326         /* allocs new screen and adds to newly created window, using window size */
327         newsc= screen_add(newwin, sc->id.name+2);
328         newwin->screen= newsc;
329         
330         /* copy area to new screen */
331         area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
332         
333         /* screen, areas init */
334         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
335         
336         return OPERATOR_FINISHED;
337 }
338
339 void SCREEN_OT_area_rip(wmOperatorType *ot)
340 {
341         ot->name= "Rip Area into New Window";
342         ot->idname= "SCREEN_OT_area_rip";
343         
344         ot->invoke= WM_operator_confirm;
345         ot->exec= screen_area_rip_op;
346         ot->poll= ED_operator_areaactive;
347 }
348
349
350 /* ************** move area edge operator *********************************** */
351
352 /* operator state vars used:  
353            x, y                         mouse coord near edge
354            delta            movement of edge
355
356         functions:
357
358         init()   set default property values, find edge based on mouse coords, test
359             if the edge can be moved, select edges, calculate min and max movement
360
361         apply() apply delta on selection
362
363         exit()  cleanup, send notifier
364
365         cancel() cancel moving
366
367         callbacks:
368
369         exec()   execute without any user interaction, based on properties
370             call init(), apply(), exit()
371
372         invoke() gets called on mouse click near edge
373             call init(), add handler
374
375         modal()  accept modal events while doing it
376                         call apply() with delta motion
377             call exit() and remove handler
378
379 */
380
381 typedef struct sAreaMoveData {
382         int bigger, smaller, origval;
383         char dir;
384 } sAreaMoveData;
385
386 /* helper call to move area-edge, sets limits */
387 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
388 {
389         ScrArea *sa;
390         
391         /* we check all areas and test for free space with MINSIZE */
392         *bigger= *smaller= 100000;
393         
394         for(sa= sc->areabase.first; sa; sa= sa->next) {
395                 if(dir=='h') {
396                         int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
397                         
398                         /* if top or down edge selected, test height */
399                         if(sa->v1->flag && sa->v4->flag)
400                                 *bigger= MIN2(*bigger, y1);
401                         else if(sa->v2->flag && sa->v3->flag)
402                                 *smaller= MIN2(*smaller, y1);
403                 }
404                 else {
405                         int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
406                         
407                         /* if left or right edge selected, test width */
408                         if(sa->v1->flag && sa->v2->flag)
409                                 *bigger= MIN2(*bigger, x1);
410                         else if(sa->v3->flag && sa->v4->flag)
411                                 *smaller= MIN2(*smaller, x1);
412                 }
413         }
414 }
415
416 /* validate selection inside screen, set variables OK */
417 /* return 0: init failed */
418 static int area_move_init (bContext *C, wmOperator *op)
419 {
420         bScreen *sc= CTX_wm_screen(C);
421         ScrEdge *actedge;
422         sAreaMoveData *md;
423         int x, y;
424
425         /* required properties */
426         x= RNA_int_get(op->ptr, "x");
427         y= RNA_int_get(op->ptr, "y");
428
429         /* setup */
430         actedge= screen_find_active_scredge(sc, x, y);
431         if(actedge==NULL) return 0;
432
433         md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
434         op->customdata= md;
435
436         md->dir= scredge_is_horizontal(actedge)?'h':'v';
437         if(md->dir=='h') md->origval= actedge->v1->vec.y;
438         else md->origval= actedge->v1->vec.x;
439         
440         select_connected_scredge(sc, actedge);
441         /* now all vertices with 'flag==1' are the ones that can be moved. */
442
443         area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
444         
445         return 1;
446 }
447
448 /* moves selected screen edge amount of delta, used by split & move */
449 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
450 {
451         wmWindow *win= CTX_wm_window(C);
452         bScreen *sc= CTX_wm_screen(C);
453         ScrVert *v1;
454         
455         delta= CLAMPIS(delta, -smaller, bigger);
456         
457         for (v1= sc->vertbase.first; v1; v1= v1->next) {
458                 if (v1->flag) {
459                         /* that way a nice AREAGRID  */
460                         if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
461                                 v1->vec.x= origval + delta;
462                                 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
463                         }
464                         if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
465                                 v1->vec.y= origval + delta;
466
467                                 v1->vec.y+= AREAGRID-1;
468                                 v1->vec.y-= (v1->vec.y % AREAGRID);
469                                 
470                                 /* prevent too small top header */
471                                 if(v1->vec.y > win->sizey-AREAMINY)
472                                         v1->vec.y= win->sizey-AREAMINY;
473                         }
474                 }
475         }
476
477         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
478 }
479
480 static void area_move_apply(bContext *C, wmOperator *op)
481 {
482         sAreaMoveData *md= op->customdata;
483         int delta;
484         
485         delta= RNA_int_get(op->ptr, "delta");
486         area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
487 }
488
489 static void area_move_exit(bContext *C, wmOperator *op)
490 {
491         if(op->customdata)
492                 MEM_freeN(op->customdata);
493         op->customdata= NULL;
494         
495         /* this makes sure aligned edges will result in aligned grabbing */
496         removedouble_scrverts(CTX_wm_screen(C));
497         removedouble_scredges(CTX_wm_screen(C));
498 }
499
500 static int area_move_exec(bContext *C, wmOperator *op)
501 {
502         if(!area_move_init(C, op))
503                 return OPERATOR_CANCELLED;
504         
505         area_move_apply(C, op);
506         area_move_exit(C, op);
507         
508         return OPERATOR_FINISHED;
509 }
510
511 /* interaction callback */
512 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
513 {
514         RNA_int_set(op->ptr, "x", event->x);
515         RNA_int_set(op->ptr, "y", event->y);
516
517         if(!area_move_init(C, op)) 
518                 return OPERATOR_PASS_THROUGH;
519         
520         /* add temp handler */
521         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
522         
523         return OPERATOR_RUNNING_MODAL;
524 }
525
526 static int area_move_cancel(bContext *C, wmOperator *op)
527 {
528
529         RNA_int_set(op->ptr, "delta", 0);
530         area_move_apply(C, op);
531         area_move_exit(C, op);
532
533         return OPERATOR_CANCELLED;
534 }
535
536 /* modal callback for while moving edges */
537 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
538 {
539         sAreaMoveData *md;
540         int delta, x, y;
541
542         md= op->customdata;
543
544         x= RNA_int_get(op->ptr, "x");
545         y= RNA_int_get(op->ptr, "y");
546
547         /* execute the events */
548         switch(event->type) {
549                 case MOUSEMOVE:
550                         delta= (md->dir == 'v')? event->x - x: event->y - y;
551                         RNA_int_set(op->ptr, "delta", delta);
552
553                         area_move_apply(C, op);
554                         break;
555                         
556                 case LEFTMOUSE:
557                         if(event->val==0) {
558                                 area_move_exit(C, op);
559                                 return OPERATOR_FINISHED;
560                         }
561                         break;
562                         
563                 case ESCKEY:
564                         return area_move_cancel(C, op);
565         }
566         
567         return OPERATOR_RUNNING_MODAL;
568 }
569
570 void SCREEN_OT_area_move(wmOperatorType *ot)
571 {
572         PropertyRNA *prop;
573
574         /* identifiers */
575         ot->name= "Move area edges";
576         ot->idname= "SCREEN_OT_area_move";
577
578         ot->exec= area_move_exec;
579         ot->invoke= area_move_invoke;
580         ot->cancel= area_move_cancel;
581         ot->modal= area_move_modal;
582
583         ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
584
585         /* rna */
586         prop= RNA_def_property(ot->srna, "x", PROP_INT, PROP_NONE);
587         prop= RNA_def_property(ot->srna, "y", PROP_INT, PROP_NONE);
588         prop= RNA_def_property(ot->srna, "delta", PROP_INT, PROP_NONE);
589 }
590
591 /* ************** split area operator *********************************** */
592
593 /* 
594 operator state vars:  
595         fac              spit point
596         dir              direction 'v' or 'h'
597
598 operator customdata:
599         area                    pointer to (active) area
600         x, y                    last used mouse pos
601         (more, see below)
602
603 functions:
604
605         init()   set default property values, find area based on context
606
607         apply() split area based on state vars
608
609         exit()  cleanup, send notifier
610
611         cancel() remove duplicated area
612
613 callbacks:
614
615         exec()   execute without any user interaction, based on state vars
616             call init(), apply(), exit()
617
618         invoke() gets called on mouse click in action-widget
619             call init(), add modal handler
620                         call apply() with initial motion
621
622         modal()  accept modal events while doing it
623             call move-areas code with delta motion
624             call exit() or cancel() and remove handler
625
626 */
627
628 #define SPLIT_STARTED   1
629 #define SPLIT_PROGRESS  2
630
631 typedef struct sAreaSplitData
632 {
633         int x, y;       /* last used mouse position */
634         
635         int origval;                    /* for move areas */
636         int bigger, smaller;    /* constraints for moving new edge */
637         int delta;                              /* delta move edge */
638         int origmin, origsize;  /* to calculate fac, for property storage */
639
640         ScrEdge *nedge;                 /* new edge */
641         ScrArea *sarea;                 /* start area */
642         ScrArea *narea;                 /* new area */
643 } sAreaSplitData;
644
645 /* generic init, no UI stuff here */
646 static int area_split_init(bContext *C, wmOperator *op)
647 {
648         ScrArea *sa= CTX_wm_area(C);
649         sAreaSplitData *sd;
650         int dir;
651         
652         /* required context */
653         if(sa==NULL) return 0;
654         
655         /* required properties */
656         dir= RNA_enum_get(op->ptr, "dir");
657         
658         /* minimal size */
659         if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
660         if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
661            
662         /* custom data */
663         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
664         op->customdata= sd;
665         
666         sd->sarea= sa;
667         sd->origsize= dir=='v' ? sa->winx:sa->winy;
668         sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
669         
670         return 1;
671 }
672
673 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
674 /* used with split operator */
675 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
676 {
677         ScrVert *sav1= sa->v1;
678         ScrVert *sav2= sa->v2;
679         ScrVert *sav3= sa->v3;
680         ScrVert *sav4= sa->v4;
681         ScrVert *sbv1= sb->v1;
682         ScrVert *sbv2= sb->v2;
683         ScrVert *sbv3= sb->v3;
684         ScrVert *sbv4= sb->v4;
685         
686         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
687                 return screen_findedge(screen, sav1, sav2);
688         }
689         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
690                 return screen_findedge(screen, sav2, sav3);
691         }
692         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
693                 return screen_findedge(screen, sav3, sav4);
694         }
695         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
696                 return screen_findedge(screen, sav1, sav4);
697         }
698
699         return NULL;
700 }
701
702
703 /* do the split, return success */
704 static int area_split_apply(bContext *C, wmOperator *op)
705 {
706         bScreen *sc= CTX_wm_screen(C);
707         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
708         float fac;
709         int dir;
710         
711         fac= RNA_float_get(op->ptr, "fac");
712         dir= RNA_enum_get(op->ptr, "dir");
713
714         sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
715         
716         if(sd->narea) {
717                 ScrVert *sv;
718                 
719                 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
720         
721                 /* select newly created edge, prepare for moving edge */
722                 for(sv= sc->vertbase.first; sv; sv= sv->next)
723                         sv->flag = 0;
724                 
725                 sd->nedge->v1->flag= 1;
726                 sd->nedge->v2->flag= 1;
727
728                 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
729                 else sd->origval= sd->nedge->v1->vec.x;
730
731                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
732                 
733                 return 1;
734         }               
735         
736         return 0;
737 }
738
739 static void area_split_exit(bContext *C, wmOperator *op)
740 {
741         if (op->customdata) {
742                 MEM_freeN(op->customdata);
743                 op->customdata = NULL;
744         }
745         
746         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
747
748         /* this makes sure aligned edges will result in aligned grabbing */
749         removedouble_scrverts(CTX_wm_screen(C));
750         removedouble_scredges(CTX_wm_screen(C));
751 }
752
753
754 /* UI callback, adds new handler */
755 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
756 {
757         sAreaSplitData *sd;
758         
759         if(event->type==EVT_ACTIONZONE) {
760                 sActionzoneData *sad= event->customdata;
761                 int dir;
762                 
763                 /* verify *sad itself */
764                 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
765                         return OPERATOR_PASS_THROUGH;
766                 
767                 /* is this our *sad? if areas not equal it should be passed on */
768                 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
769                         return OPERATOR_PASS_THROUGH;
770                 
771                 /* prepare operator state vars */
772                 if(sad->gesture_dir==AZONE_N || sad->gesture_dir==AZONE_S) {
773                         dir= 'h';
774                         RNA_float_set(op->ptr, "fac", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
775                 }
776                 else {
777                         dir= 'v';
778                         RNA_float_set(op->ptr, "fac", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
779                 }
780                 RNA_enum_set(op->ptr, "dir", dir);
781
782                 /* general init, also non-UI case, adds customdata, sets area and defaults */
783                 if(!area_split_init(C, op))
784                         return OPERATOR_PASS_THROUGH;
785                 
786                 sd= (sAreaSplitData *)op->customdata;
787                 
788                 sd->x= event->x;
789                 sd->y= event->y;
790                 
791                 /* do the split */
792                 if(area_split_apply(C, op)) {
793                         area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
794                         
795                         /* add temp handler for edge move or cancel */
796                         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
797                         
798                         return OPERATOR_RUNNING_MODAL;
799                 }
800                 
801         }
802         else {
803                 /* nonmodal for now */
804                 return op->type->exec(C, op);
805         }
806         
807         return OPERATOR_PASS_THROUGH;
808 }
809
810 /* function to be called outside UI context, or for redo */
811 static int area_split_exec(bContext *C, wmOperator *op)
812 {
813         
814         if(!area_split_init(C, op))
815                 return OPERATOR_CANCELLED;
816         
817         area_split_apply(C, op);
818         area_split_exit(C, op);
819         
820         return OPERATOR_FINISHED;
821 }
822
823
824 static int area_split_cancel(bContext *C, wmOperator *op)
825 {
826         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
827
828         if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
829                 if (CTX_wm_area(C) == sd->narea) {
830                         CTX_wm_area_set(C, NULL);
831                         CTX_wm_region_set(C, NULL);
832                 }
833                 sd->narea = NULL;
834         }
835         area_split_exit(C, op);
836
837         return OPERATOR_CANCELLED;
838 }
839
840 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
841 {
842         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
843         float fac;
844         int dir;
845
846         /* execute the events */
847         switch(event->type) {
848                 case MOUSEMOVE:
849                         dir= RNA_enum_get(op->ptr, "dir");
850                         
851                         sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
852                         area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
853                         
854                         fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
855                         RNA_float_set(op->ptr, "fac", fac / (float)sd->origsize);
856                         
857                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
858                         break;
859                         
860                 case LEFTMOUSE:
861                         if(event->val==0) { /* mouse up */
862                                 area_split_exit(C, op);
863                                 return OPERATOR_FINISHED;
864                         }
865                         break;
866                 case RIGHTMOUSE: /* cancel operation */
867                 case ESCKEY:
868                         return area_split_cancel(C, op);
869         }
870         
871         return OPERATOR_RUNNING_MODAL;
872 }
873
874 static EnumPropertyItem prop_direction_items[] = {
875         {'h', "HORIZONTAL", "Horizontal", ""},
876         {'v', "VERTICAL", "Vertical", ""},
877         {0, NULL, NULL, NULL}};
878
879 void SCREEN_OT_area_split(wmOperatorType *ot)
880 {
881         PropertyRNA *prop;
882
883         ot->name = "Split area";
884         ot->idname = "SCREEN_OT_area_split";
885         
886         ot->exec= area_split_exec;
887         ot->invoke= area_split_invoke;
888         ot->modal= area_split_modal;
889         
890         ot->poll= ED_operator_areaactive;
891         ot->flag= OPTYPE_REGISTER;
892         
893         /* rna */
894         prop= RNA_def_property(ot->srna, "dir", PROP_ENUM, PROP_NONE);
895         RNA_def_property_enum_items(prop, prop_direction_items);
896         RNA_def_property_enum_default(prop, 'h');
897
898         prop= RNA_def_property(ot->srna, "fac", PROP_FLOAT, PROP_NONE);
899         RNA_def_property_range(prop, 0.0, 1.0);
900         RNA_def_property_float_default(prop, 0.5f);
901 }
902
903 /* ************** frame change operator ***************************** */
904
905
906 /* function to be called outside UI context, or for redo */
907 static int frame_offset_exec(bContext *C, wmOperator *op)
908 {
909         int delta;
910
911         delta = RNA_int_get(op->ptr, "delta");
912
913         CTX_data_scene(C)->r.cfra += delta;
914         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
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, NC_WINDOW, 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, NC_WINDOW, 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, NC_WINDOW, 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, NC_SCREEN|NA_EDITED, 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, NC_SCREEN|NA_EDITED, 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, NC_SCREEN|NA_EDITED, 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, NC_SCENE|ND_FRAME, CTX_data_scene(C));
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         WM_operatortype_append(ED_OT_undo);
1507         WM_operatortype_append(ED_OT_redo);
1508         ED_marker_operatortypes();      
1509         
1510 }
1511
1512 /* called in spacetypes.c */
1513 void ED_keymap_screen(wmWindowManager *wm)
1514 {
1515         ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
1516         
1517         WM_keymap_verify_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0);
1518         
1519         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
1520         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE, 0, 0, 0); /* action tria */
1521         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE, 0, 0, 0);  /* action tria */ 
1522         WM_keymap_verify_item(keymap, "SCREEN_OT_area_rip", RKEY, KM_PRESS, KM_ALT, 0);
1523         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
1524         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
1525         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
1526         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
1527         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
1528
1529          /* tests */
1530         RNA_enum_set(WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0)->ptr, "dir", 'h');
1531         RNA_enum_set(WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0)->ptr, "dir", 'v');
1532         
1533         /*frame offsets*/
1534         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", TIMER0, KM_ANY, KM_ANY, 0);
1535         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
1536         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
1537         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
1538         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
1539
1540         WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
1541         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
1542
1543         /* undo */
1544         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
1545         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
1546         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
1547         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
1548                                                   
1549         /* screen level global keymaps */
1550         // err...
1551         ED_marker_keymap(wm);
1552 }
1553