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