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