RNA
[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 "UI_interface.h"
57
58 #include "screen_intern.h"      /* own module include */
59
60 /* ************** Exported Poll tests ********************** */
61
62 int ED_operator_areaactive(bContext *C)
63 {
64         if(CTX_wm_window(C)==NULL) return 0;
65         if(CTX_wm_screen(C)==NULL) return 0;
66         if(CTX_wm_area(C)==NULL) return 0;
67         return 1;
68 }
69
70 int ED_operator_screenactive(bContext *C)
71 {
72         if(CTX_wm_window(C)==NULL) return 0;
73         if(CTX_wm_screen(C)==NULL) return 0;
74         return 1;
75 }
76
77 /* when mouse is over area-edge */
78 int ED_operator_screen_mainwinactive(bContext *C)
79 {
80         if(CTX_wm_window(C)==NULL) return 0;
81         if(CTX_wm_screen(C)==NULL) return 0;
82         if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
83         return 1;
84 }
85
86 int ED_operator_scene_editable(bContext *C)
87 {
88         Scene *scene= CTX_data_scene(C);
89         if(scene && scene->id.lib==NULL)
90                 return 1;
91         return 0;
92 }
93
94 static int ed_spacetype_test(bContext *C, int type)
95 {
96         if(ED_operator_areaactive(C)) {
97                 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
98                 return sl && (sl->spacetype == type);
99         }
100         return 0;
101 }
102
103 int ED_operator_view3d_active(bContext *C)
104 {
105         return ed_spacetype_test(C, SPACE_VIEW3D);
106 }
107
108 int ED_operator_timeline_active(bContext *C)
109 {
110         return ed_spacetype_test(C, SPACE_TIME);
111 }
112
113 int ED_operator_outliner_active(bContext *C)
114 {
115         if(ed_spacetype_test(C, SPACE_OOPS)) {
116                 SpaceOops *so= (SpaceOops *)CTX_wm_space_data(C);
117                 return (so->type == SO_OUTLINER);
118         }
119         return 0;
120 }
121
122 int ED_operator_file_active(bContext *C)
123 {
124         return ed_spacetype_test(C, SPACE_FILE);
125 }
126
127 int ED_operator_action_active(bContext *C)
128 {
129         return ed_spacetype_test(C, SPACE_ACTION);
130 }
131
132 int ED_operator_buttons_active(bContext *C)
133 {
134         return ed_spacetype_test(C, SPACE_BUTS);
135 }
136
137 int ED_operator_node_active(bContext *C)
138 {
139         return ed_spacetype_test(C, SPACE_NODE);
140 }
141
142 int ED_operator_ipo_active(bContext *C)
143 {
144         return ed_spacetype_test(C, SPACE_IPO);
145 }
146
147 int ED_operator_sequencer_active(bContext *C)
148 {
149         return ed_spacetype_test(C, SPACE_SEQ);
150 }
151
152 int ED_operator_object_active(bContext *C)
153 {
154         return NULL != CTX_data_active_object(C);
155 }
156
157 int ED_operator_editmesh(bContext *C)
158 {
159         Object *obedit= CTX_data_edit_object(C);
160         if(obedit && obedit->type==OB_MESH)
161                 return NULL != ((Mesh *)obedit->data)->edit_mesh;
162         return 0;
163 }
164
165 int ED_operator_uvedit(bContext *C)
166 {
167         Object *obedit= CTX_data_edit_object(C);
168         EditMesh *em= NULL;
169
170         if(obedit && obedit->type==OB_MESH)
171                 em= ((Mesh *)obedit->data)->edit_mesh;
172
173     if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE)))
174                 return 1;
175
176         return 0;
177 }
178
179 int ED_operator_editcurve(bContext *C)
180 {
181         Object *obedit= CTX_data_edit_object(C);
182         if(obedit && obedit->type==OB_CURVE)
183                 return NULL != ((Mesh *)obedit->data)->edit_mesh;
184         return 0;
185 }
186
187
188 /* *************************** action zone operator ************************** */
189
190 /* operator state vars used:  
191         none
192
193 functions:
194
195         apply() set actionzone event
196
197         exit()  free customdata
198         
199 callbacks:
200
201         exec()  never used
202
203         invoke() check if in zone  
204                 add customdata, put mouseco and area in it
205                 add modal handler
206
207         modal() accept modal events while doing it
208                 call apply() with gesture info, active window, nonactive window
209                 call exit() and remove handler when LMB confirm
210
211 */
212
213 typedef struct sActionzoneData {
214         ScrArea *sa1, *sa2;
215         AZone *az;
216         int x, y, gesture_dir;
217 } sActionzoneData;
218
219 /* used by other operators too */
220 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
221 {
222         ScrArea *sa= NULL;
223         sa= scr->areabase.first;
224         while(sa) {
225                 if(BLI_in_rcti(&sa->totrct, x, y)) break;
226                 sa= sa->next;
227         }
228         
229         return sa;
230 }
231
232
233 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
234 {
235         AZone *az= NULL;
236         int i= 0;
237         
238         for(az= sa->actionzones.first, i= 0; az; az= az->next, i++) {
239                 if(az->type == AZONE_TRI) {
240                         if(IsPointInTri2DInts(az->x1, az->y1, az->x2, az->y2, x, y)) 
241                                 break;
242                 }
243                 if(az->type == AZONE_QUAD) {
244                         if(az->x1 < x && x < az->x2 && az->y1 < y && y < az->y2) 
245                                 break;
246                 }
247         }
248         
249         return az;
250 }
251
252 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
253 {
254         AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
255         sActionzoneData *sad;
256         
257         /* quick escape */
258         if(az==NULL)
259                 return OPERATOR_PASS_THROUGH;
260         
261         /* ok we do the actionzone */
262         sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
263         sad->sa1= CTX_wm_area(C);
264         sad->az= az;
265         sad->x= event->x; sad->y= event->y;
266         
267         /* add modal handler */
268         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
269         
270         return OPERATOR_RUNNING_MODAL;
271 }
272
273 static void actionzone_exit(bContext *C, wmOperator *op)
274 {
275         if(op->customdata)
276                 MEM_freeN(op->customdata);
277         op->customdata= NULL;
278 }
279
280 /* send EVT_ACTIONZONE event */
281 static void actionzone_apply(bContext *C, wmOperator *op)
282 {
283         wmEvent event;
284         wmWindow *win= CTX_wm_window(C);
285         
286         event= *(win->eventstate);      /* XXX huh huh? make api call */
287         event.type= EVT_ACTIONZONE;
288         event.customdata= op->customdata;
289         event.customdatafree= TRUE;
290         op->customdata= NULL;
291         
292         wm_event_add(win, &event);
293 }
294
295 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
296 {
297         sActionzoneData *sad= op->customdata;
298         int deltax, deltay;
299         
300         switch(event->type) {
301                 case MOUSEMOVE:
302                         /* calculate gesture direction */
303                         deltax= (event->x - sad->x);
304                         deltay= (event->y - sad->y);
305                         
306                         if(deltay > ABS(deltax))
307                                 sad->gesture_dir= AZONE_N;
308                         else if(deltax > ABS(deltay))
309                                 sad->gesture_dir= AZONE_E;
310                         else if(deltay < -ABS(deltax))
311                                 sad->gesture_dir= AZONE_S;
312                         else
313                                 sad->gesture_dir= AZONE_W;
314                         
315                         /* gesture is large enough? */
316                         if(ABS(deltax) > 12 || ABS(deltay) > 12) {
317                                 
318                                 /* second area, for join */
319                                 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
320                                 /* apply sends event */
321                                 actionzone_apply(C, op);
322                                 actionzone_exit(C, op);
323                                 
324                                 return OPERATOR_FINISHED;
325                         }
326                                 break;
327                 case ESCKEY:
328                 case LEFTMOUSE:
329                         actionzone_exit(C, op);
330                         return OPERATOR_CANCELLED;
331         }
332         
333         return OPERATOR_RUNNING_MODAL;
334 }
335
336 void SCREEN_OT_actionzone(wmOperatorType *ot)
337 {
338         /* identifiers */
339         ot->name= "Handle area action zones";
340         ot->idname= "SCREEN_OT_actionzone";
341         
342         ot->invoke= actionzone_invoke;
343         ot->modal= actionzone_modal;
344         
345         ot->poll= ED_operator_areaactive;
346 }
347
348
349 /* *********** Rip area operator ****************** */
350
351
352 /* operator callback */
353 /* (ton) removed attempt to merge ripped area with another, don't think this is desired functionality.
354 conventions: 'atomic' and 'dont think for user' :) */
355 static int screen_area_rip_op(bContext *C, wmOperator *op)
356 {
357         wmWindow *newwin, *win;
358         bScreen *newsc, *sc;
359         ScrArea *sa;
360         rcti rect;
361         
362         win= CTX_wm_window(C);
363         sc= CTX_wm_screen(C);
364         sa= CTX_wm_area(C);
365
366         /*  poll() checks area context, but we don't accept full-area windows */
367         if(sc->full != SCREENNORMAL) 
368                 return OPERATOR_CANCELLED;
369         
370         /* adds window to WM */
371         rect= sa->totrct;
372         BLI_translate_rcti(&rect, win->posx, win->posy);
373         newwin= WM_window_open(C, &rect);
374         
375         /* allocs new screen and adds to newly created window, using window size */
376         newsc= screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
377         newwin->screen= newsc;
378         
379         /* copy area to new screen */
380         area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
381         
382         /* screen, areas init */
383         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
384         
385         return OPERATOR_FINISHED;
386 }
387
388 void SCREEN_OT_area_rip(wmOperatorType *ot)
389 {
390         ot->name= "Rip Area into New Window";
391         ot->idname= "SCREEN_OT_area_rip";
392         
393         ot->invoke= WM_operator_confirm;
394         ot->exec= screen_area_rip_op;
395         ot->poll= ED_operator_areaactive;
396 }
397
398
399 /* ************** move area edge operator *********************************** */
400
401 /* operator state vars used:  
402            x, y                         mouse coord near edge
403            delta            movement of edge
404
405         functions:
406
407         init()   set default property values, find edge based on mouse coords, test
408             if the edge can be moved, select edges, calculate min and max movement
409
410         apply() apply delta on selection
411
412         exit()  cleanup, send notifier
413
414         cancel() cancel moving
415
416         callbacks:
417
418         exec()   execute without any user interaction, based on properties
419             call init(), apply(), exit()
420
421         invoke() gets called on mouse click near edge
422             call init(), add handler
423
424         modal()  accept modal events while doing it
425                         call apply() with delta motion
426             call exit() and remove handler
427
428 */
429
430 typedef struct sAreaMoveData {
431         int bigger, smaller, origval;
432         char dir;
433 } sAreaMoveData;
434
435 /* helper call to move area-edge, sets limits */
436 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
437 {
438         ScrArea *sa;
439         
440         /* we check all areas and test for free space with MINSIZE */
441         *bigger= *smaller= 100000;
442         
443         for(sa= sc->areabase.first; sa; sa= sa->next) {
444                 if(dir=='h') {
445                         int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
446                         
447                         /* if top or down edge selected, test height */
448                         if(sa->v1->flag && sa->v4->flag)
449                                 *bigger= MIN2(*bigger, y1);
450                         else if(sa->v2->flag && sa->v3->flag)
451                                 *smaller= MIN2(*smaller, y1);
452                 }
453                 else {
454                         int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
455                         
456                         /* if left or right edge selected, test width */
457                         if(sa->v1->flag && sa->v2->flag)
458                                 *bigger= MIN2(*bigger, x1);
459                         else if(sa->v3->flag && sa->v4->flag)
460                                 *smaller= MIN2(*smaller, x1);
461                 }
462         }
463 }
464
465 /* validate selection inside screen, set variables OK */
466 /* return 0: init failed */
467 static int area_move_init (bContext *C, wmOperator *op)
468 {
469         bScreen *sc= CTX_wm_screen(C);
470         ScrEdge *actedge;
471         sAreaMoveData *md;
472         int x, y;
473
474         /* required properties */
475         x= RNA_int_get(op->ptr, "x");
476         y= RNA_int_get(op->ptr, "y");
477
478         /* setup */
479         actedge= screen_find_active_scredge(sc, x, y);
480         if(actedge==NULL) return 0;
481
482         md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
483         op->customdata= md;
484
485         md->dir= scredge_is_horizontal(actedge)?'h':'v';
486         if(md->dir=='h') md->origval= actedge->v1->vec.y;
487         else md->origval= actedge->v1->vec.x;
488         
489         select_connected_scredge(sc, actedge);
490         /* now all vertices with 'flag==1' are the ones that can be moved. */
491
492         area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
493         
494         return 1;
495 }
496
497 /* moves selected screen edge amount of delta, used by split & move */
498 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
499 {
500         wmWindow *win= CTX_wm_window(C);
501         bScreen *sc= CTX_wm_screen(C);
502         ScrVert *v1;
503         
504         delta= CLAMPIS(delta, -smaller, bigger);
505         
506         for (v1= sc->vertbase.first; v1; v1= v1->next) {
507                 if (v1->flag) {
508                         /* that way a nice AREAGRID  */
509                         if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
510                                 v1->vec.x= origval + delta;
511                                 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
512                         }
513                         if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
514                                 v1->vec.y= origval + delta;
515
516                                 v1->vec.y+= AREAGRID-1;
517                                 v1->vec.y-= (v1->vec.y % AREAGRID);
518                                 
519                                 /* prevent too small top header */
520                                 if(v1->vec.y > win->sizey-AREAMINY)
521                                         v1->vec.y= win->sizey-AREAMINY;
522                         }
523                 }
524         }
525
526         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
527 }
528
529 static void area_move_apply(bContext *C, wmOperator *op)
530 {
531         sAreaMoveData *md= op->customdata;
532         int delta;
533         
534         delta= RNA_int_get(op->ptr, "delta");
535         area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
536 }
537
538 static void area_move_exit(bContext *C, wmOperator *op)
539 {
540         if(op->customdata)
541                 MEM_freeN(op->customdata);
542         op->customdata= NULL;
543         
544         /* this makes sure aligned edges will result in aligned grabbing */
545         removedouble_scrverts(CTX_wm_screen(C));
546         removedouble_scredges(CTX_wm_screen(C));
547 }
548
549 static int area_move_exec(bContext *C, wmOperator *op)
550 {
551         if(!area_move_init(C, op))
552                 return OPERATOR_CANCELLED;
553         
554         area_move_apply(C, op);
555         area_move_exit(C, op);
556         
557         return OPERATOR_FINISHED;
558 }
559
560 /* interaction callback */
561 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
562 {
563         RNA_int_set(op->ptr, "x", event->x);
564         RNA_int_set(op->ptr, "y", event->y);
565
566         if(!area_move_init(C, op)) 
567                 return OPERATOR_PASS_THROUGH;
568         
569         /* add temp handler */
570         WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
571         
572         return OPERATOR_RUNNING_MODAL;
573 }
574
575 static int area_move_cancel(bContext *C, wmOperator *op)
576 {
577
578         RNA_int_set(op->ptr, "delta", 0);
579         area_move_apply(C, op);
580         area_move_exit(C, op);
581
582         return OPERATOR_CANCELLED;
583 }
584
585 /* modal callback for while moving edges */
586 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
587 {
588         sAreaMoveData *md;
589         int delta, x, y;
590
591         md= op->customdata;
592
593         x= RNA_int_get(op->ptr, "x");
594         y= RNA_int_get(op->ptr, "y");
595
596         /* execute the events */
597         switch(event->type) {
598                 case MOUSEMOVE:
599                         delta= (md->dir == 'v')? event->x - x: event->y - y;
600                         RNA_int_set(op->ptr, "delta", delta);
601
602                         area_move_apply(C, op);
603                         break;
604                         
605                 case LEFTMOUSE:
606                         if(event->val==0) {
607                                 area_move_exit(C, op);
608                                 return OPERATOR_FINISHED;
609                         }
610                         break;
611                         
612                 case ESCKEY:
613                         return area_move_cancel(C, op);
614         }
615         
616         return OPERATOR_RUNNING_MODAL;
617 }
618
619 void SCREEN_OT_area_move(wmOperatorType *ot)
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         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
634         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
635         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
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, "direction");
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, "factor");
759         dir= RNA_enum_get(op->ptr, "direction");
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, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
822                 }
823                 else {
824                         dir= 'v';
825                         RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
826                 }
827                 RNA_enum_set(op->ptr, "direction", 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, "direction");
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, "factor", 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         ot->name = "Split area";
929         ot->idname = "SCREEN_OT_area_split";
930         
931         ot->exec= area_split_exec;
932         ot->invoke= area_split_invoke;
933         ot->modal= area_split_modal;
934         
935         ot->poll= ED_operator_areaactive;
936         ot->flag= OPTYPE_REGISTER;
937         
938         /* rna */
939         RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
940         RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
941 }
942
943 /* ************** frame change operator ***************************** */
944
945
946 /* function to be called outside UI context, or for redo */
947 static int frame_offset_exec(bContext *C, wmOperator *op)
948 {
949         int delta;
950
951         delta = RNA_int_get(op->ptr, "delta");
952
953         CTX_data_scene(C)->r.cfra += delta;
954         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
955
956         return OPERATOR_FINISHED;
957 }
958
959 void SCREEN_OT_frame_offset(wmOperatorType *ot)
960 {
961         ot->name = "Frame Offset";
962         ot->idname = "SCREEN_OT_frame_offset";
963
964         ot->exec= frame_offset_exec;
965
966         ot->poll= ED_operator_screenactive;
967         ot->flag= OPTYPE_REGISTER;
968
969         /* rna */
970         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
971 }
972
973 /* ************** switch screen operator ***************************** */
974
975
976 /* function to be called outside UI context, or for redo */
977 static int screen_set_exec(bContext *C, wmOperator *op)
978 {
979         bScreen *screen= CTX_wm_screen(C);
980         int delta= RNA_int_get(op->ptr, "delta");
981         
982         /* this screen is 'fake', solve later XXX */
983         if(CTX_wm_area(C)->full)
984                 return OPERATOR_CANCELLED;
985         
986         if(delta==1) {
987                 screen= screen->id.next;
988                 if(screen==NULL) screen= CTX_data_main(C)->screen.first;
989         }
990         else if(delta== -1) {
991                 screen= screen->id.prev;
992                 if(screen==NULL) screen= CTX_data_main(C)->screen.last;
993         }
994         else {
995                 screen= NULL;
996         }
997         
998         if(screen) {
999                 ed_screen_set(C, screen);
1000                 return OPERATOR_FINISHED;
1001         }
1002         return OPERATOR_CANCELLED;
1003 }
1004
1005 void SCREEN_OT_screen_set(wmOperatorType *ot)
1006 {
1007         ot->name = "Set Screen";
1008         ot->idname = "SCREEN_OT_screen_set";
1009         
1010         ot->exec= screen_set_exec;
1011         ot->poll= ED_operator_screenactive;
1012         
1013         /* rna */
1014         RNA_def_pointer_runtime(ot->srna, "screen", &RNA_Screen, "Screen", "");
1015         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1016 }
1017
1018 /* ************** screen full-area operator ***************************** */
1019
1020
1021 /* function to be called outside UI context, or for redo */
1022 static int screen_full_area_exec(bContext *C, wmOperator *op)
1023 {
1024         ed_screen_fullarea(C);
1025         return OPERATOR_FINISHED;
1026 }
1027
1028 void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1029 {
1030         ot->name = "Toggle Full Area in Screen";
1031         ot->idname = "SCREEN_OT_screen_full_area";
1032         
1033         ot->exec= screen_full_area_exec;
1034         ot->poll= ED_operator_screenactive;
1035 }
1036
1037
1038
1039 /* ************** join area operator ********************************************** */
1040
1041 /* operator state vars used:  
1042                         x1, y1     mouse coord in first area, which will disappear
1043                         x2, y2     mouse coord in 2nd area, which will become joined
1044
1045 functions:
1046
1047    init()   find edge based on state vars 
1048                         test if the edge divides two areas, 
1049                         store active and nonactive area,
1050             
1051    apply()  do the actual join
1052
1053    exit()       cleanup, send notifier
1054
1055 callbacks:
1056
1057    exec()       calls init, apply, exit 
1058    
1059    invoke() sets mouse coords in x,y
1060             call init()
1061             add modal handler
1062
1063    modal()      accept modal events while doing it
1064                         call apply() with active window and nonactive window
1065             call exit() and remove handler when LMB confirm
1066
1067 */
1068
1069 typedef struct sAreaJoinData
1070 {
1071         ScrArea *sa1;   /* first area to be considered */
1072         ScrArea *sa2;   /* second area to be considered */
1073         ScrArea *scr;   /* designed for removal */
1074
1075 } sAreaJoinData;
1076
1077
1078 /* validate selection inside screen, set variables OK */
1079 /* return 0: init failed */
1080 /* XXX todo: find edge based on (x,y) and set other area? */
1081 static int area_join_init(bContext *C, wmOperator *op)
1082 {
1083         ScrArea *sa1, *sa2;
1084         sAreaJoinData* jd= NULL;
1085         int x1, y1;
1086         int x2, y2;
1087
1088         /* required properties, make negative to get return 0 if not set by caller */
1089         x1= RNA_int_get(op->ptr, "x1");
1090         y1= RNA_int_get(op->ptr, "y1");
1091         x2= RNA_int_get(op->ptr, "x2");
1092         y2= RNA_int_get(op->ptr, "y2");
1093         
1094         sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1095         sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1096         if(sa1==NULL || sa2==NULL || sa1==sa2)
1097                 return 0;
1098
1099         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1100                 
1101         jd->sa1 = sa1;
1102         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1103         jd->sa2 = sa2;
1104         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1105         
1106         op->customdata= jd;
1107         
1108         return 1;
1109 }
1110
1111 /* apply the join of the areas (space types) */
1112 static int area_join_apply(bContext *C, wmOperator *op)
1113 {
1114         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1115         if (!jd) return 0;
1116
1117         if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1118                 return 0;
1119         }
1120         if (CTX_wm_area(C) == jd->sa2) {
1121                 CTX_wm_area_set(C, NULL);
1122                 CTX_wm_region_set(C, NULL);
1123         }
1124
1125         return 1;
1126 }
1127
1128 /* finish operation */
1129 static void area_join_exit(bContext *C, wmOperator *op)
1130 {
1131         if (op->customdata) {
1132                 MEM_freeN(op->customdata);
1133                 op->customdata = NULL;
1134         }
1135
1136         /* this makes sure aligned edges will result in aligned grabbing */
1137         removedouble_scredges(CTX_wm_screen(C));
1138         removenotused_scredges(CTX_wm_screen(C));
1139         removenotused_scrverts(CTX_wm_screen(C));
1140 }
1141
1142 static int area_join_exec(bContext *C, wmOperator *op)
1143 {
1144         if(!area_join_init(C, op)) 
1145                 return OPERATOR_CANCELLED;
1146         
1147         area_join_apply(C, op);
1148         area_join_exit(C, op);
1149
1150         return OPERATOR_FINISHED;
1151 }
1152
1153 /* interaction callback */
1154 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1155 {
1156
1157         if(event->type==EVT_ACTIONZONE) {
1158                 sActionzoneData *sad= event->customdata;
1159                 
1160                 /* verify *sad itself */
1161                 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1162                         return OPERATOR_PASS_THROUGH;
1163                 
1164                 /* is this our *sad? if areas equal it should be passed on */
1165                 if(sad->sa1==sad->sa2)
1166                         return OPERATOR_PASS_THROUGH;
1167                 
1168                 /* prepare operator state vars */
1169                 RNA_int_set(op->ptr, "x1", sad->x);
1170                 RNA_int_set(op->ptr, "y1", sad->y);
1171                 RNA_int_set(op->ptr, "x2", event->x);
1172                 RNA_int_set(op->ptr, "y2", event->y);
1173
1174                 if(!area_join_init(C, op)) 
1175                         return OPERATOR_PASS_THROUGH;
1176         
1177                 /* add temp handler */
1178                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1179         
1180                 return OPERATOR_RUNNING_MODAL;
1181         }
1182         
1183         return OPERATOR_PASS_THROUGH;
1184 }
1185
1186 static int area_join_cancel(bContext *C, wmOperator *op)
1187 {
1188         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1189
1190         if (jd->sa1) {
1191                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1192                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1193         }
1194         if (jd->sa2) {
1195                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1196                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1197         }
1198
1199         WM_event_add_notifier(C, NC_WINDOW, NULL);
1200         
1201         area_join_exit(C, op);
1202
1203         return OPERATOR_CANCELLED;
1204 }
1205
1206 /* modal callback while selecting area (space) that will be removed */
1207 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1208 {
1209         bScreen *sc= CTX_wm_screen(C);
1210         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1211         
1212         /* execute the events */
1213         switch(event->type) {
1214                         
1215                 case MOUSEMOVE: 
1216                         {
1217                                 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1218                                 int dir;
1219                                 
1220                                 if (sa) {                                       
1221                                         if (jd->sa1 != sa) {
1222                                                 dir = area_getorientation(sc, jd->sa1, sa);
1223                                                 if (dir >= 0) {
1224                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1225                                                         jd->sa2 = sa;
1226                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1227                                                 } 
1228                                                 else {
1229                                                         /* we are not bordering on the previously selected area 
1230                                                            we check if area has common border with the one marked for removal
1231                                                            in this case we can swap areas.
1232                                                         */
1233                                                         dir = area_getorientation(sc, sa, jd->sa2);
1234                                                         if (dir >= 0) {
1235                                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1236                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1237                                                                 jd->sa1 = jd->sa2;
1238                                                                 jd->sa2 = sa;
1239                                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1240                                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1241                                                         } 
1242                                                         else {
1243                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1244                                                                 jd->sa2 = NULL;
1245                                                         }
1246                                                 }
1247                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1248                                         } 
1249                                         else {
1250                                                 /* we are back in the area previously selected for keeping 
1251                                                  * we swap the areas if possible to allow user to choose */
1252                                                 if (jd->sa2 != NULL) {
1253                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1254                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1255                                                         jd->sa1 = jd->sa2;
1256                                                         jd->sa2 = sa;
1257                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1258                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1259                                                         dir = area_getorientation(sc, jd->sa1, jd->sa2);
1260                                                         if (dir < 0) {
1261                                                                 printf("oops, didn't expect that!\n");
1262                                                         }
1263                                                 } 
1264                                                 else {
1265                                                         dir = area_getorientation(sc, jd->sa1, sa);
1266                                                         if (dir >= 0) {
1267                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1268                                                                 jd->sa2 = sa;
1269                                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1270                                                         }
1271                                                 }
1272                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1273                                         }
1274                                 }
1275                         }
1276                         break;
1277                 case LEFTMOUSE:
1278                         if(event->val==0) {
1279                                 area_join_apply(C, op);
1280                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1281                                 area_join_exit(C, op);
1282                                 return OPERATOR_FINISHED;
1283                         }
1284                         break;
1285                         
1286                 case ESCKEY:
1287                         return area_join_cancel(C, op);
1288         }
1289
1290         return OPERATOR_RUNNING_MODAL;
1291 }
1292
1293 /* Operator for joining two areas (space types) */
1294 void SCREEN_OT_area_join(wmOperatorType *ot)
1295 {
1296         /* identifiers */
1297         ot->name= "Join area";
1298         ot->idname= "SCREEN_OT_area_join";
1299         
1300         /* api callbacks */
1301         ot->exec= area_join_exec;
1302         ot->invoke= area_join_invoke;
1303         ot->modal= area_join_modal;
1304
1305         ot->poll= ED_operator_screenactive;
1306
1307         /* rna */
1308         RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1309         RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1310         RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1311         RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1312 }
1313
1314 /* ************** repeat last operator ***************************** */
1315
1316 static int repeat_last_exec(bContext *C, wmOperator *op)
1317 {
1318         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1319         
1320         if(lastop) {
1321                 if(lastop->type->poll==NULL || lastop->type->poll(C)) {
1322                         printf("repeat %s\n", lastop->type->idname);
1323                         lastop->type->exec(C, lastop);
1324                 }
1325         }
1326         
1327         return OPERATOR_FINISHED;
1328 }
1329
1330 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1331 {
1332         /* identifiers */
1333         ot->name= "Repeat Last";
1334         ot->idname= "SCREEN_OT_repeat_last";
1335         
1336         /* api callbacks */
1337         ot->exec= repeat_last_exec;
1338         
1339         ot->poll= ED_operator_screenactive;
1340         
1341 }
1342
1343 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1344 {
1345         wmWindowManager *wm= CTX_wm_manager(C);
1346         wmOperator *lastop;
1347         int items, i;
1348         char *menu, *p;
1349         
1350         items= BLI_countlist(&wm->operators);
1351         if(items==0)
1352                 return OPERATOR_CANCELLED;
1353         
1354         menu= MEM_callocN(items * OP_MAX_TYPENAME, "string");
1355         
1356         p= menu + sprintf(menu, "%s %%t", op->type->name);
1357         for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1358                 p+= sprintf(p, "|%s %%x%d", lastop->type->name, i);
1359         
1360         uiPupmenuOperator(C, i/20, op, "index", menu);
1361         MEM_freeN(menu);
1362         
1363         return OPERATOR_RUNNING_MODAL;
1364 }
1365
1366 static int repeat_history_exec(bContext *C, wmOperator *op)
1367 {
1368         wmWindowManager *wm= CTX_wm_manager(C);
1369         
1370         op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1371         if(op) {
1372                 /* let's put it as last operator in list */
1373                 BLI_remlink(&wm->operators, op);
1374                 BLI_addtail(&wm->operators, op);
1375                 
1376                 if(op->type->poll==NULL || op->type->poll(C)) {
1377                         printf("repeat %s\n", op->type->idname);
1378                         op->type->exec(C, op);
1379                 }
1380         }
1381                                          
1382         return OPERATOR_FINISHED;
1383 }
1384
1385 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1386 {
1387         /* identifiers */
1388         ot->name= "Repeat History";
1389         ot->idname= "SCREEN_OT_repeat_history";
1390         
1391         /* api callbacks */
1392         ot->invoke= repeat_history_invoke;
1393         ot->exec= repeat_history_exec;
1394         
1395         ot->poll= ED_operator_screenactive;
1396         
1397         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1398 }
1399
1400 /* ************** region split operator ***************************** */
1401
1402 /* insert a region in the area region list */
1403 static int region_split_exec(bContext *C, wmOperator *op)
1404 {
1405         ScrArea *sa= CTX_wm_area(C);
1406         ARegion *ar= CTX_wm_region(C);
1407         ARegion *newar= BKE_area_region_copy(ar);
1408         int dir= RNA_enum_get(op->ptr, "direction");
1409         
1410         BLI_insertlinkafter(&sa->regionbase, CTX_wm_region(C), newar);
1411         
1412         newar->alignment= ar->alignment;
1413         
1414         if(dir=='h')
1415                 ar->alignment= RGN_ALIGN_HSPLIT;
1416         else
1417                 ar->alignment= RGN_ALIGN_VSPLIT;
1418         
1419         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1420         
1421         return OPERATOR_FINISHED;
1422 }
1423
1424 void SCREEN_OT_region_split(wmOperatorType *ot)
1425 {
1426         /* identifiers */
1427         ot->name= "Split Region";
1428         ot->idname= "SCREEN_OT_region_split";
1429         
1430         /* api callbacks */
1431         ot->invoke= WM_operator_confirm;
1432         ot->exec= region_split_exec;
1433         ot->poll= ED_operator_areaactive;
1434         
1435         RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1436 }
1437
1438 /* ************** region flip operator ***************************** */
1439
1440 /* flip a region alignment */
1441 static int region_flip_exec(bContext *C, wmOperator *op)
1442 {
1443         ARegion *ar= CTX_wm_region(C);
1444
1445         if(ar->alignment==RGN_ALIGN_TOP)
1446                 ar->alignment= RGN_ALIGN_BOTTOM;
1447         else if(ar->alignment==RGN_ALIGN_BOTTOM)
1448                 ar->alignment= RGN_ALIGN_TOP;
1449         else if(ar->alignment==RGN_ALIGN_LEFT)
1450                 ar->alignment= RGN_ALIGN_RIGHT;
1451         else if(ar->alignment==RGN_ALIGN_RIGHT)
1452                 ar->alignment= RGN_ALIGN_LEFT;
1453         
1454         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1455         
1456         return OPERATOR_FINISHED;
1457 }
1458
1459 void SCREEN_OT_region_flip(wmOperatorType *ot)
1460 {
1461         /* identifiers */
1462         ot->name= "Flip Region";
1463         ot->idname= "SCREEN_OT_region_flip";
1464         
1465         /* api callbacks */
1466         ot->invoke= WM_operator_confirm;
1467         ot->exec= region_flip_exec;
1468         
1469         ot->poll= ED_operator_areaactive;
1470 }
1471
1472 /* ****************** anim player, typically with timer ***************** */
1473
1474 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
1475 {
1476         bScreen *screen= CTX_wm_screen(C);
1477         
1478         if(screen->animtimer==event->customdata) {
1479                 Scene *scene= CTX_data_scene(C);
1480                 
1481                 scene->r.cfra++;
1482                 
1483                 if (scene->r.psfra) {
1484                         if(scene->r.cfra > scene->r.pefra)
1485                                 scene->r.cfra= scene->r.psfra;
1486                 }
1487                 else {
1488                         if(scene->r.cfra > scene->r.efra)
1489                                 scene->r.cfra= scene->r.sfra;
1490                 }
1491
1492                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1493                 
1494                 return OPERATOR_FINISHED;
1495         }
1496         return OPERATOR_PASS_THROUGH;
1497 }
1498
1499 void SCREEN_OT_animation_play(wmOperatorType *ot)
1500 {
1501         /* identifiers */
1502         ot->name= "Animation player";
1503         ot->idname= "SCREEN_OT_animation_play";
1504         
1505         /* api callbacks */
1506         ot->invoke= screen_animation_play;
1507         
1508         ot->poll= ED_operator_screenactive;
1509         
1510 }
1511
1512 /* ************** border select operator (template) ***************************** */
1513
1514 /* operator state vars used: (added by default WM callbacks)   
1515         xmin, ymin     
1516         xmax, ymax     
1517
1518         customdata: the wmGesture pointer
1519
1520 callbacks:
1521
1522         exec()  has to be filled in by user
1523
1524         invoke() default WM function
1525                          adds modal handler
1526
1527         modal() default WM function 
1528                         accept modal events while doing it, calls exec(), handles ESC and border drawing
1529         
1530         poll()  has to be filled in by user for context
1531 */
1532 #if 0
1533 static int border_select_do(bContext *C, wmOperator *op)
1534 {
1535         int event_type= RNA_int_get(op->ptr, "event_type");
1536         
1537         if(event_type==LEFTMOUSE)
1538                 printf("border select do select\n");
1539         else if(event_type==RIGHTMOUSE)
1540                 printf("border select deselect\n");
1541         else 
1542                 printf("border select do something\n");
1543         
1544         return 1;
1545 }
1546
1547 void SCREEN_OT_border_select(wmOperatorType *ot)
1548 {
1549         /* identifiers */
1550         ot->name= "Border select";
1551         ot->idname= "SCREEN_OT_border_select";
1552         
1553         /* api callbacks */
1554         ot->exec= border_select_do;
1555         ot->invoke= WM_border_select_invoke;
1556         ot->modal= WM_border_select_modal;
1557         
1558         ot->poll= ED_operator_areaactive;
1559         
1560         /* rna */
1561         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1562         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1563         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1564         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1565         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1566
1567 }
1568 #endif
1569
1570 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
1571
1572 /* called in spacetypes.c */
1573 void ED_operatortypes_screen(void)
1574 {
1575         /* generic UI stuff */
1576         WM_operatortype_append(SCREEN_OT_actionzone);
1577         WM_operatortype_append(SCREEN_OT_repeat_last);
1578         WM_operatortype_append(SCREEN_OT_repeat_history);
1579         
1580         /* screen tools */
1581         WM_operatortype_append(SCREEN_OT_area_move);
1582         WM_operatortype_append(SCREEN_OT_area_split);
1583         WM_operatortype_append(SCREEN_OT_area_join);
1584         WM_operatortype_append(SCREEN_OT_area_rip);
1585         WM_operatortype_append(SCREEN_OT_region_split);
1586         WM_operatortype_append(SCREEN_OT_region_flip);
1587         WM_operatortype_append(SCREEN_OT_screen_set);
1588         WM_operatortype_append(SCREEN_OT_screen_full_area);
1589         
1590         /*frame changes*/
1591         WM_operatortype_append(SCREEN_OT_frame_offset);
1592         WM_operatortype_append(SCREEN_OT_animation_play);
1593         
1594         /* tools shared by more space types */
1595         WM_operatortype_append(ED_OT_undo);
1596         WM_operatortype_append(ED_OT_redo);
1597         ED_marker_operatortypes();      
1598         
1599 }
1600
1601 /* called in spacetypes.c */
1602 void ED_keymap_screen(wmWindowManager *wm)
1603 {
1604         ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
1605         
1606         WM_keymap_verify_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0);
1607         
1608         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
1609         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE, 0, 0, 0);
1610         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE, 0, 0, 0);
1611         WM_keymap_verify_item(keymap, "SCREEN_OT_area_rip", RKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
1612         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
1613         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
1614         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
1615         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
1616         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
1617
1618          /* tests */
1619         RNA_enum_set(WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0)->ptr, "direction", 'h');
1620         RNA_enum_set(WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0)->ptr, "direction", 'v');
1621         
1622         /*frame offsets*/
1623         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", TIMER0, KM_ANY, KM_ANY, 0);
1624         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
1625         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
1626         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
1627         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
1628
1629         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
1630         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
1631         WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
1632
1633         /* undo */
1634         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
1635         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
1636         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
1637         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
1638                                                   
1639         /* screen level global keymaps */
1640         // err...
1641         ED_marker_keymap(wm);
1642 }
1643