2.50: svn merge https://svn.blender.org/svnroot/bf-blender/trunk/blender -r17853...
[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 }
1038
1039
1040
1041 /* ************** join area operator ********************************************** */
1042
1043 /* operator state vars used:  
1044                         x1, y1     mouse coord in first area, which will disappear
1045                         x2, y2     mouse coord in 2nd area, which will become joined
1046
1047 functions:
1048
1049    init()   find edge based on state vars 
1050                         test if the edge divides two areas, 
1051                         store active and nonactive area,
1052             
1053    apply()  do the actual join
1054
1055    exit()       cleanup, send notifier
1056
1057 callbacks:
1058
1059    exec()       calls init, apply, exit 
1060    
1061    invoke() sets mouse coords in x,y
1062             call init()
1063             add modal handler
1064
1065    modal()      accept modal events while doing it
1066                         call apply() with active window and nonactive window
1067             call exit() and remove handler when LMB confirm
1068
1069 */
1070
1071 typedef struct sAreaJoinData
1072 {
1073         ScrArea *sa1;   /* first area to be considered */
1074         ScrArea *sa2;   /* second area to be considered */
1075         ScrArea *scr;   /* designed for removal */
1076
1077 } sAreaJoinData;
1078
1079
1080 /* validate selection inside screen, set variables OK */
1081 /* return 0: init failed */
1082 /* XXX todo: find edge based on (x,y) and set other area? */
1083 static int area_join_init(bContext *C, wmOperator *op)
1084 {
1085         ScrArea *sa1, *sa2;
1086         sAreaJoinData* jd= NULL;
1087         int x1, y1;
1088         int x2, y2;
1089
1090         /* required properties, make negative to get return 0 if not set by caller */
1091         x1= RNA_int_get(op->ptr, "x1");
1092         y1= RNA_int_get(op->ptr, "y1");
1093         x2= RNA_int_get(op->ptr, "x2");
1094         y2= RNA_int_get(op->ptr, "y2");
1095         
1096         sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1097         sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1098         if(sa1==NULL || sa2==NULL || sa1==sa2)
1099                 return 0;
1100
1101         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1102                 
1103         jd->sa1 = sa1;
1104         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1105         jd->sa2 = sa2;
1106         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1107         
1108         op->customdata= jd;
1109         
1110         return 1;
1111 }
1112
1113 /* apply the join of the areas (space types) */
1114 static int area_join_apply(bContext *C, wmOperator *op)
1115 {
1116         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1117         if (!jd) return 0;
1118
1119         if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1120                 return 0;
1121         }
1122         if (CTX_wm_area(C) == jd->sa2) {
1123                 CTX_wm_area_set(C, NULL);
1124                 CTX_wm_region_set(C, NULL);
1125         }
1126
1127         return 1;
1128 }
1129
1130 /* finish operation */
1131 static void area_join_exit(bContext *C, wmOperator *op)
1132 {
1133         if (op->customdata) {
1134                 MEM_freeN(op->customdata);
1135                 op->customdata = NULL;
1136         }
1137
1138         /* this makes sure aligned edges will result in aligned grabbing */
1139         removedouble_scredges(CTX_wm_screen(C));
1140         removenotused_scredges(CTX_wm_screen(C));
1141         removenotused_scrverts(CTX_wm_screen(C));
1142 }
1143
1144 static int area_join_exec(bContext *C, wmOperator *op)
1145 {
1146         if(!area_join_init(C, op)) 
1147                 return OPERATOR_CANCELLED;
1148         
1149         area_join_apply(C, op);
1150         area_join_exit(C, op);
1151
1152         return OPERATOR_FINISHED;
1153 }
1154
1155 /* interaction callback */
1156 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1157 {
1158
1159         if(event->type==EVT_ACTIONZONE) {
1160                 sActionzoneData *sad= event->customdata;
1161                 
1162                 /* verify *sad itself */
1163                 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1164                         return OPERATOR_PASS_THROUGH;
1165                 
1166                 /* is this our *sad? if areas equal it should be passed on */
1167                 if(sad->sa1==sad->sa2)
1168                         return OPERATOR_PASS_THROUGH;
1169                 
1170                 /* prepare operator state vars */
1171                 RNA_int_set(op->ptr, "x1", sad->x);
1172                 RNA_int_set(op->ptr, "y1", sad->y);
1173                 RNA_int_set(op->ptr, "x2", event->x);
1174                 RNA_int_set(op->ptr, "y2", event->y);
1175
1176                 if(!area_join_init(C, op)) 
1177                         return OPERATOR_PASS_THROUGH;
1178         
1179                 /* add temp handler */
1180                 WM_event_add_modal_handler(C, &CTX_wm_window(C)->handlers, op);
1181         
1182                 return OPERATOR_RUNNING_MODAL;
1183         }
1184         
1185         return OPERATOR_PASS_THROUGH;
1186 }
1187
1188 static int area_join_cancel(bContext *C, wmOperator *op)
1189 {
1190         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1191
1192         if (jd->sa1) {
1193                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1194                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1195         }
1196         if (jd->sa2) {
1197                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1198                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1199         }
1200
1201         WM_event_add_notifier(C, NC_WINDOW, NULL);
1202         
1203         area_join_exit(C, op);
1204
1205         return OPERATOR_CANCELLED;
1206 }
1207
1208 /* modal callback while selecting area (space) that will be removed */
1209 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1210 {
1211         bScreen *sc= CTX_wm_screen(C);
1212         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1213         
1214         /* execute the events */
1215         switch(event->type) {
1216                         
1217                 case MOUSEMOVE: 
1218                         {
1219                                 ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1220                                 int dir;
1221                                 
1222                                 if (sa) {                                       
1223                                         if (jd->sa1 != sa) {
1224                                                 dir = area_getorientation(sc, jd->sa1, sa);
1225                                                 if (dir >= 0) {
1226                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1227                                                         jd->sa2 = sa;
1228                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1229                                                 } 
1230                                                 else {
1231                                                         /* we are not bordering on the previously selected area 
1232                                                            we check if area has common border with the one marked for removal
1233                                                            in this case we can swap areas.
1234                                                         */
1235                                                         dir = area_getorientation(sc, sa, jd->sa2);
1236                                                         if (dir >= 0) {
1237                                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1238                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1239                                                                 jd->sa1 = jd->sa2;
1240                                                                 jd->sa2 = sa;
1241                                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1242                                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1243                                                         } 
1244                                                         else {
1245                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1246                                                                 jd->sa2 = NULL;
1247                                                         }
1248                                                 }
1249                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1250                                         } 
1251                                         else {
1252                                                 /* we are back in the area previously selected for keeping 
1253                                                  * we swap the areas if possible to allow user to choose */
1254                                                 if (jd->sa2 != NULL) {
1255                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1256                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1257                                                         jd->sa1 = jd->sa2;
1258                                                         jd->sa2 = sa;
1259                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1260                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1261                                                         dir = area_getorientation(sc, jd->sa1, jd->sa2);
1262                                                         if (dir < 0) {
1263                                                                 printf("oops, didn't expect that!\n");
1264                                                         }
1265                                                 } 
1266                                                 else {
1267                                                         dir = area_getorientation(sc, jd->sa1, sa);
1268                                                         if (dir >= 0) {
1269                                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1270                                                                 jd->sa2 = sa;
1271                                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1272                                                         }
1273                                                 }
1274                                                 WM_event_add_notifier(C, NC_WINDOW, NULL);
1275                                         }
1276                                 }
1277                         }
1278                         break;
1279                 case LEFTMOUSE:
1280                         if(event->val==0) {
1281                                 area_join_apply(C, op);
1282                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1283                                 area_join_exit(C, op);
1284                                 return OPERATOR_FINISHED;
1285                         }
1286                         break;
1287                         
1288                 case ESCKEY:
1289                         return area_join_cancel(C, op);
1290         }
1291
1292         return OPERATOR_RUNNING_MODAL;
1293 }
1294
1295 /* Operator for joining two areas (space types) */
1296 void SCREEN_OT_area_join(wmOperatorType *ot)
1297 {
1298         /* identifiers */
1299         ot->name= "Join area";
1300         ot->idname= "SCREEN_OT_area_join";
1301         
1302         /* api callbacks */
1303         ot->exec= area_join_exec;
1304         ot->invoke= area_join_invoke;
1305         ot->modal= area_join_modal;
1306
1307         ot->poll= ED_operator_screenactive;
1308
1309         /* rna */
1310         RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
1311         RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
1312         RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
1313         RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
1314 }
1315
1316 /* ************** repeat last operator ***************************** */
1317
1318 static int repeat_last_exec(bContext *C, wmOperator *op)
1319 {
1320         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
1321         
1322         if(lastop) {
1323                 if(lastop->type->poll==NULL || lastop->type->poll(C)) {
1324                         printf("repeat %s\n", lastop->type->idname);
1325                         lastop->type->exec(C, lastop);
1326                 }
1327         }
1328         
1329         return OPERATOR_FINISHED;
1330 }
1331
1332 void SCREEN_OT_repeat_last(wmOperatorType *ot)
1333 {
1334         /* identifiers */
1335         ot->name= "Repeat Last";
1336         ot->idname= "SCREEN_OT_repeat_last";
1337         
1338         /* api callbacks */
1339         ot->exec= repeat_last_exec;
1340         
1341         ot->poll= ED_operator_screenactive;
1342         
1343 }
1344
1345 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
1346 {
1347         wmWindowManager *wm= CTX_wm_manager(C);
1348         wmOperator *lastop;
1349         int items, i;
1350         char *menu, *p;
1351         
1352         items= BLI_countlist(&wm->operators);
1353         if(items==0)
1354                 return OPERATOR_CANCELLED;
1355         
1356         menu= MEM_callocN(items * OP_MAX_TYPENAME, "string");
1357         
1358         p= menu + sprintf(menu, "%s %%t", op->type->name);
1359         for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
1360                 p+= sprintf(p, "|%s %%x%d", lastop->type->name, i);
1361         
1362         uiPupmenuOperator(C, i/20, op, "index", menu);
1363         MEM_freeN(menu);
1364         
1365         return OPERATOR_RUNNING_MODAL;
1366 }
1367
1368 static int repeat_history_exec(bContext *C, wmOperator *op)
1369 {
1370         wmWindowManager *wm= CTX_wm_manager(C);
1371         
1372         op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
1373         if(op) {
1374                 /* let's put it as last operator in list */
1375                 BLI_remlink(&wm->operators, op);
1376                 BLI_addtail(&wm->operators, op);
1377                 
1378                 if(op->type->poll==NULL || op->type->poll(C)) {
1379                         printf("repeat %s\n", op->type->idname);
1380                         op->type->exec(C, op);
1381                 }
1382         }
1383                                          
1384         return OPERATOR_FINISHED;
1385 }
1386
1387 void SCREEN_OT_repeat_history(wmOperatorType *ot)
1388 {
1389         /* identifiers */
1390         ot->name= "Repeat History";
1391         ot->idname= "SCREEN_OT_repeat_history";
1392         
1393         /* api callbacks */
1394         ot->invoke= repeat_history_invoke;
1395         ot->exec= repeat_history_exec;
1396         
1397         ot->poll= ED_operator_screenactive;
1398         
1399         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
1400 }
1401
1402 /* ************** region split operator ***************************** */
1403
1404 /* insert a region in the area region list */
1405 static int region_split_exec(bContext *C, wmOperator *op)
1406 {
1407         ARegion *ar= CTX_wm_region(C);
1408         
1409         if(ar->regiontype==RGN_TYPE_HEADER)
1410                 BKE_report(op->reports, RPT_ERROR, "Cannot split header");
1411         else if(ar->alignment==RGN_ALIGN_QSPLIT)
1412                 BKE_report(op->reports, RPT_ERROR, "Cannot split further");
1413         else {
1414                 ScrArea *sa= CTX_wm_area(C);
1415                 ARegion *newar= BKE_area_region_copy(sa->type, ar);
1416                 int dir= RNA_enum_get(op->ptr, "type");
1417         
1418                 BLI_insertlinkafter(&sa->regionbase, ar, newar);
1419                 
1420                 newar->alignment= ar->alignment;
1421                 
1422                 if(dir=='h')
1423                         ar->alignment= RGN_ALIGN_HSPLIT;
1424                 else
1425                         ar->alignment= RGN_ALIGN_VSPLIT;
1426                 
1427                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1428         }
1429         
1430         return OPERATOR_FINISHED;
1431 }
1432
1433 void SCREEN_OT_region_split(wmOperatorType *ot)
1434 {
1435         /* identifiers */
1436         ot->name= "Split Region";
1437         ot->idname= "SCREEN_OT_region_split";
1438         
1439         /* api callbacks */
1440         ot->invoke= WM_menu_invoke;
1441         ot->exec= region_split_exec;
1442         ot->poll= ED_operator_areaactive;
1443         
1444         RNA_def_enum(ot->srna, "type", prop_direction_items, 'h', "Direction", "");
1445 }
1446
1447 /* ************** region four-split operator ***************************** */
1448
1449 /* insert a region in the area region list */
1450 static int region_foursplit_exec(bContext *C, wmOperator *op)
1451 {
1452         ARegion *ar= CTX_wm_region(C);
1453         
1454         /* some rules... */
1455         if(ar->regiontype!=RGN_TYPE_WINDOW)
1456                 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
1457         else if(ar->alignment==RGN_ALIGN_QSPLIT) {
1458                 ScrArea *sa= CTX_wm_area(C);
1459                 ARegion *arn;
1460                 
1461                 /* keep current region */
1462                 ar->alignment= 0;
1463                 
1464                 if(sa->spacetype==SPACE_VIEW3D) {
1465                         RegionView3D *rv3d= ar->regiondata;
1466                         rv3d->viewlock= 0;
1467                 }
1468                 
1469                 for(ar= sa->regionbase.first; ar; ar= arn) {
1470                         arn= ar->next;
1471                         if(ar->alignment==RGN_ALIGN_QSPLIT) {
1472                                 ED_region_exit(C, ar);
1473                                 BKE_area_region_free(sa->type, ar);
1474                                 BLI_remlink(&sa->regionbase, ar);
1475                                 MEM_freeN(ar);
1476                         }
1477                 }
1478                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1479         }
1480         else if(ar->next)
1481                 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
1482         else {
1483                 ScrArea *sa= CTX_wm_area(C);
1484                 ARegion *newar;
1485                 int count;
1486                 
1487                 ar->alignment= RGN_ALIGN_QSPLIT;
1488                 
1489                 for(count=0; count<3; count++) {
1490                         newar= BKE_area_region_copy(sa->type, ar);
1491                         BLI_addtail(&sa->regionbase, newar);
1492                 }
1493                 
1494                 /* lock views and set them */
1495                 if(sa->spacetype==SPACE_VIEW3D) {
1496                         RegionView3D *rv3d;
1497                         
1498                         rv3d= ar->regiondata;
1499                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_FRONT; rv3d->persp= V3D_ORTHO;
1500                         
1501                         ar= ar->next;
1502                         rv3d= ar->regiondata;
1503                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_TOP; rv3d->persp= V3D_ORTHO;
1504                         
1505                         ar= ar->next;
1506                         rv3d= ar->regiondata;
1507                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= V3D_VIEW_RIGHT; rv3d->persp= V3D_ORTHO;
1508                         
1509                         ar= ar->next;
1510                         rv3d= ar->regiondata;
1511                         rv3d->view= V3D_VIEW_CAMERA; rv3d->persp= V3D_CAMOB;
1512                 }
1513                 
1514                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1515         }
1516         
1517         
1518         return OPERATOR_FINISHED;
1519 }
1520
1521 void SCREEN_OT_region_foursplit(wmOperatorType *ot)
1522 {
1523         /* identifiers */
1524         ot->name= "Split Region in 4 Parts";
1525         ot->idname= "SCREEN_OT_region_foursplit";
1526         
1527         /* api callbacks */
1528         ot->invoke= WM_operator_confirm;
1529         ot->exec= region_foursplit_exec;
1530         ot->poll= ED_operator_areaactive;
1531 }
1532
1533
1534
1535 /* ************** region flip operator ***************************** */
1536
1537 /* flip a region alignment */
1538 static int region_flip_exec(bContext *C, wmOperator *op)
1539 {
1540         ARegion *ar= CTX_wm_region(C);
1541
1542         if(ar->alignment==RGN_ALIGN_TOP)
1543                 ar->alignment= RGN_ALIGN_BOTTOM;
1544         else if(ar->alignment==RGN_ALIGN_BOTTOM)
1545                 ar->alignment= RGN_ALIGN_TOP;
1546         else if(ar->alignment==RGN_ALIGN_LEFT)
1547                 ar->alignment= RGN_ALIGN_RIGHT;
1548         else if(ar->alignment==RGN_ALIGN_RIGHT)
1549                 ar->alignment= RGN_ALIGN_LEFT;
1550         
1551         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1552         printf("executed region flip\n");
1553         
1554         return OPERATOR_FINISHED;
1555 }
1556
1557 static void testfunc(bContext *C, void *argv, int arg)
1558 {
1559         printf("arg %d\n", arg);
1560 }
1561
1562 static void newlevel1(uiMenuItem *head)
1563 {
1564         uiMenuFunc(head, testfunc, NULL);
1565         
1566         uiMenuItemVal(head, "First", ICON_PROP_ON, 1);
1567         uiMenuItemVal(head, "Second", ICON_PROP_CON, 2);
1568         uiMenuItemVal(head, "Third", ICON_SMOOTHCURVE, 3);
1569         uiMenuItemVal(head, "Fourth", ICON_SHARPCURVE, 4);      
1570 }
1571
1572 static int testing123(bContext *C, wmOperator *op, wmEvent *event)
1573 {
1574         uiMenuItem *head= uiMenuBegin("Hello world");
1575         
1576         uiMenuContext(head, WM_OP_EXEC_DEFAULT);
1577         uiMenuItemO(head, "SCREEN_OT_region_flip", ICON_PROP_ON);
1578         uiMenuItemO(head, "SCREEN_OT_screen_full_area", ICON_PROP_CON);
1579         uiMenuItemO(head, "SCREEN_OT_region_foursplit", ICON_SMOOTHCURVE);
1580         uiMenuLevel(head, "Submenu", newlevel1);
1581         uiMenuItemO(head, "SCREEN_OT_area_rip", ICON_PROP_ON);
1582         
1583         uiMenuEnd(C, head);
1584         
1585         /* this operator is only for a menu, not used further */
1586         return OPERATOR_CANCELLED;
1587 }
1588
1589 void SCREEN_OT_region_flip(wmOperatorType *ot)
1590 {
1591         /* identifiers */
1592         ot->name= "Flip Region";
1593         ot->idname= "SCREEN_OT_region_flip";
1594         
1595         /* api callbacks */
1596         ot->invoke= testing123; // XXX WM_operator_confirm;
1597         ot->exec= region_flip_exec;
1598         
1599         ot->poll= ED_operator_areaactive;
1600         
1601         RNA_def_int(ot->srna, "test", 0, INT_MIN, INT_MAX, "test", "", INT_MIN, INT_MAX);
1602
1603 }
1604
1605 /* ****************** anim player, typically with timer ***************** */
1606
1607 static int screen_animation_play(bContext *C, wmOperator *op, wmEvent *event)
1608 {
1609         bScreen *screen= CTX_wm_screen(C);
1610         
1611         if(screen->animtimer==event->customdata) {
1612                 Scene *scene= CTX_data_scene(C);
1613                 
1614                 scene->r.cfra++;
1615                 
1616                 if (scene->r.psfra) {
1617                         if(scene->r.cfra > scene->r.pefra)
1618                                 scene->r.cfra= scene->r.psfra;
1619                 }
1620                 else {
1621                         if(scene->r.cfra > scene->r.efra)
1622                                 scene->r.cfra= scene->r.sfra;
1623                 }
1624
1625                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1626                 
1627                 return OPERATOR_FINISHED;
1628         }
1629         return OPERATOR_PASS_THROUGH;
1630 }
1631
1632 void SCREEN_OT_animation_play(wmOperatorType *ot)
1633 {
1634         /* identifiers */
1635         ot->name= "Animation player";
1636         ot->idname= "SCREEN_OT_animation_play";
1637         
1638         /* api callbacks */
1639         ot->invoke= screen_animation_play;
1640         
1641         ot->poll= ED_operator_screenactive;
1642         
1643 }
1644
1645 /* ************** border select operator (template) ***************************** */
1646
1647 /* operator state vars used: (added by default WM callbacks)   
1648         xmin, ymin     
1649         xmax, ymax     
1650
1651         customdata: the wmGesture pointer
1652
1653 callbacks:
1654
1655         exec()  has to be filled in by user
1656
1657         invoke() default WM function
1658                          adds modal handler
1659
1660         modal() default WM function 
1661                         accept modal events while doing it, calls exec(), handles ESC and border drawing
1662         
1663         poll()  has to be filled in by user for context
1664 */
1665 #if 0
1666 static int border_select_do(bContext *C, wmOperator *op)
1667 {
1668         int event_type= RNA_int_get(op->ptr, "event_type");
1669         
1670         if(event_type==LEFTMOUSE)
1671                 printf("border select do select\n");
1672         else if(event_type==RIGHTMOUSE)
1673                 printf("border select deselect\n");
1674         else 
1675                 printf("border select do something\n");
1676         
1677         return 1;
1678 }
1679
1680 void SCREEN_OT_border_select(wmOperatorType *ot)
1681 {
1682         /* identifiers */
1683         ot->name= "Border select";
1684         ot->idname= "SCREEN_OT_border_select";
1685         
1686         /* api callbacks */
1687         ot->exec= border_select_do;
1688         ot->invoke= WM_border_select_invoke;
1689         ot->modal= WM_border_select_modal;
1690         
1691         ot->poll= ED_operator_areaactive;
1692         
1693         /* rna */
1694         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
1695         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
1696         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
1697         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
1698         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
1699
1700 }
1701 #endif
1702
1703 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
1704
1705 /* called in spacetypes.c */
1706 void ED_operatortypes_screen(void)
1707 {
1708         /* generic UI stuff */
1709         WM_operatortype_append(SCREEN_OT_actionzone);
1710         WM_operatortype_append(SCREEN_OT_repeat_last);
1711         WM_operatortype_append(SCREEN_OT_repeat_history);
1712         
1713         /* screen tools */
1714         WM_operatortype_append(SCREEN_OT_area_move);
1715         WM_operatortype_append(SCREEN_OT_area_split);
1716         WM_operatortype_append(SCREEN_OT_area_join);
1717         WM_operatortype_append(SCREEN_OT_area_rip);
1718         WM_operatortype_append(SCREEN_OT_region_split);
1719         WM_operatortype_append(SCREEN_OT_region_foursplit);
1720         WM_operatortype_append(SCREEN_OT_region_flip);
1721         WM_operatortype_append(SCREEN_OT_screen_set);
1722         WM_operatortype_append(SCREEN_OT_screen_full_area);
1723         
1724         /*frame changes*/
1725         WM_operatortype_append(SCREEN_OT_frame_offset);
1726         WM_operatortype_append(SCREEN_OT_animation_play);
1727         
1728         /* tools shared by more space types */
1729         WM_operatortype_append(ED_OT_undo);
1730         WM_operatortype_append(ED_OT_redo);
1731         ED_marker_operatortypes();      
1732         
1733 }
1734
1735 /* called in spacetypes.c */
1736 void ED_keymap_screen(wmWindowManager *wm)
1737 {
1738         ListBase *keymap= WM_keymap_listbase(wm, "Screen", 0, 0);
1739         
1740         /* standard timers */
1741         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", TIMER0, KM_ANY, KM_ANY, 0);
1742         
1743         WM_keymap_verify_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0);
1744         
1745         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
1746         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE, 0, 0, 0);
1747         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE, 0, 0, 0);
1748         WM_keymap_verify_item(keymap, "SCREEN_OT_area_rip", RKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
1749         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
1750         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
1751         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
1752         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
1753         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_CTRL, 0);
1754
1755          /* tests */
1756         WM_keymap_add_item(keymap, "SCREEN_OT_region_split", SKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
1757         WM_keymap_add_item(keymap, "SCREEN_OT_region_foursplit", SKEY, KM_PRESS, KM_CTRL|KM_ALT|KM_SHIFT, 0);
1758         
1759         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
1760         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_last", F4KEY, KM_PRESS, 0, 0);
1761         WM_keymap_add_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
1762
1763         /* undo */
1764         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
1765         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
1766         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
1767         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
1768                                                   
1769         /* screen level global keymaps */
1770         // err...
1771         ED_marker_keymap(wm);
1772         
1773         /* frame offsets */
1774         keymap= WM_keymap_listbase(wm, "Frames", 0, 0);
1775         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
1776         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
1777         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
1778         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
1779         
1780 }
1781