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