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