Fix [#23977] toggle back to object mode not working (outliner issue)
[blender.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 <math.h>
28 #include <string.h>
29
30 #include "MEM_guardedalloc.h"
31
32 #include "BLI_math.h"
33 #include "BLI_blenlib.h"
34 #include "BLI_editVert.h"
35 #include "BLI_dlrbTree.h"
36
37 #include "DNA_armature_types.h"
38 #include "DNA_lattice_types.h"
39 #include "DNA_object_types.h"
40 #include "DNA_curve_types.h"
41 #include "DNA_scene_types.h"
42 #include "DNA_meta_types.h"
43
44 #include "BKE_context.h"
45 #include "BKE_customdata.h"
46 #include "BKE_main.h"
47 #include "BKE_mesh.h"
48 #include "BKE_report.h"
49 #include "BKE_scene.h"
50 #include "BKE_screen.h"
51 #include "BKE_sound.h"
52
53 #include "WM_api.h"
54 #include "WM_types.h"
55
56 #include "ED_util.h"
57 #include "ED_screen.h"
58 #include "ED_object.h"
59 #include "ED_screen_types.h"
60 #include "ED_keyframes_draw.h"
61
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64
65 #include "UI_interface.h"
66
67 #include "wm_window.h"
68
69 #include "screen_intern.h"      /* own module include */
70
71 #define KM_MODAL_CANCEL         1
72 #define KM_MODAL_APPLY          2
73 #define KM_MODAL_STEP10         3
74 #define KM_MODAL_STEP10_OFF     4
75
76 /* ************** Exported Poll tests ********************** */
77
78 int ED_operator_regionactive(bContext *C)
79 {
80         if(CTX_wm_window(C)==NULL) return 0;
81         if(CTX_wm_screen(C)==NULL) return 0;
82         if(CTX_wm_region(C)==NULL) return 0;
83         return 1;
84 }
85
86 int ED_operator_areaactive(bContext *C)
87 {
88         if(CTX_wm_window(C)==NULL) return 0;
89         if(CTX_wm_screen(C)==NULL) return 0;
90         if(CTX_wm_area(C)==NULL) return 0;
91         return 1;
92 }
93
94 int ED_operator_screenactive(bContext *C)
95 {
96         if(CTX_wm_window(C)==NULL) return 0;
97         if(CTX_wm_screen(C)==NULL) return 0;
98         return 1;
99 }
100
101 /* when mouse is over area-edge */
102 int ED_operator_screen_mainwinactive(bContext *C)
103 {
104         if(CTX_wm_window(C)==NULL) return 0;
105         if(CTX_wm_screen(C)==NULL) return 0;
106         if (CTX_wm_screen(C)->subwinactive!=CTX_wm_screen(C)->mainwin) return 0;
107         return 1;
108 }
109
110 int ED_operator_scene_editable(bContext *C)
111 {
112         Scene *scene= CTX_data_scene(C);
113         if(scene && scene->id.lib==NULL)
114                 return 1;
115         return 0;
116 }
117
118 static int ed_spacetype_test(bContext *C, int type)
119 {
120         if(ED_operator_areaactive(C)) {
121                 SpaceLink *sl= (SpaceLink *)CTX_wm_space_data(C);
122                 return sl && (sl->spacetype == type);
123         }
124         return 0;
125 }
126
127 int ED_operator_view3d_active(bContext *C)
128 {
129         return ed_spacetype_test(C, SPACE_VIEW3D);
130 }
131
132 int ED_operator_region_view3d_active(bContext *C)
133 {
134         if(CTX_wm_region_view3d(C))
135                 return TRUE;
136         
137         CTX_wm_operator_poll_msg_set(C, "expected a view3d region");
138         return FALSE;   
139 }
140
141 int ED_operator_timeline_active(bContext *C)
142 {
143         return ed_spacetype_test(C, SPACE_TIME);
144 }
145
146 int ED_operator_outliner_active(bContext *C)
147 {
148         return ed_spacetype_test(C, SPACE_OUTLINER);
149 }
150
151 int ED_operator_outliner_active_no_editobject(bContext *C)
152 {
153         if(ed_spacetype_test(C, SPACE_OUTLINER)) {
154                 Object *ob = ED_object_active_context(C);
155                 Object *obedit= CTX_data_edit_object(C);
156                 if(ob && ob == obedit)
157                         return 0;
158                 else
159                         return 1;
160         }
161         return 0;
162 }
163
164 int ED_operator_file_active(bContext *C)
165 {
166         return ed_spacetype_test(C, SPACE_FILE);
167 }
168
169 int ED_operator_action_active(bContext *C)
170 {
171         return ed_spacetype_test(C, SPACE_ACTION);
172 }
173
174 int ED_operator_buttons_active(bContext *C)
175 {
176         return ed_spacetype_test(C, SPACE_BUTS);
177 }
178
179 int ED_operator_node_active(bContext *C)
180 {
181         SpaceNode *snode= CTX_wm_space_node(C);
182         
183         if(snode && snode->edittree)
184                 return 1;
185         
186         return 0;
187 }
188
189 // XXX rename
190 int ED_operator_ipo_active(bContext *C)
191 {
192         return ed_spacetype_test(C, SPACE_IPO);
193 }
194
195 int ED_operator_sequencer_active(bContext *C)
196 {
197         return ed_spacetype_test(C, SPACE_SEQ);
198 }
199
200 int ED_operator_image_active(bContext *C)
201 {
202         return ed_spacetype_test(C, SPACE_IMAGE);
203 }
204
205 int ED_operator_nla_active(bContext *C)
206 {
207         return ed_spacetype_test(C, SPACE_NLA);
208 }
209
210 int ED_operator_logic_active(bContext *C)
211 {
212         return ed_spacetype_test(C, SPACE_LOGIC);
213 }
214
215 int ED_operator_object_active(bContext *C)
216 {
217         Object *ob = ED_object_active_context(C);
218         return ((ob != NULL) && !(ob->restrictflag & OB_RESTRICT_VIEW));
219 }
220
221 int ED_operator_object_active_editable(bContext *C)
222 {
223         Object *ob = ED_object_active_context(C);
224         return ((ob != NULL) && !(ob->id.lib) && !(ob->restrictflag & OB_RESTRICT_VIEW));
225 }
226
227 int ED_operator_editmesh(bContext *C)
228 {
229         Object *obedit= CTX_data_edit_object(C);
230         if(obedit && obedit->type==OB_MESH)
231                 return NULL != ((Mesh *)obedit->data)->edit_mesh;
232         return 0;
233 }
234
235 int ED_operator_editmesh_view3d(bContext *C)
236 {
237         return ED_operator_editmesh(C) && ED_operator_view3d_active(C);
238 }
239
240 int ED_operator_editmesh_region_view3d(bContext *C)
241 {
242         return ED_operator_editmesh(C) && CTX_wm_region_view3d(C);
243 }
244
245 int ED_operator_editarmature(bContext *C)
246 {
247         Object *obedit= CTX_data_edit_object(C);
248         if(obedit && obedit->type==OB_ARMATURE)
249                 return NULL != ((bArmature *)obedit->data)->edbo;
250         return 0;
251 }
252
253 int ED_operator_posemode(bContext *C)
254 {
255         Object *obact= CTX_data_active_object(C);
256         Object *obedit= CTX_data_edit_object(C);
257         
258         if ((obact != obedit) && (obact) && (obact->type==OB_ARMATURE))
259                 return (obact->mode & OB_MODE_POSE)!=0;
260         
261         return 0;
262 }
263
264
265 int ED_operator_uvedit(bContext *C)
266 {
267         Object *obedit= CTX_data_edit_object(C);
268         EditMesh *em= NULL;
269         
270         if(obedit && obedit->type==OB_MESH)
271                 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
272         
273         if(em && (em->faces.first) && (CustomData_has_layer(&em->fdata, CD_MTFACE))) {
274                 BKE_mesh_end_editmesh(obedit->data, em);
275                 return 1;
276         }
277         
278         if(obedit)
279                 BKE_mesh_end_editmesh(obedit->data, em);
280         return 0;
281 }
282
283 int ED_operator_uvmap(bContext *C)
284 {
285         Object *obedit= CTX_data_edit_object(C);
286         EditMesh *em= NULL;
287         
288         if(obedit && obedit->type==OB_MESH)
289                 em= BKE_mesh_get_editmesh((Mesh *)obedit->data);
290         
291         if(em && (em->faces.first)) {
292                 BKE_mesh_end_editmesh(obedit->data, em);
293                 return 1;
294         }
295         
296         if(obedit)
297                 BKE_mesh_end_editmesh(obedit->data, em);
298         return 0;
299 }
300
301 int ED_operator_editsurfcurve(bContext *C)
302 {
303         Object *obedit= CTX_data_edit_object(C);
304         if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
305                 return NULL != ((Curve *)obedit->data)->editnurb;
306         return 0;
307 }
308
309
310 int ED_operator_editcurve(bContext *C)
311 {
312         Object *obedit= CTX_data_edit_object(C);
313         if(obedit && obedit->type==OB_CURVE)
314                 return NULL != ((Curve *)obedit->data)->editnurb;
315         return 0;
316 }
317
318 int ED_operator_editsurf(bContext *C)
319 {
320         Object *obedit= CTX_data_edit_object(C);
321         if(obedit && obedit->type==OB_SURF)
322                 return NULL != ((Curve *)obedit->data)->editnurb;
323         return 0;
324 }
325
326 int ED_operator_editfont(bContext *C)
327 {
328         Object *obedit= CTX_data_edit_object(C);
329         if(obedit && obedit->type==OB_FONT)
330                 return NULL != ((Curve *)obedit->data)->editfont;
331         return 0;
332 }
333
334 int ED_operator_editlattice(bContext *C)
335 {
336         Object *obedit= CTX_data_edit_object(C);
337         if(obedit && obedit->type==OB_LATTICE)
338                 return NULL != ((Lattice *)obedit->data)->editlatt;
339         return 0;
340 }
341
342 int ED_operator_editmball(bContext *C)
343 {
344         Object *obedit= CTX_data_edit_object(C);
345         if(obedit && obedit->type==OB_MBALL)
346                 return NULL != ((MetaBall *)obedit->data)->editelems;
347         return 0;
348 }
349
350 /* *************************** action zone operator ************************** */
351
352 /* operator state vars used:  
353  none
354  
355  functions:
356  
357  apply() set actionzone event
358  
359  exit() free customdata
360  
361  callbacks:
362  
363  exec() never used
364  
365  invoke() check if in zone  
366  add customdata, put mouseco and area in it
367  add modal handler
368  
369  modal()        accept modal events while doing it
370  call apply() with gesture info, active window, nonactive window
371  call exit() and remove handler when LMB confirm
372  
373  */
374
375 typedef struct sActionzoneData {
376         ScrArea *sa1, *sa2;
377         AZone *az;
378         int x, y, gesture_dir, modifier;
379 } sActionzoneData;
380
381 /* used by other operators too */
382 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
383 {
384         ScrArea *sa= NULL;
385         sa= scr->areabase.first;
386         while(sa) {
387                 if(BLI_in_rcti(&sa->totrct, x, y)) break;
388                 sa= sa->next;
389         }
390         
391         return sa;
392 }
393
394 /* quick poll to save operators to be created and handled */
395 static int actionzone_area_poll(bContext *C)
396 {
397         wmWindow *win= CTX_wm_window(C);
398         ScrArea *sa= CTX_wm_area(C);
399         
400         if(sa && win) {
401                 AZone *az;
402                 int x= win->eventstate->x;
403                 int y= win->eventstate->y;
404                 
405                 for(az= sa->actionzones.first; az; az= az->next)
406                         if(BLI_in_rcti(&az->rect, x, y))
407                                 return 1;
408         }       
409         return 0;
410 }
411
412 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
413 {
414         AZone *az= NULL;
415         
416         for(az= sa->actionzones.first; az; az= az->next) {
417                 if(BLI_in_rcti(&az->rect, x, y)) {
418                         if(az->type == AZONE_AREA) {
419                                 if(isect_point_tri_v2_int(az->x1, az->y1, az->x2, az->y2, x, y)) 
420                                         break;
421                         }
422                         else if(az->type == AZONE_REGION) {
423                                 break;
424                         }
425                 }
426         }
427         
428         return az;
429 }
430
431
432 static void actionzone_exit(bContext *C, wmOperator *op)
433 {
434         if(op->customdata)
435                 MEM_freeN(op->customdata);
436         op->customdata= NULL;
437 }
438
439 /* send EVT_ACTIONZONE event */
440 static void actionzone_apply(bContext *C, wmOperator *op, int type)
441 {
442         wmEvent event;
443         wmWindow *win= CTX_wm_window(C);
444         sActionzoneData *sad= op->customdata;
445         
446         sad->modifier= RNA_int_get(op->ptr, "modifier");
447         
448         event= *(win->eventstate);      /* XXX huh huh? make api call */
449         if(type==AZONE_AREA)
450                 event.type= EVT_ACTIONZONE_AREA;
451         else
452                 event.type= EVT_ACTIONZONE_REGION;
453         event.customdata= op->customdata;
454         event.customdatafree= TRUE;
455         op->customdata= NULL;
456         
457         wm_event_add(win, &event);
458 }
459
460 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
461 {
462         AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
463         sActionzoneData *sad;
464         
465         /* quick escape */
466         if(az==NULL)
467                 return OPERATOR_PASS_THROUGH;
468         
469         /* ok we do the actionzone */
470         sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
471         sad->sa1= CTX_wm_area(C);
472         sad->az= az;
473         sad->x= event->x; sad->y= event->y;
474         
475         /* region azone directly reacts on mouse clicks */
476         if(sad->az->type==AZONE_REGION) {
477                 actionzone_apply(C, op, AZONE_REGION);
478                 actionzone_exit(C, op);
479                 return OPERATOR_FINISHED;
480         }
481         else {
482                 /* add modal handler */
483                 WM_event_add_modal_handler(C, op);
484                 
485                 return OPERATOR_RUNNING_MODAL;
486         }
487 }
488
489
490 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
491 {
492         sActionzoneData *sad= op->customdata;
493         int deltax, deltay;
494         int mindelta= sad->az->type==AZONE_REGION?1:12;
495         
496         switch(event->type) {
497                 case MOUSEMOVE:
498                         /* calculate gesture direction */
499                         deltax= (event->x - sad->x);
500                         deltay= (event->y - sad->y);
501                         
502                         if(deltay > ABS(deltax))
503                                 sad->gesture_dir= 'n';
504                         else if(deltax > ABS(deltay))
505                                 sad->gesture_dir= 'e';
506                         else if(deltay < -ABS(deltax))
507                                 sad->gesture_dir= 's';
508                         else
509                                 sad->gesture_dir= 'w';
510                         
511                         /* gesture is large enough? */
512                         if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
513                                 
514                                 /* second area, for join */
515                                 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
516                                 /* apply sends event */
517                                 actionzone_apply(C, op, sad->az->type);
518                                 actionzone_exit(C, op);
519                                 
520                                 return OPERATOR_FINISHED;
521                         }
522                         break;
523                 case ESCKEY:
524                         actionzone_exit(C, op);
525                         return OPERATOR_CANCELLED;
526                 case LEFTMOUSE:                         
527                         actionzone_exit(C, op);
528                         return OPERATOR_CANCELLED;
529                         
530         }
531         
532         return OPERATOR_RUNNING_MODAL;
533 }
534
535 static void SCREEN_OT_actionzone(wmOperatorType *ot)
536 {
537         /* identifiers */
538         ot->name= "Handle area action zones";
539         ot->description= "Handle area action zones for mouse actions/gestures";
540         ot->idname= "SCREEN_OT_actionzone";
541         
542         ot->invoke= actionzone_invoke;
543         ot->modal= actionzone_modal;
544         ot->poll= actionzone_area_poll;
545         
546         ot->flag= OPTYPE_BLOCKING;
547         
548         RNA_def_int(ot->srna, "modifier", 0, 0, 2, "modifier", "modifier state", 0, 2);
549 }
550
551 /* ************** swap area operator *********************************** */
552
553 /* operator state vars used:  
554  sa1            start area
555  sa2            area to swap with
556  
557  functions:
558  
559  init()   set custom data for operator, based on actionzone event custom data
560  
561  cancel()       cancel the operator
562  
563  exit() cleanup, send notifier
564  
565  callbacks:
566  
567  invoke() gets called on shift+lmb drag in actionzone
568  call init(), add handler
569  
570  modal()  accept modal events while doing it
571  
572  */
573
574 typedef struct sAreaSwapData {
575         ScrArea *sa1, *sa2;
576 } sAreaSwapData;
577
578 static int area_swap_init(bContext *C, wmOperator *op, wmEvent *event)
579 {
580         sAreaSwapData *sd= NULL;
581         sActionzoneData *sad= event->customdata;
582         
583         if(sad==NULL || sad->sa1==NULL)
584                 return 0;
585         
586         sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
587         sd->sa1= sad->sa1;
588         sd->sa2= sad->sa2;
589         op->customdata= sd;
590         
591         return 1;
592 }
593
594
595 static void area_swap_exit(bContext *C, wmOperator *op)
596 {
597         WM_cursor_restore(CTX_wm_window(C));
598         if(op->customdata)
599                 MEM_freeN(op->customdata);
600         op->customdata= NULL;
601 }
602
603 static int area_swap_cancel(bContext *C, wmOperator *op)
604 {
605         area_swap_exit(C, op);
606         return OPERATOR_CANCELLED;
607 }
608
609 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
610 {
611         
612         if(!area_swap_init(C, op, event))
613                 return OPERATOR_PASS_THROUGH;
614         
615         /* add modal handler */
616         WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
617         WM_event_add_modal_handler(C, op);
618         
619         return OPERATOR_RUNNING_MODAL;
620         
621 }
622
623 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
624 {
625         sActionzoneData *sad= op->customdata;
626         
627         switch(event->type) {
628                 case MOUSEMOVE:
629                         /* second area, for join */
630                         sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
631                         break;
632                 case LEFTMOUSE: /* release LMB */
633                         if(event->val==KM_RELEASE) {
634                                 if(!sad->sa2 || sad->sa1 == sad->sa2) {
635                                         
636                                         return area_swap_cancel(C, op);
637                                 }
638
639                                 ED_area_tag_redraw(sad->sa1);
640                                 ED_area_tag_redraw(sad->sa2);
641
642                                 ED_area_swapspace(C, sad->sa1, sad->sa2);
643                                 
644                                 area_swap_exit(C, op);
645                                 
646                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
647                                 
648                                 return OPERATOR_FINISHED;
649                         }
650                         break;
651                         
652                 case ESCKEY:
653                         return area_swap_cancel(C, op);
654         }
655         return OPERATOR_RUNNING_MODAL;
656 }
657
658 static void SCREEN_OT_area_swap(wmOperatorType *ot)
659 {
660         ot->name= "Swap areas";
661         ot->description= "Swap selected areas screen positions";
662         ot->idname= "SCREEN_OT_area_swap";
663         
664         ot->invoke= area_swap_invoke;
665         ot->modal= area_swap_modal;
666         ot->poll= ED_operator_areaactive;
667         
668         ot->flag= OPTYPE_BLOCKING;
669 }
670
671 /* *********** Duplicate area as new window operator ****************** */
672
673 /* operator callback */
674 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
675 {
676         wmWindow *newwin, *win;
677         bScreen *newsc, *sc;
678         ScrArea *sa;
679         rcti rect;
680         
681         win= CTX_wm_window(C);
682         sc= CTX_wm_screen(C);
683         sa= CTX_wm_area(C);
684         
685         /* XXX hrmf! */
686         if(event->type==EVT_ACTIONZONE_AREA) {
687                 sActionzoneData *sad= event->customdata;
688                 
689                 if(sad==NULL)
690                         return OPERATOR_PASS_THROUGH;
691                 
692                 sa= sad->sa1;
693         }
694         
695         /*  poll() checks area context, but we don't accept full-area windows */
696         if(sc->full != SCREENNORMAL) {
697                 if(event->type==EVT_ACTIONZONE_AREA)
698                         actionzone_exit(C, op);
699                 return OPERATOR_CANCELLED;
700         }
701         
702         /* adds window to WM */
703         rect= sa->totrct;
704         BLI_translate_rcti(&rect, win->posx, win->posy);
705         newwin= WM_window_open(C, &rect);
706         
707         /* allocs new screen and adds to newly created window, using window size */
708         newsc= ED_screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
709         newwin->screen= newsc;
710         
711         /* copy area to new screen */
712         area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
713
714         ED_area_tag_redraw((ScrArea *)newsc->areabase.first);
715
716         /* screen, areas init */
717         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
718         
719         if(event->type==EVT_ACTIONZONE_AREA)
720                 actionzone_exit(C, op);
721         
722         return OPERATOR_FINISHED;
723 }
724
725 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
726 {
727         ot->name= "Duplicate Area into New Window";
728         ot->description= "Duplicate selected area into new window";
729         ot->idname= "SCREEN_OT_area_dupli";
730         
731         ot->invoke= area_dupli_invoke;
732         ot->poll= ED_operator_areaactive;
733 }
734
735
736 /* ************** move area edge operator *********************************** */
737
738 /* operator state vars used:  
739  x, y                           mouse coord near edge
740  delta            movement of edge
741  
742  functions:
743  
744  init()   set default property values, find edge based on mouse coords, test
745  if the edge can be moved, select edges, calculate min and max movement
746  
747  apply()        apply delta on selection
748  
749  exit() cleanup, send notifier
750  
751  cancel() cancel moving
752  
753  callbacks:
754  
755  exec()   execute without any user interaction, based on properties
756  call init(), apply(), exit()
757  
758  invoke() gets called on mouse click near edge
759  call init(), add handler
760  
761  modal()  accept modal events while doing it
762  call apply() with delta motion
763  call exit() and remove handler
764  
765  */
766
767 typedef struct sAreaMoveData {
768         int bigger, smaller, origval, step;
769         char dir;
770 } sAreaMoveData;
771
772 /* helper call to move area-edge, sets limits */
773 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
774 {
775         ScrArea *sa;
776         
777         /* we check all areas and test for free space with MINSIZE */
778         *bigger= *smaller= 100000;
779         
780         for(sa= sc->areabase.first; sa; sa= sa->next) {
781                 if(dir=='h') {
782                         int y1= sa->v2->vec.y - sa->v1->vec.y-AREAMINY;
783                         
784                         /* if top or down edge selected, test height */
785                         if(sa->v1->flag && sa->v4->flag)
786                                 *bigger= MIN2(*bigger, y1);
787                         else if(sa->v2->flag && sa->v3->flag)
788                                 *smaller= MIN2(*smaller, y1);
789                 }
790                 else {
791                         int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
792                         
793                         /* if left or right edge selected, test width */
794                         if(sa->v1->flag && sa->v2->flag)
795                                 *bigger= MIN2(*bigger, x1);
796                         else if(sa->v3->flag && sa->v4->flag)
797                                 *smaller= MIN2(*smaller, x1);
798                 }
799         }
800 }
801
802 /* validate selection inside screen, set variables OK */
803 /* return 0: init failed */
804 static int area_move_init (bContext *C, wmOperator *op)
805 {
806         bScreen *sc= CTX_wm_screen(C);
807         ScrEdge *actedge;
808         sAreaMoveData *md;
809         int x, y;
810         
811         /* required properties */
812         x= RNA_int_get(op->ptr, "x");
813         y= RNA_int_get(op->ptr, "y");
814         
815         /* setup */
816         actedge= screen_find_active_scredge(sc, x, y);
817         if(actedge==NULL) return 0;
818         
819         md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
820         op->customdata= md;
821         
822         md->dir= scredge_is_horizontal(actedge)?'h':'v';
823         if(md->dir=='h') md->origval= actedge->v1->vec.y;
824         else md->origval= actedge->v1->vec.x;
825         
826         select_connected_scredge(sc, actedge);
827         /* now all vertices with 'flag==1' are the ones that can be moved. */
828         
829         area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
830         
831         return 1;
832 }
833
834 /* moves selected screen edge amount of delta, used by split & move */
835 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
836 {
837         wmWindow *win= CTX_wm_window(C);
838         bScreen *sc= CTX_wm_screen(C);
839         ScrVert *v1;
840         ScrArea *sa;
841         
842         delta= CLAMPIS(delta, -smaller, bigger);
843         
844         for (v1= sc->vertbase.first; v1; v1= v1->next) {
845                 if (v1->flag) {
846                         /* that way a nice AREAGRID  */
847                         if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
848                                 v1->vec.x= origval + delta;
849                                 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
850                         }
851                         if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
852                                 v1->vec.y= origval + delta;
853                                 
854                                 v1->vec.y+= AREAGRID-1;
855                                 v1->vec.y-= (v1->vec.y % AREAGRID);
856                                 
857                                 /* prevent too small top header */
858                                 if(v1->vec.y > win->sizey-AREAMINY)
859                                         v1->vec.y= win->sizey-AREAMINY;
860                         }
861                 }
862         }
863
864         for(sa= sc->areabase.first; sa; sa= sa->next) {
865                 if(sa->v1->flag || sa->v2->flag || sa->v3->flag || sa->v4->flag)
866                         ED_area_tag_redraw(sa);
867         }
868
869         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); /* redraw everything */
870 }
871
872 static void area_move_apply(bContext *C, wmOperator *op)
873 {
874         sAreaMoveData *md= op->customdata;
875         int delta;
876         
877         delta= RNA_int_get(op->ptr, "delta");
878         area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
879 }
880
881 static void area_move_exit(bContext *C, wmOperator *op)
882 {
883         if(op->customdata)
884                 MEM_freeN(op->customdata);
885         op->customdata= NULL;
886         
887         /* this makes sure aligned edges will result in aligned grabbing */
888         removedouble_scrverts(CTX_wm_screen(C));
889         removedouble_scredges(CTX_wm_screen(C));
890 }
891
892 static int area_move_exec(bContext *C, wmOperator *op)
893 {
894         if(!area_move_init(C, op))
895                 return OPERATOR_CANCELLED;
896         
897         area_move_apply(C, op);
898         area_move_exit(C, op);
899         
900         return OPERATOR_FINISHED;
901 }
902
903 /* interaction callback */
904 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
905 {
906         RNA_int_set(op->ptr, "x", event->x);
907         RNA_int_set(op->ptr, "y", event->y);
908         
909         if(!area_move_init(C, op)) 
910                 return OPERATOR_PASS_THROUGH;
911         
912         /* add temp handler */
913         WM_event_add_modal_handler(C, op);
914         
915         return OPERATOR_RUNNING_MODAL;
916 }
917
918 static int area_move_cancel(bContext *C, wmOperator *op)
919 {
920         
921         RNA_int_set(op->ptr, "delta", 0);
922         area_move_apply(C, op);
923         area_move_exit(C, op);
924         
925         return OPERATOR_CANCELLED;
926 }
927
928 /* modal callback for while moving edges */
929 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
930 {
931         sAreaMoveData *md= op->customdata;
932         int delta, x, y;
933         
934         /* execute the events */
935         switch(event->type) {
936                 case MOUSEMOVE:
937                         
938                         x= RNA_int_get(op->ptr, "x");
939                         y= RNA_int_get(op->ptr, "y");
940                         
941                         delta= (md->dir == 'v')? event->x - x: event->y - y;
942                         if(md->step) delta= delta - (delta % md->step);
943                         RNA_int_set(op->ptr, "delta", delta);
944                         
945                         area_move_apply(C, op);
946                         break;
947                         
948                 case EVT_MODAL_MAP:
949                         
950                         switch (event->val) {
951                                 case KM_MODAL_APPLY:
952                                         area_move_exit(C, op);
953                                         return OPERATOR_FINISHED;
954                                         
955                                 case KM_MODAL_CANCEL:
956                                         return area_move_cancel(C, op);
957                                         
958                                 case KM_MODAL_STEP10:
959                                         md->step= 10;
960                                         break;
961                                 case KM_MODAL_STEP10_OFF:
962                                         md->step= 0;
963                                         break;
964                         }
965         }
966         
967         return OPERATOR_RUNNING_MODAL;
968 }
969
970 static void SCREEN_OT_area_move(wmOperatorType *ot)
971 {
972         /* identifiers */
973         ot->name= "Move area edges";
974         ot->description= "Move selected area edges";
975         ot->idname= "SCREEN_OT_area_move";
976         
977         ot->exec= area_move_exec;
978         ot->invoke= area_move_invoke;
979         ot->cancel= area_move_cancel;
980         ot->modal= area_move_modal;
981         ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
982         
983         ot->flag= OPTYPE_BLOCKING;
984         
985         /* rna */
986         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
987         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
988         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
989 }
990
991 /* ************** split area operator *********************************** */
992
993 /* 
994  operator state vars:  
995  fac              spit point
996  dir              direction 'v' or 'h'
997  
998  operator customdata:
999  area                           pointer to (active) area
1000  x, y                   last used mouse pos
1001  (more, see below)
1002  
1003  functions:
1004  
1005  init()   set default property values, find area based on context
1006  
1007  apply()        split area based on state vars
1008  
1009  exit() cleanup, send notifier
1010  
1011  cancel() remove duplicated area
1012  
1013  callbacks:
1014  
1015  exec()   execute without any user interaction, based on state vars
1016  call init(), apply(), exit()
1017  
1018  invoke() gets called on mouse click in action-widget
1019  call init(), add modal handler
1020  call apply() with initial motion
1021  
1022  modal()  accept modal events while doing it
1023  call move-areas code with delta motion
1024  call exit() or cancel() and remove handler
1025  
1026  */
1027
1028 #define SPLIT_STARTED   1
1029 #define SPLIT_PROGRESS  2
1030
1031 typedef struct sAreaSplitData
1032         {
1033                 int x, y;       /* last used mouse position */
1034                 
1035                 int origval;                    /* for move areas */
1036                 int bigger, smaller;    /* constraints for moving new edge */
1037                 int delta;                              /* delta move edge */
1038                 int origmin, origsize;  /* to calculate fac, for property storage */
1039                 
1040                 ScrEdge *nedge;                 /* new edge */
1041                 ScrArea *sarea;                 /* start area */
1042                 ScrArea *narea;                 /* new area */
1043         } sAreaSplitData;
1044
1045 /* generic init, no UI stuff here */
1046 static int area_split_init(bContext *C, wmOperator *op)
1047 {
1048         ScrArea *sa= CTX_wm_area(C);
1049         sAreaSplitData *sd;
1050         int dir;
1051         
1052         /* required context */
1053         if(sa==NULL) return 0;
1054         
1055         /* required properties */
1056         dir= RNA_enum_get(op->ptr, "direction");
1057         
1058         /* minimal size */
1059         if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
1060         if(dir=='h' && sa->winy < 2*AREAMINY) return 0;
1061         
1062         /* custom data */
1063         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
1064         op->customdata= sd;
1065         
1066         sd->sarea= sa;
1067         sd->origsize= dir=='v' ? sa->winx:sa->winy;
1068         sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
1069         
1070         return 1;
1071 }
1072
1073 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
1074 /* used with split operator */
1075 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
1076 {
1077         ScrVert *sav1= sa->v1;
1078         ScrVert *sav2= sa->v2;
1079         ScrVert *sav3= sa->v3;
1080         ScrVert *sav4= sa->v4;
1081         ScrVert *sbv1= sb->v1;
1082         ScrVert *sbv2= sb->v2;
1083         ScrVert *sbv3= sb->v3;
1084         ScrVert *sbv4= sb->v4;
1085         
1086         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
1087                 return screen_findedge(screen, sav1, sav2);
1088         }
1089         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
1090                 return screen_findedge(screen, sav2, sav3);
1091         }
1092         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
1093                 return screen_findedge(screen, sav3, sav4);
1094         }
1095         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
1096                 return screen_findedge(screen, sav1, sav4);
1097         }
1098         
1099         return NULL;
1100 }
1101
1102
1103 /* do the split, return success */
1104 static int area_split_apply(bContext *C, wmOperator *op)
1105 {
1106         bScreen *sc= CTX_wm_screen(C);
1107         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1108         float fac;
1109         int dir;
1110         
1111         fac= RNA_float_get(op->ptr, "factor");
1112         dir= RNA_enum_get(op->ptr, "direction");
1113         
1114         sd->narea= area_split(CTX_wm_window(C), sc, sd->sarea, dir, fac);
1115         
1116         if(sd->narea) {
1117                 ScrVert *sv;
1118                 
1119                 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
1120                 
1121                 /* select newly created edge, prepare for moving edge */
1122                 for(sv= sc->vertbase.first; sv; sv= sv->next)
1123                         sv->flag = 0;
1124                 
1125                 sd->nedge->v1->flag= 1;
1126                 sd->nedge->v2->flag= 1;
1127                 
1128                 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
1129                 else sd->origval= sd->nedge->v1->vec.x;
1130
1131                 ED_area_tag_redraw(sd->sarea);
1132                 ED_area_tag_redraw(sd->narea);
1133
1134                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1135                 
1136                 return 1;
1137         }               
1138         
1139         return 0;
1140 }
1141
1142 static void area_split_exit(bContext *C, wmOperator *op)
1143 {
1144         if (op->customdata) {
1145                 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1146                 if(sd->sarea) ED_area_tag_redraw(sd->sarea);
1147                 if(sd->narea) ED_area_tag_redraw(sd->narea);
1148
1149                 MEM_freeN(op->customdata);
1150                 op->customdata = NULL;
1151         }
1152         
1153         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1154         
1155         /* this makes sure aligned edges will result in aligned grabbing */
1156         removedouble_scrverts(CTX_wm_screen(C));
1157         removedouble_scredges(CTX_wm_screen(C));
1158 }
1159
1160
1161 /* UI callback, adds new handler */
1162 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1163 {
1164         sAreaSplitData *sd;
1165         
1166         if(event->type==EVT_ACTIONZONE_AREA) {
1167                 sActionzoneData *sad= event->customdata;
1168                 int dir;
1169                 
1170                 if(sad->modifier>0) {
1171                         return OPERATOR_PASS_THROUGH;
1172                 }
1173                 
1174                 /* no full window splitting allowed */
1175                 if(CTX_wm_area(C)->full)
1176                         return OPERATOR_PASS_THROUGH;
1177                 
1178                 /* verify *sad itself */
1179                 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1180                         return OPERATOR_PASS_THROUGH;
1181                 
1182                 /* is this our *sad? if areas not equal it should be passed on */
1183                 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1184                         return OPERATOR_PASS_THROUGH;
1185                 
1186                 /* prepare operator state vars */
1187                 if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
1188                         dir= 'h';
1189                         RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1190                 }
1191                 else {
1192                         dir= 'v';
1193                         RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1194                 }
1195                 RNA_enum_set(op->ptr, "direction", dir);
1196                 
1197                 /* general init, also non-UI case, adds customdata, sets area and defaults */
1198                 if(!area_split_init(C, op))
1199                         return OPERATOR_PASS_THROUGH;
1200                 
1201                 sd= (sAreaSplitData *)op->customdata;
1202                 
1203                 sd->x= event->x;
1204                 sd->y= event->y;
1205                 
1206                 /* do the split */
1207                 if(area_split_apply(C, op)) {
1208                         area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1209                         
1210                         /* add temp handler for edge move or cancel */
1211                         WM_event_add_modal_handler(C, op);
1212                         
1213                         return OPERATOR_RUNNING_MODAL;
1214                 }
1215                 
1216         }
1217         else {
1218                 /* nonmodal for now */
1219                 return op->type->exec(C, op);
1220         }
1221         
1222         return OPERATOR_PASS_THROUGH;
1223 }
1224
1225 /* function to be called outside UI context, or for redo */
1226 static int area_split_exec(bContext *C, wmOperator *op)
1227 {
1228         
1229         if(!area_split_init(C, op))
1230                 return OPERATOR_CANCELLED;
1231         
1232         area_split_apply(C, op);
1233         area_split_exit(C, op);
1234         
1235         return OPERATOR_FINISHED;
1236 }
1237
1238
1239 static int area_split_cancel(bContext *C, wmOperator *op)
1240 {
1241         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1242         
1243         if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1244                 if (CTX_wm_area(C) == sd->narea) {
1245                         CTX_wm_area_set(C, NULL);
1246                         CTX_wm_region_set(C, NULL);
1247                 }
1248                 sd->narea = NULL;
1249         }
1250         area_split_exit(C, op);
1251         
1252         return OPERATOR_CANCELLED;
1253 }
1254
1255 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1256 {
1257         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1258         float fac;
1259         int dir;
1260         
1261         /* execute the events */
1262         switch(event->type) {
1263                 case MOUSEMOVE:
1264                         dir= RNA_enum_get(op->ptr, "direction");
1265                         
1266                         sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1267                         area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1268                         
1269                         fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1270                         RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1271                         break;
1272                         
1273                 case LEFTMOUSE:
1274                         if(event->val==KM_RELEASE) { /* mouse up */
1275                                 area_split_exit(C, op);
1276                                 return OPERATOR_FINISHED;
1277                         }
1278                         break;
1279                 case RIGHTMOUSE: /* cancel operation */
1280                 case ESCKEY:
1281                         return area_split_cancel(C, op);
1282         }
1283         
1284         return OPERATOR_RUNNING_MODAL;
1285 }
1286
1287 static EnumPropertyItem prop_direction_items[] = {
1288 {'h', "HORIZONTAL", 0, "Horizontal", ""},
1289 {'v', "VERTICAL", 0, "Vertical", ""},
1290 {0, NULL, 0, NULL, NULL}};
1291
1292 static void SCREEN_OT_area_split(wmOperatorType *ot)
1293 {
1294         ot->name = "Split area";
1295         ot->description= "Split selected area into new windows";
1296         ot->idname = "SCREEN_OT_area_split";
1297         
1298         ot->exec= area_split_exec;
1299         ot->invoke= area_split_invoke;
1300         ot->modal= area_split_modal;
1301         
1302         ot->poll= ED_operator_areaactive;
1303         ot->flag= OPTYPE_BLOCKING;
1304         
1305         /* rna */
1306         RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1307         RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1308 }
1309
1310
1311
1312 /* ************** scale region edge operator *********************************** */
1313
1314 typedef struct RegionMoveData {
1315         AZone *az;
1316         ARegion *ar;
1317         ScrArea *sa;
1318         int bigger, smaller, origval;
1319         int origx, origy;
1320         int maxsize;
1321         AZEdge edge;
1322         
1323 } RegionMoveData;
1324
1325
1326 static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge)
1327 {
1328         ARegion *ar;
1329         int dist;
1330         
1331         if(edge==AE_RIGHT_TO_TOPLEFT || edge==AE_LEFT_TO_TOPRIGHT) {
1332                 dist = sa->totrct.xmax - sa->totrct.xmin;
1333         } else {        /* AE_BOTTOM_TO_TOPLEFT, AE_TOP_TO_BOTTOMRIGHT */
1334                 dist = sa->totrct.ymax - sa->totrct.ymin;
1335         }
1336         
1337         /* subtractwidth of regions on opposite side 
1338          * prevents dragging regions into other opposite regions */
1339         for (ar=sa->regionbase.first; ar; ar=ar->next)
1340         {
1341                 if (ar == scalear)
1342                         continue;
1343                 
1344                 if (scalear->alignment == RGN_ALIGN_TOP && ar->alignment == RGN_ALIGN_BOTTOM)
1345                         dist -= ar->winy;
1346                 else if (scalear->alignment == RGN_ALIGN_BOTTOM && ar->alignment == RGN_ALIGN_TOP)
1347                         dist -= ar->winy;
1348                 else if (scalear->alignment == RGN_ALIGN_LEFT && ar->alignment == RGN_ALIGN_RIGHT)
1349                         dist -= ar->winx;
1350                 else if (scalear->alignment == RGN_ALIGN_RIGHT && ar->alignment == RGN_ALIGN_LEFT)
1351                         dist -= ar->winx;
1352                 
1353                 /* case of regions in regions, like operator properties panel */
1354                 /* these can sit on top of other regions such as headers, so account for this */
1355                 else if (edge == AE_BOTTOM_TO_TOPLEFT && scalear->alignment & RGN_ALIGN_TOP && ar->alignment == RGN_ALIGN_TOP && ar->regiontype == RGN_TYPE_HEADER)
1356                         dist -= ar->winy;
1357                 else if (edge == AE_TOP_TO_BOTTOMRIGHT && scalear->alignment & RGN_ALIGN_BOTTOM && ar->alignment == RGN_ALIGN_BOTTOM && ar->regiontype == RGN_TYPE_HEADER)
1358                         dist -= ar->winy;
1359         }
1360
1361         return dist;
1362 }
1363
1364 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1365 {
1366         sActionzoneData *sad= event->customdata;
1367         AZone *az;
1368         
1369         if(event->type!=EVT_ACTIONZONE_REGION) {
1370                 BKE_report(op->reports, RPT_ERROR, "Can only scale region size from an action zone");   
1371                 return OPERATOR_CANCELLED;
1372         }
1373         
1374         az = sad->az;
1375         
1376         if(az->ar) {
1377                 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1378                 int maxsize;
1379                 
1380                 op->customdata= rmd;
1381                 
1382                 rmd->az = az;
1383                 rmd->ar= az->ar;
1384                 rmd->sa = sad->sa1;
1385                 rmd->edge= az->edge;
1386                 rmd->origx= event->x;
1387                 rmd->origy= event->y;
1388                 rmd->maxsize = area_max_regionsize(rmd->sa, rmd->ar, rmd->edge);
1389                 
1390                 /* if not set we do now, otherwise it uses type */
1391                 if(rmd->ar->sizex==0) 
1392                         rmd->ar->sizex= rmd->ar->type->prefsizex;
1393                 if(rmd->ar->sizey==0) 
1394                         rmd->ar->sizey= rmd->ar->type->prefsizey;
1395                 
1396                 /* now copy to regionmovedata */
1397                 if(rmd->edge==AE_LEFT_TO_TOPRIGHT || rmd->edge==AE_RIGHT_TO_TOPLEFT) {
1398                         rmd->origval= rmd->ar->sizex;
1399                 } else {
1400                         rmd->origval= rmd->ar->sizey;
1401                 }
1402                 
1403                 /* limit headers to standard height for now */
1404                 if (rmd->ar->regiontype == RGN_TYPE_HEADER)
1405                         maxsize = rmd->ar->type->prefsizey;
1406                 else
1407                         maxsize = 1000;
1408                 
1409                 CLAMP(rmd->maxsize, 0, maxsize);
1410                 
1411                 /* add temp handler */
1412                 WM_event_add_modal_handler(C, op);
1413                 
1414                 return OPERATOR_RUNNING_MODAL;
1415         }
1416         
1417         return OPERATOR_FINISHED;
1418 }
1419
1420 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1421 {
1422         RegionMoveData *rmd= op->customdata;
1423         int delta;
1424         
1425         /* execute the events */
1426         switch(event->type) {
1427                 case MOUSEMOVE:
1428                         
1429                         if(rmd->edge==AE_LEFT_TO_TOPRIGHT || rmd->edge==AE_RIGHT_TO_TOPLEFT) {
1430                                 delta= event->x - rmd->origx;
1431                                 if(rmd->edge==AE_LEFT_TO_TOPRIGHT) delta= -delta;
1432                                 
1433                                 rmd->ar->sizex= rmd->origval + delta;
1434                                 CLAMP(rmd->ar->sizex, 0, rmd->maxsize);
1435                                 
1436                                 if(rmd->ar->sizex < 24) {
1437                                         rmd->ar->sizex= rmd->origval;
1438                                         if(!(rmd->ar->flag & RGN_FLAG_HIDDEN))
1439                                                 ED_region_toggle_hidden(C, rmd->ar);
1440                                 }
1441                                 else if(rmd->ar->flag & RGN_FLAG_HIDDEN)
1442                                         ED_region_toggle_hidden(C, rmd->ar);
1443                         }
1444                         else {
1445                                 int maxsize=0;
1446                                 delta= event->y - rmd->origy;
1447                                 if(rmd->edge==AE_BOTTOM_TO_TOPLEFT) delta= -delta;
1448                                 
1449                                 rmd->ar->sizey= rmd->origval + delta;
1450                                 CLAMP(rmd->ar->sizey, 0, rmd->maxsize);
1451                                 
1452                                 if(rmd->ar->regiontype == RGN_TYPE_TOOL_PROPS)
1453                                         maxsize = rmd->maxsize - ((rmd->sa->headertype==2)?48:24) - 10;
1454
1455                                 if(rmd->ar->sizey < 24 || (maxsize > 0 && (rmd->ar->sizey > maxsize)) ) {
1456                                         rmd->ar->sizey= rmd->origval;
1457                                         if(!(rmd->ar->flag & RGN_FLAG_HIDDEN))
1458                                                 ED_region_toggle_hidden(C, rmd->ar);
1459                                 }
1460                                 else if(rmd->ar->flag & RGN_FLAG_HIDDEN)
1461                                         ED_region_toggle_hidden(C, rmd->ar);
1462                         }
1463                         ED_area_tag_redraw(rmd->sa);
1464                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1465                         
1466                         break;
1467                         
1468                 case LEFTMOUSE:
1469                         if(event->val==KM_RELEASE) {
1470                                 
1471                                 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1472                                         if(rmd->ar->flag & RGN_FLAG_HIDDEN) {
1473                                                 ED_region_toggle_hidden(C, rmd->ar);
1474                                                 ED_area_tag_redraw(rmd->sa);
1475                                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1476                                         }
1477                                 }
1478                                 MEM_freeN(op->customdata);
1479                                 op->customdata = NULL;
1480                                 
1481                                 return OPERATOR_FINISHED;
1482                         }
1483                         break;
1484                         
1485                 case ESCKEY:
1486                         ;
1487         }
1488         
1489         return OPERATOR_RUNNING_MODAL;
1490 }
1491
1492
1493 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1494 {
1495         /* identifiers */
1496         ot->name= "Scale Region Size";
1497         ot->description= "Scale selected area";
1498         ot->idname= "SCREEN_OT_region_scale";
1499         
1500         ot->invoke= region_scale_invoke;
1501         ot->modal= region_scale_modal;
1502         
1503         ot->poll= ED_operator_areaactive;
1504         
1505         ot->flag= OPTYPE_BLOCKING;
1506 }
1507
1508
1509 /* ************** frame change operator ***************************** */
1510
1511 /* function to be called outside UI context, or for redo */
1512 static int frame_offset_exec(bContext *C, wmOperator *op)
1513 {
1514         int delta;
1515         
1516         delta = RNA_int_get(op->ptr, "delta");
1517
1518         CTX_data_scene(C)->r.cfra += delta;
1519         CTX_data_scene(C)->r.subframe = 0.f;
1520         
1521         sound_seek_scene(C);
1522
1523         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1524         
1525         return OPERATOR_FINISHED;
1526 }
1527
1528 static void SCREEN_OT_frame_offset(wmOperatorType *ot)
1529 {
1530         ot->name = "Frame Offset";
1531         ot->idname = "SCREEN_OT_frame_offset";
1532         
1533         ot->exec= frame_offset_exec;
1534         
1535         ot->poll= ED_operator_screenactive;
1536         ot->flag= 0;
1537         
1538         /* rna */
1539         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1540 }
1541
1542
1543 /* function to be called outside UI context, or for redo */
1544 static int frame_jump_exec(bContext *C, wmOperator *op)
1545 {
1546         Scene *scene= CTX_data_scene(C);
1547         
1548         if (RNA_boolean_get(op->ptr, "end"))
1549                 CFRA= PEFRA;
1550         else
1551                 CFRA= PSFRA;
1552         
1553         sound_seek_scene(C);
1554
1555         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1556         
1557         return OPERATOR_FINISHED;
1558 }
1559
1560 static void SCREEN_OT_frame_jump(wmOperatorType *ot)
1561 {
1562         ot->name = "Jump to Endpoint";
1563         ot->description= "Jump to first/last frame in frame range";
1564         ot->idname = "SCREEN_OT_frame_jump";
1565         
1566         ot->exec= frame_jump_exec;
1567         
1568         ot->poll= ED_operator_screenactive;
1569         ot->flag= OPTYPE_UNDO;
1570         
1571         /* rna */
1572         RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range.");
1573 }
1574
1575
1576 /* ************** jump to keyframe operator ***************************** */
1577
1578 /* function to be called outside UI context, or for redo */
1579 static int keyframe_jump_exec(bContext *C, wmOperator *op)
1580 {
1581         Scene *scene= CTX_data_scene(C);
1582         Object *ob= CTX_data_active_object(C);
1583         DLRBT_Tree keys;
1584         ActKeyColumn *ak;
1585         float cfra= (scene)? (float)(CFRA) : 0.0f;
1586         short next= RNA_boolean_get(op->ptr, "next");
1587         short done = 0;
1588         
1589         /* sanity checks */
1590         if (scene == NULL)
1591                 return OPERATOR_CANCELLED;
1592         
1593         /* init binarytree-list for getting keyframes */
1594         BLI_dlrbTree_init(&keys);
1595         
1596         /* populate tree with keyframe nodes */
1597         if (scene && scene->adt)
1598                 scene_to_keylist(NULL, scene, &keys, NULL);
1599         if (ob && ob->adt)
1600                 ob_to_keylist(NULL, ob, &keys, NULL);
1601         
1602         /* build linked-list for searching */
1603         BLI_dlrbTree_linkedlist_sync(&keys);
1604         
1605         /* find matching keyframe in the right direction */
1606         do {
1607                 if (next)
1608                         ak= (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfra);
1609                 else
1610                         ak= (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfra);
1611                 
1612                 if (ak) {
1613                         if (CFRA != (int)ak->cfra) {
1614                                 /* this changes the frame, so set the frame and we're done */
1615                                 CFRA= (int)ak->cfra;
1616                                 done = 1;
1617                         }
1618                         else {
1619                                 /* make this the new starting point for the search */
1620                                 cfra = ak->cfra;
1621                         }
1622                 }
1623         } while ((ak != NULL) && (done == 0));
1624         
1625         /* any success? */
1626         if (done == 0)
1627                 BKE_report(op->reports, RPT_INFO, "No more keyframes to jump to in this direction");
1628         
1629         /* free temp stuff */
1630         BLI_dlrbTree_free(&keys);
1631         
1632         sound_seek_scene(C);
1633
1634         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1635         
1636         return OPERATOR_FINISHED;
1637 }
1638
1639 static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
1640 {
1641         ot->name = "Jump to Keyframe";
1642         ot->description= "Jump to previous/next keyframe";
1643         ot->idname = "SCREEN_OT_keyframe_jump";
1644         
1645         ot->exec= keyframe_jump_exec;
1646         
1647         ot->poll= ED_operator_screenactive;
1648         ot->flag= OPTYPE_UNDO;
1649         
1650         /* rna */
1651         RNA_def_boolean(ot->srna, "next", 1, "Next Keyframe", "");
1652 }
1653
1654 /* ************** switch screen operator ***************************** */
1655
1656
1657 /* function to be called outside UI context, or for redo */
1658 static int screen_set_exec(bContext *C, wmOperator *op)
1659 {
1660         bScreen *screen= CTX_wm_screen(C);
1661         ScrArea *sa= CTX_wm_area(C);
1662         int tot= BLI_countlist(&CTX_data_main(C)->screen);
1663         int delta= RNA_int_get(op->ptr, "delta");
1664         
1665         /* return to previous state before switching screens */
1666         if(sa && sa->full)
1667                 ED_screen_full_restore(C, sa);
1668         
1669         if(delta==1) {
1670                 while(tot--) {
1671                         screen= screen->id.next;
1672                         if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1673                         if(screen->winid==0 && screen->full==0)
1674                                 break;
1675                 }
1676         }
1677         else if(delta== -1) {
1678                 while(tot--) {
1679                         screen= screen->id.prev;
1680                         if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1681                         if(screen->winid==0 && screen->full==0)
1682                                 break;
1683                 }
1684         }
1685         else {
1686                 screen= NULL;
1687         }
1688         
1689         if(screen) {
1690                 ED_screen_set(C, screen);
1691                 return OPERATOR_FINISHED;
1692         }
1693         return OPERATOR_CANCELLED;
1694 }
1695
1696 static void SCREEN_OT_screen_set(wmOperatorType *ot)
1697 {
1698         ot->name = "Set Screen";
1699         ot->description= "Cycle through available screens";
1700         ot->idname = "SCREEN_OT_screen_set";
1701         
1702         ot->exec= screen_set_exec;
1703         ot->poll= ED_operator_screenactive;
1704         
1705         /* rna */
1706         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1707 }
1708
1709 /* ************** screen full-area operator ***************************** */
1710
1711
1712 /* function to be called outside UI context, or for redo */
1713 static int screen_full_area_exec(bContext *C, wmOperator *op)
1714 {
1715         ED_screen_full_toggle(C, CTX_wm_window(C), CTX_wm_area(C));
1716         return OPERATOR_FINISHED;
1717 }
1718
1719 static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1720 {
1721         ot->name = "Toggle Full Screen";
1722         ot->description= "Toggle display selected area as fullscreen";
1723         ot->idname = "SCREEN_OT_screen_full_area";
1724         
1725         ot->exec= screen_full_area_exec;
1726         ot->poll= ED_operator_areaactive;
1727         ot->flag= 0;
1728         
1729 }
1730
1731
1732
1733 /* ************** join area operator ********************************************** */
1734
1735 /* operator state vars used:  
1736  x1, y1     mouse coord in first area, which will disappear
1737  x2, y2     mouse coord in 2nd area, which will become joined
1738  
1739  functions:
1740  
1741  init()   find edge based on state vars 
1742  test if the edge divides two areas, 
1743  store active and nonactive area,
1744  
1745  apply()  do the actual join
1746  
1747  exit() cleanup, send notifier
1748  
1749  callbacks:
1750  
1751  exec() calls init, apply, exit 
1752  
1753  invoke() sets mouse coords in x,y
1754  call init()
1755  add modal handler
1756  
1757  modal()        accept modal events while doing it
1758  call apply() with active window and nonactive window
1759  call exit() and remove handler when LMB confirm
1760  
1761  */
1762
1763 typedef struct sAreaJoinData
1764         {
1765                 ScrArea *sa1;   /* first area to be considered */
1766                 ScrArea *sa2;   /* second area to be considered */
1767                 ScrArea *scr;   /* designed for removal */
1768                 
1769         } sAreaJoinData;
1770
1771
1772 /* validate selection inside screen, set variables OK */
1773 /* return 0: init failed */
1774 /* XXX todo: find edge based on (x,y) and set other area? */
1775 static int area_join_init(bContext *C, wmOperator *op)
1776 {
1777         ScrArea *sa1, *sa2;
1778         sAreaJoinData* jd= NULL;
1779         int x1, y1;
1780         int x2, y2;
1781         
1782         /* required properties, make negative to get return 0 if not set by caller */
1783         x1= RNA_int_get(op->ptr, "min_x");
1784         y1= RNA_int_get(op->ptr, "min_y");
1785         x2= RNA_int_get(op->ptr, "max_x");
1786         y2= RNA_int_get(op->ptr, "max_y");
1787         
1788         sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1789         sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1790         if(sa1==NULL || sa2==NULL || sa1==sa2)
1791                 return 0;
1792         
1793         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1794         
1795         jd->sa1 = sa1;
1796         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1797         jd->sa2 = sa2;
1798         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1799         
1800         op->customdata= jd;
1801         
1802         return 1;
1803 }
1804
1805 /* apply the join of the areas (space types) */
1806 static int area_join_apply(bContext *C, wmOperator *op)
1807 {
1808         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1809         if (!jd) return 0;
1810         
1811         if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1812                 return 0;
1813         }
1814         if (CTX_wm_area(C) == jd->sa2) {
1815                 CTX_wm_area_set(C, NULL);
1816                 CTX_wm_region_set(C, NULL);
1817         }
1818         
1819         return 1;
1820 }
1821
1822 /* finish operation */
1823 static void area_join_exit(bContext *C, wmOperator *op)
1824 {
1825         if (op->customdata) {
1826                 MEM_freeN(op->customdata);
1827                 op->customdata = NULL;
1828         }
1829         
1830         /* this makes sure aligned edges will result in aligned grabbing */
1831         removedouble_scredges(CTX_wm_screen(C));
1832         removenotused_scredges(CTX_wm_screen(C));
1833         removenotused_scrverts(CTX_wm_screen(C));
1834 }
1835
1836 static int area_join_exec(bContext *C, wmOperator *op)
1837 {
1838         if(!area_join_init(C, op)) 
1839                 return OPERATOR_CANCELLED;
1840         
1841         area_join_apply(C, op);
1842         area_join_exit(C, op);
1843         
1844         return OPERATOR_FINISHED;
1845 }
1846
1847 /* interaction callback */
1848 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1849 {
1850         
1851         if(event->type==EVT_ACTIONZONE_AREA) {
1852                 sActionzoneData *sad= event->customdata;
1853                 
1854                 if(sad->modifier>0) {
1855                         return OPERATOR_PASS_THROUGH;
1856                 }
1857                 
1858                 /* verify *sad itself */
1859                 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1860                         return OPERATOR_PASS_THROUGH;
1861                 
1862                 /* is this our *sad? if areas equal it should be passed on */
1863                 if(sad->sa1==sad->sa2)
1864                         return OPERATOR_PASS_THROUGH;
1865                 
1866                 /* prepare operator state vars */
1867                 RNA_int_set(op->ptr, "min_x", sad->x);
1868                 RNA_int_set(op->ptr, "min_y", sad->y);
1869                 RNA_int_set(op->ptr, "max_x", event->x);
1870                 RNA_int_set(op->ptr, "max_y", event->y);
1871                 
1872                 if(!area_join_init(C, op)) 
1873                         return OPERATOR_PASS_THROUGH;
1874                 
1875                 /* add temp handler */
1876                 WM_event_add_modal_handler(C, op);
1877                 
1878                 return OPERATOR_RUNNING_MODAL;
1879         }
1880         
1881         return OPERATOR_PASS_THROUGH;
1882 }
1883
1884 static int area_join_cancel(bContext *C, wmOperator *op)
1885 {
1886         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1887         
1888         if (jd->sa1) {
1889                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1890                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1891         }
1892         if (jd->sa2) {
1893                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1894                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1895         }
1896         
1897         WM_event_add_notifier(C, NC_WINDOW, NULL);
1898         
1899         area_join_exit(C, op);
1900         
1901         return OPERATOR_CANCELLED;
1902 }
1903
1904 /* modal callback while selecting area (space) that will be removed */
1905 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1906 {
1907         bScreen *sc= CTX_wm_screen(C);
1908         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1909         
1910         /* execute the events */
1911         switch(event->type) {
1912                         
1913                 case MOUSEMOVE: 
1914                 {
1915                         ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1916                         int dir;
1917                         
1918                         if (sa) {                                       
1919                                 if (jd->sa1 != sa) {
1920                                         dir = area_getorientation(sc, jd->sa1, sa);
1921                                         if (dir >= 0) {
1922                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1923                                                 jd->sa2 = sa;
1924                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1925                                         } 
1926                                         else {
1927                                                 /* we are not bordering on the previously selected area 
1928                                                  we check if area has common border with the one marked for removal
1929                                                  in this case we can swap areas.
1930                                                  */
1931                                                 dir = area_getorientation(sc, sa, jd->sa2);
1932                                                 if (dir >= 0) {
1933                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1934                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1935                                                         jd->sa1 = jd->sa2;
1936                                                         jd->sa2 = sa;
1937                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1938                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1939                                                 } 
1940                                                 else {
1941                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1942                                                         jd->sa2 = NULL;
1943                                                 }
1944                                         }
1945                                         WM_event_add_notifier(C, NC_WINDOW, NULL);
1946                                 } 
1947                                 else {
1948                                         /* we are back in the area previously selected for keeping 
1949                                          * we swap the areas if possible to allow user to choose */
1950                                         if (jd->sa2 != NULL) {
1951                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1952                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1953                                                 jd->sa1 = jd->sa2;
1954                                                 jd->sa2 = sa;
1955                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1956                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1957                                                 dir = area_getorientation(sc, jd->sa1, jd->sa2);
1958                                                 if (dir < 0) {
1959                                                         printf("oops, didn't expect that!\n");
1960                                                 }
1961                                         } 
1962                                         else {
1963                                                 dir = area_getorientation(sc, jd->sa1, sa);
1964                                                 if (dir >= 0) {
1965                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1966                                                         jd->sa2 = sa;
1967                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1968                                                 }
1969                                         }
1970                                         WM_event_add_notifier(C, NC_WINDOW, NULL);
1971                                 }
1972                         }
1973                 }
1974                         break;
1975                 case LEFTMOUSE:
1976                         if(event->val==KM_RELEASE) {
1977                                 ED_area_tag_redraw(jd->sa1);
1978                                 ED_area_tag_redraw(jd->sa2);
1979
1980                                 area_join_apply(C, op);
1981                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1982                                 area_join_exit(C, op);
1983                                 return OPERATOR_FINISHED;
1984                         }
1985                         break;
1986                         
1987                 case RIGHTMOUSE:
1988                 case ESCKEY:
1989                         return area_join_cancel(C, op);
1990         }
1991         
1992         return OPERATOR_RUNNING_MODAL;
1993 }
1994
1995 /* Operator for joining two areas (space types) */
1996 static void SCREEN_OT_area_join(wmOperatorType *ot)
1997 {
1998         /* identifiers */
1999         ot->name= "Join area";
2000         ot->description= "Join selected areas into new window";
2001         ot->idname= "SCREEN_OT_area_join";
2002         
2003         /* api callbacks */
2004         ot->exec= area_join_exec;
2005         ot->invoke= area_join_invoke;
2006         ot->modal= area_join_modal;
2007         ot->poll= ED_operator_areaactive;
2008         
2009         ot->flag= OPTYPE_BLOCKING;
2010         
2011         /* rna */
2012         RNA_def_int(ot->srna, "min_x", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
2013         RNA_def_int(ot->srna, "min_y", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
2014         RNA_def_int(ot->srna, "max_x", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
2015         RNA_def_int(ot->srna, "max_y", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
2016 }
2017
2018 /* ************** repeat last operator ***************************** */
2019
2020 static int repeat_last_exec(bContext *C, wmOperator *op)
2021 {
2022         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
2023         
2024         if(lastop)
2025                 WM_operator_repeat(C, lastop);
2026         
2027         return OPERATOR_CANCELLED;
2028 }
2029
2030 static void SCREEN_OT_repeat_last(wmOperatorType *ot)
2031 {
2032         /* identifiers */
2033         ot->name= "Repeat Last";
2034         ot->description= "Repeat last action";
2035         ot->idname= "SCREEN_OT_repeat_last";
2036         
2037         /* api callbacks */
2038         ot->exec= repeat_last_exec;
2039         
2040         ot->poll= ED_operator_screenactive;
2041         
2042 }
2043
2044 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
2045 {
2046         wmWindowManager *wm= CTX_wm_manager(C);
2047         wmOperator *lastop;
2048         uiPopupMenu *pup;
2049         uiLayout *layout;
2050         int items, i;
2051         
2052         items= BLI_countlist(&wm->operators);
2053         if(items==0)
2054                 return OPERATOR_CANCELLED;
2055         
2056         pup= uiPupMenuBegin(C, op->type->name, 0);
2057         layout= uiPupMenuLayout(pup);
2058         
2059         for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
2060                 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
2061         
2062         uiPupMenuEnd(C, pup);
2063         
2064         return OPERATOR_CANCELLED;
2065 }
2066
2067 static int repeat_history_exec(bContext *C, wmOperator *op)
2068 {
2069         wmWindowManager *wm= CTX_wm_manager(C);
2070         
2071         op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
2072         if(op) {
2073                 /* let's put it as last operator in list */
2074                 BLI_remlink(&wm->operators, op);
2075                 BLI_addtail(&wm->operators, op);
2076                 
2077                 WM_operator_repeat(C, op);
2078         }
2079         
2080         return OPERATOR_FINISHED;
2081 }
2082
2083 static void SCREEN_OT_repeat_history(wmOperatorType *ot)
2084 {
2085         /* identifiers */
2086         ot->name= "Repeat History";
2087         ot->description= "Display menu for previous actions performed";
2088         ot->idname= "SCREEN_OT_repeat_history";
2089         
2090         /* api callbacks */
2091         ot->invoke= repeat_history_invoke;
2092         ot->exec= repeat_history_exec;
2093         
2094         ot->poll= ED_operator_screenactive;
2095         
2096         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
2097 }
2098
2099 /* ********************** redo operator ***************************** */
2100
2101 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
2102 {
2103         wmWindowManager *wm= CTX_wm_manager(C);
2104         wmOperator *lastop;
2105         
2106         /* only for operators that are registered and did an undo push */
2107         for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
2108                 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
2109                         break;
2110         
2111         if(lastop)
2112                 WM_operator_redo_popup(C, lastop);
2113         
2114         return OPERATOR_CANCELLED;
2115 }
2116
2117 static void SCREEN_OT_redo_last(wmOperatorType *ot)
2118 {
2119         /* identifiers */
2120         ot->name= "Redo Last";
2121         ot->description= "Display menu for last action performed";
2122         ot->idname= "SCREEN_OT_redo_last";
2123         
2124         /* api callbacks */
2125         ot->invoke= redo_last_invoke;
2126         
2127         ot->poll= ED_operator_screenactive;
2128 }
2129
2130 /* ************** region four-split operator ***************************** */
2131
2132 /* insert a region in the area region list */
2133 static int region_quadview_exec(bContext *C, wmOperator *op)
2134 {
2135         ARegion *ar= CTX_wm_region(C);
2136         
2137         /* some rules... */
2138         if(ar->regiontype!=RGN_TYPE_WINDOW)
2139                 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
2140         else if(ar->alignment==RGN_ALIGN_QSPLIT) {
2141                 ScrArea *sa= CTX_wm_area(C);
2142                 ARegion *arn;
2143                 
2144                 /* keep current region */
2145                 ar->alignment= 0;
2146                 
2147                 if(sa->spacetype==SPACE_VIEW3D) {
2148                         RegionView3D *rv3d= ar->regiondata;
2149                         rv3d->viewlock= 0;
2150                         rv3d->rflag &= ~RV3D_CLIPPING;
2151                 }
2152                 
2153                 for(ar= sa->regionbase.first; ar; ar= arn) {
2154                         arn= ar->next;
2155                         if(ar->alignment==RGN_ALIGN_QSPLIT) {
2156                                 ED_region_exit(C, ar);
2157                                 BKE_area_region_free(sa->type, ar);
2158                                 BLI_remlink(&sa->regionbase, ar);
2159                                 MEM_freeN(ar);
2160                         }
2161                 }
2162                 ED_area_tag_redraw(sa);
2163                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2164         }
2165         else if(ar->next)
2166                 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
2167         else {
2168                 ScrArea *sa= CTX_wm_area(C);
2169                 ARegion *newar;
2170                 int count;
2171                 
2172                 ar->alignment= RGN_ALIGN_QSPLIT;
2173                 
2174                 for(count=0; count<3; count++) {
2175                         newar= BKE_area_region_copy(sa->type, ar);
2176                         BLI_addtail(&sa->regionbase, newar);
2177                 }
2178                 
2179                 /* lock views and set them */
2180                 if(sa->spacetype==SPACE_VIEW3D) {
2181                         RegionView3D *rv3d;
2182                         
2183                         rv3d= ar->regiondata;
2184                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_FRONT; rv3d->persp= RV3D_ORTHO;
2185                         if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2186                         
2187                         ar= ar->next;
2188                         rv3d= ar->regiondata;
2189                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_TOP; rv3d->persp= RV3D_ORTHO;
2190                         if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2191                         
2192                         ar= ar->next;
2193                         rv3d= ar->regiondata;
2194                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_RIGHT; rv3d->persp= RV3D_ORTHO;
2195                         if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2196                         
2197                         ar= ar->next;
2198                         rv3d= ar->regiondata;
2199                         rv3d->view= RV3D_VIEW_CAMERA; rv3d->persp= RV3D_CAMOB;
2200                         if (rv3d->localvd) {rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2201                 }
2202                 ED_area_tag_redraw(sa);
2203                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2204         }
2205         
2206         
2207         return OPERATOR_FINISHED;
2208 }
2209
2210 static void SCREEN_OT_region_quadview(wmOperatorType *ot)
2211 {
2212         /* identifiers */
2213         ot->name= "Toggle Quad View";
2214         ot->description= "Split selected area into camera, front, right & top views";
2215         ot->idname= "SCREEN_OT_region_quadview";
2216         
2217         /* api callbacks */
2218         //      ot->invoke= WM_operator_confirm;
2219         ot->exec= region_quadview_exec;
2220         ot->poll= ED_operator_areaactive;
2221         ot->flag= 0;
2222 }
2223
2224
2225
2226 /* ************** region flip operator ***************************** */
2227
2228 /* flip a region alignment */
2229 static int region_flip_exec(bContext *C, wmOperator *op)
2230 {
2231         ARegion *ar= CTX_wm_region(C);
2232         
2233         if (!ar)
2234                 return OPERATOR_CANCELLED;
2235         
2236         if(ar->alignment==RGN_ALIGN_TOP)
2237                 ar->alignment= RGN_ALIGN_BOTTOM;
2238         else if(ar->alignment==RGN_ALIGN_BOTTOM)
2239                 ar->alignment= RGN_ALIGN_TOP;
2240         else if(ar->alignment==RGN_ALIGN_LEFT)
2241                 ar->alignment= RGN_ALIGN_RIGHT;
2242         else if(ar->alignment==RGN_ALIGN_RIGHT)
2243                 ar->alignment= RGN_ALIGN_LEFT;
2244
2245         ED_area_tag_redraw(CTX_wm_area(C));
2246         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2247         
2248         return OPERATOR_FINISHED;
2249 }
2250
2251
2252 static void SCREEN_OT_region_flip(wmOperatorType *ot)
2253 {
2254         /* identifiers */
2255         ot->name= "Flip Region";
2256         ot->idname= "SCREEN_OT_region_flip";
2257         
2258         /* api callbacks */
2259         ot->exec= region_flip_exec;
2260         ot->poll= ED_operator_areaactive;
2261         ot->flag= 0;
2262 }
2263
2264 /* ************** header flip operator ***************************** */
2265
2266 /* flip a header region alignment */
2267 static int header_flip_exec(bContext *C, wmOperator *op)
2268 {
2269         ARegion *ar= CTX_wm_region(C);
2270         
2271         /* find the header region 
2272          *      - try context first, but upon failing, search all regions in area...
2273          */
2274         if((ar == NULL) || (ar->regiontype != RGN_TYPE_HEADER)) {
2275                 ScrArea *sa= CTX_wm_area(C);
2276                 
2277                 /* loop over all regions until a matching one is found */
2278                 for (ar= sa->regionbase.first; ar; ar= ar->next) {
2279                         if(ar->regiontype == RGN_TYPE_HEADER)
2280                                 break;
2281                 }
2282                 
2283                 /* don't do anything if no region */
2284                 if(ar == NULL)
2285                         return OPERATOR_CANCELLED;
2286         }       
2287         
2288         /* copied from SCREEN_OT_region_flip */
2289         if(ar->alignment==RGN_ALIGN_TOP)
2290                 ar->alignment= RGN_ALIGN_BOTTOM;
2291         else if(ar->alignment==RGN_ALIGN_BOTTOM)
2292                 ar->alignment= RGN_ALIGN_TOP;
2293         else if(ar->alignment==RGN_ALIGN_LEFT)
2294                 ar->alignment= RGN_ALIGN_RIGHT;
2295         else if(ar->alignment==RGN_ALIGN_RIGHT)
2296                 ar->alignment= RGN_ALIGN_LEFT;
2297
2298         ED_area_tag_redraw(CTX_wm_area(C));
2299
2300         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2301         
2302         return OPERATOR_FINISHED;
2303 }
2304
2305
2306 static void SCREEN_OT_header_flip(wmOperatorType *ot)
2307 {
2308         /* identifiers */
2309         ot->name= "Flip Header Region";
2310         ot->idname= "SCREEN_OT_header_flip";
2311         
2312         /* api callbacks */
2313         ot->exec= header_flip_exec;
2314         
2315         ot->poll= ED_operator_areaactive;
2316         ot->flag= 0;
2317 }
2318
2319 /* ************** header tools operator ***************************** */
2320
2321 static int header_toolbox_invoke(bContext *C, wmOperator *op, wmEvent *event)
2322 {
2323         ScrArea *sa= CTX_wm_area(C);
2324         ARegion *ar= CTX_wm_region(C);
2325         uiPopupMenu *pup;
2326         uiLayout *layout;
2327         
2328         pup= uiPupMenuBegin(C, "Header", 0);
2329         layout= uiPupMenuLayout(pup);
2330         
2331         // XXX SCREEN_OT_region_flip doesn't work - gets wrong context for active region, so added custom operator
2332         if (ar->alignment == RGN_ALIGN_TOP)
2333                 uiItemO(layout, "Flip to Bottom", 0, "SCREEN_OT_header_flip");  
2334         else
2335                 uiItemO(layout, "Flip to Top", 0, "SCREEN_OT_header_flip");
2336         
2337         uiItemS(layout);
2338         
2339         /* file browser should be fullscreen all the time, but other regions can be maximised/restored... */
2340         if (sa->spacetype != SPACE_FILE) {
2341                 if (sa->full) 
2342                         uiItemO(layout, "Tile Area", 0, "SCREEN_OT_screen_full_area");
2343                 else
2344                         uiItemO(layout, "Maximize Area", 0, "SCREEN_OT_screen_full_area");
2345         }
2346         
2347         uiPupMenuEnd(C, pup);
2348         
2349         return OPERATOR_CANCELLED;
2350 }
2351
2352 void SCREEN_OT_header_toolbox(wmOperatorType *ot)
2353 {
2354         /* identifiers */
2355         ot->name= "Header Toolbox";
2356         ot->description="Display header region toolbox";
2357         ot->idname= "SCREEN_OT_header_toolbox";
2358         
2359         /* api callbacks */
2360         ot->invoke= header_toolbox_invoke;
2361 }
2362
2363 /* ****************** anim player, with timer ***************** */
2364
2365 static int match_area_with_refresh(int spacetype, int refresh)
2366 {
2367         switch (spacetype) {
2368                 case SPACE_TIME:
2369                         if (refresh & SPACE_TIME)
2370                                 return 1;
2371                         break;
2372         }
2373         
2374         return 0;
2375 }
2376
2377 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2378 {
2379         if(regiontype==RGN_TYPE_WINDOW) {
2380                 
2381                 switch (spacetype) {
2382                         case SPACE_VIEW3D:
2383                                 if(redraws & TIME_ALL_3D_WIN)
2384                                         return 1;
2385                                 break;
2386                         case SPACE_IPO:
2387                         case SPACE_ACTION:
2388                         case SPACE_NLA:
2389                                 if(redraws & TIME_ALL_ANIM_WIN)
2390                                         return 1;
2391                                 break;
2392                         case SPACE_TIME:
2393                                 /* if only 1 window or 3d windows, we do timeline too */
2394                                 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2395                                         return 1;
2396                                 break;
2397                         case SPACE_BUTS:
2398                                 if(redraws & TIME_ALL_BUTS_WIN)
2399                                         return 1;
2400                                 break;
2401                         case SPACE_SEQ:
2402                                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2403                                         return 1;
2404                                 break;
2405                         case SPACE_NODE:
2406                                 if(redraws & (TIME_NODES))
2407                                         return 1;
2408                                 break;
2409                         case SPACE_IMAGE:
2410                                 if(redraws & TIME_ALL_IMAGE_WIN)
2411                                         return 1;
2412                                 break;
2413                                 
2414                 }
2415         }
2416         else if(regiontype==RGN_TYPE_UI) {
2417                 if(redraws & TIME_ALL_BUTS_WIN)
2418                         return 1;
2419         }
2420         else if(regiontype==RGN_TYPE_HEADER) {
2421                 if(spacetype==SPACE_TIME)
2422                         return 1;
2423         }
2424         else if (regiontype==RGN_TYPE_PREVIEW) {
2425                 switch (spacetype) {
2426                         case SPACE_SEQ:
2427                                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2428                                         return 1;
2429                                 break;
2430                 }
2431         }
2432         return 0;
2433 }
2434
2435 static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
2436 {
2437         bScreen *screen= CTX_wm_screen(C);
2438
2439         if(screen->animtimer && screen->animtimer==event->customdata) {
2440                 Scene *scene= CTX_data_scene(C);
2441                 wmTimer *wt= screen->animtimer;
2442                 ScreenAnimData *sad= wt->customdata;
2443                 ScrArea *sa;
2444                 int sync;
2445                 float time;
2446                 
2447                 /* sync, don't sync, or follow scene setting */
2448                 if (sad->flag & ANIMPLAY_FLAG_SYNC) sync= 1;
2449                 else if (sad->flag & ANIMPLAY_FLAG_NO_SYNC) sync= 0;
2450                 else sync= (scene->flag & SCE_FRAME_DROP);
2451                 
2452                 if((scene->audio.flag & AUDIO_SYNC) && !(sad->flag & ANIMPLAY_FLAG_REVERSE) && finite(time = sound_sync_scene(scene)))
2453                         scene->r.cfra = time * FPS + 0.5;
2454                 else
2455                 {
2456                         if (sync) {
2457                                 int step = floor(wt->duration * FPS);
2458                                 /* skip frames */
2459                                 if (sad->flag & ANIMPLAY_FLAG_REVERSE)
2460                                         scene->r.cfra -= step;
2461                                 else
2462                                         scene->r.cfra += step;
2463                                 wt->duration -= ((float)step)/FPS;
2464                         }
2465                         else {
2466                                 /* one frame +/- */
2467                                 if (sad->flag & ANIMPLAY_FLAG_REVERSE)
2468                                         scene->r.cfra--;
2469                                 else
2470                                         scene->r.cfra++;
2471                         }
2472                 }
2473                 
2474                 /* reset 'jumped' flag before checking if we need to jump... */
2475                 sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
2476                 
2477                 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
2478                         /* jump back to end? */
2479                         if (PRVRANGEON) {
2480                                 if (scene->r.cfra < scene->r.psfra) {
2481                                         scene->r.cfra= scene->r.pefra;
2482                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2483                                 }
2484                         }
2485                         else {
2486                                 if (scene->r.cfra < scene->r.sfra) {
2487                                         scene->r.cfra= scene->r.efra;
2488                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2489                                 }
2490                         }
2491                 }
2492                 else {
2493                         /* jump back to start? */
2494                         if (PRVRANGEON) {
2495                                 if (scene->r.cfra > scene->r.pefra) {
2496                                         scene->r.cfra= scene->r.psfra;
2497                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2498                                 }
2499                         }
2500                         else {
2501                                 if (scene->r.cfra > scene->r.efra) {
2502                                         scene->r.cfra= scene->r.sfra;
2503                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2504                                 }
2505                         }
2506                 }
2507                 
2508                 if (sad->flag & ANIMPLAY_FLAG_JUMPED)
2509                         sound_seek_scene(C);
2510                 
2511                 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2512                 ED_update_for_newframe(C, 1);
2513                 
2514                 for (sa= screen->areabase.first; sa; sa= sa->next) {
2515                         ARegion *ar;
2516                         for (ar= sa->regionbase.first; ar; ar= ar->next) {
2517                                 if (ar==sad->ar)
2518                                         ED_region_tag_redraw(ar);
2519                                 else
2520                                         if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2521                                                 ED_region_tag_redraw(ar);
2522                         }
2523                         
2524                         if (match_area_with_refresh(sa->spacetype, sad->refresh))
2525                                 ED_area_tag_refresh(sa);
2526                 }
2527                 
2528                 /* update frame rate info too 
2529                  * NOTE: this may not be accurate enough, since we might need this after modifiers/etc. 
2530                  * have been calculated instead of just before updates have been done?
2531                  */
2532                 ED_refresh_viewport_fps(C);
2533                 
2534                 /* recalculate the timestep for the timer now that we've finished calculating this,
2535                  * since the frames-per-second value may have been changed
2536                  */
2537                 // TODO: this may make evaluation a bit slower if the value doesn't change... any way to avoid this?
2538                 wt->timestep= (1.0/FPS);
2539                 
2540                 return OPERATOR_FINISHED;
2541         }
2542         return OPERATOR_PASS_THROUGH;
2543 }
2544
2545 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2546 {
2547         /* identifiers */
2548         ot->name= "Animation Step";
2549         ot->description= "Step through animation by position";
2550         ot->idname= "SCREEN_OT_animation_step";
2551         
2552         /* api callbacks */
2553         ot->invoke= screen_animation_step;
2554         
2555         ot->poll= ED_operator_screenactive;
2556         
2557 }
2558
2559 /* ****************** anim player, starts or ends timer ***************** */
2560
2561 /* toggle operator */
2562 int ED_screen_animation_play(bContext *C, int sync, int mode)
2563 {
2564         bScreen *screen= CTX_wm_screen(C);
2565         Scene *scene = CTX_data_scene(C);
2566
2567         if (screen->animtimer) {
2568                 /* stop playback now */
2569                 ED_screen_animation_timer(C, 0, 0, 0, 0);
2570                 sound_stop_scene(scene);
2571         }
2572         else {
2573                 ScrArea *sa= CTX_wm_area(C);
2574                 int refresh= SPACE_TIME;
2575                 
2576                 if (mode == 1) // XXX only play audio forwards!?
2577                         sound_play_scene(scene);
2578                 
2579                 /* timeline gets special treatment since it has it's own menu for determining redraws */
2580                 if ((sa) && (sa->spacetype == SPACE_TIME)) {
2581                         SpaceTime *stime= (SpaceTime *)sa->spacedata.first;
2582                         
2583                         ED_screen_animation_timer(C, stime->redraws, refresh, sync, mode);
2584                         
2585                         /* update region if TIME_REGION was set, to leftmost 3d window */
2586                         ED_screen_animation_timer_update(screen, stime->redraws, refresh);
2587                 }
2588                 else {
2589                         int redraws = TIME_REGION|TIME_ALL_3D_WIN;
2590                         
2591                         /* XXX - would like a better way to deal with this situation - Campbell */
2592                         if ((!sa) || (sa->spacetype == SPACE_SEQ)) {
2593                                 redraws |= TIME_SEQ;
2594                         }
2595                         
2596                         ED_screen_animation_timer(C, redraws, refresh, sync, mode);
2597                         
2598                         if(screen->animtimer) {
2599                                 wmTimer *wt= screen->animtimer;
2600                                 ScreenAnimData *sad= wt->customdata;
2601                                 
2602                                 sad->ar= CTX_wm_region(C);
2603                         }
2604                 }
2605         }
2606
2607         return OPERATOR_FINISHED;
2608 }
2609
2610 static int screen_animation_play_exec(bContext *C, wmOperator *op)
2611 {
2612         int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2613         int sync= -1;
2614         
2615         if (RNA_property_is_set(op->ptr, "sync"))
2616                 sync= (RNA_boolean_get(op->ptr, "sync"));
2617         
2618         return ED_screen_animation_play(C, sync, mode);
2619 }
2620
2621 static void SCREEN_OT_animation_play(wmOperatorType *ot)
2622 {
2623         /* identifiers */
2624         ot->name= "Play Animation";
2625         ot->description= "Play animation";
2626         ot->idname= "SCREEN_OT_animation_play";
2627         
2628         /* api callbacks */
2629         ot->exec= screen_animation_play_exec;
2630         
2631         ot->poll= ED_operator_screenactive;
2632         
2633         RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2634         RNA_def_boolean(ot->srna, "sync", 0, "Sync", "Drop frames to maintain framerate");
2635 }
2636
2637 static int screen_animation_cancel_exec(bContext *C, wmOperator *op)
2638 {
2639         bScreen *screen= CTX_wm_screen(C);
2640         
2641         if(screen->animtimer) {
2642                 ScreenAnimData *sad= screen->animtimer->customdata;
2643                 Scene *scene= CTX_data_scene(C);
2644                 
2645                 /* reset current frame before stopping, and just send a notifier to deal with the rest 
2646                  * (since playback still needs to be stopped)
2647                  */
2648                 scene->r.cfra= sad->sfra;
2649                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2650                 
2651                 /* call the other "toggling" operator to clean up now */
2652                 ED_screen_animation_play(C, 0, 0);
2653         }
2654
2655         return OPERATOR_PASS_THROUGH;
2656 }
2657
2658 static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
2659 {
2660         /* identifiers */
2661         ot->name= "Cancel Animation";
2662         ot->description= "Cancel animation, returning to the original frame";
2663         ot->idname= "SCREEN_OT_animation_cancel";
2664         
2665         /* api callbacks */
2666         ot->exec= screen_animation_cancel_exec;
2667         
2668         ot->poll= ED_operator_screenactive;
2669 }
2670
2671 /* ************** border select operator (template) ***************************** */
2672
2673 /* operator state vars used: (added by default WM callbacks)   
2674  xmin, ymin     
2675  xmax, ymax     
2676  
2677  customdata: the wmGesture pointer
2678  
2679  callbacks:
2680  
2681  exec() has to be filled in by user
2682  
2683  invoke() default WM function
2684  adds modal handler
2685  
2686  modal()        default WM function 
2687  accept modal events while doing it, calls exec(), handles ESC and border drawing
2688  
2689  poll() has to be filled in by user for context
2690  */
2691 #if 0
2692 static int border_select_do(bContext *C, wmOperator *op)
2693 {
2694         int event_type= RNA_int_get(op->ptr, "event_type");
2695         
2696         if(event_type==LEFTMOUSE)
2697                 printf("border select do select\n");
2698         else if(event_type==RIGHTMOUSE)
2699                 printf("border select deselect\n");
2700         else 
2701                 printf("border select do something\n");
2702         
2703         return 1;
2704 }
2705
2706 static void SCREEN_OT_border_select(wmOperatorType *ot)
2707 {
2708         /* identifiers */
2709         ot->name= "Border select";
2710         ot->idname= "SCREEN_OT_border_select";
2711         
2712         /* api callbacks */
2713         ot->exec= border_select_do;
2714         ot->invoke= WM_border_select_invoke;
2715         ot->modal= WM_border_select_modal;
2716         
2717         ot->poll= ED_operator_areaactive;
2718         
2719         /* rna */
2720         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2721         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2722         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2723         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2724         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2725         
2726 }
2727 #endif
2728
2729 /* *********************** generic fullscreen 'back' button *************** */
2730
2731
2732 static int fullscreen_back_exec(bContext *C, wmOperator *op)
2733 {
2734         bScreen *screen = CTX_wm_screen(C);
2735         ScrArea *sa=NULL;
2736         
2737         /* search current screen for 'fullscreen' areas */
2738         for (sa=screen->areabase.first; sa; sa=sa->next) {
2739                 if (sa->full) break;
2740         }
2741         if (!sa) {
2742                 BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found.");
2743                 return OPERATOR_CANCELLED;
2744         }
2745         
2746         ED_screen_full_restore(C, sa);
2747         
2748         return OPERATOR_FINISHED;
2749 }
2750
2751 static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
2752 {
2753         /* identifiers */
2754         ot->name= "Back to Previous Screen";
2755         ot->description= "Revert back to the original screen layout, before fullscreen area overlay";
2756         ot->idname= "SCREEN_OT_back_to_previous";
2757         
2758         /* api callbacks */
2759         ot->exec= fullscreen_back_exec;
2760         ot->poll= ED_operator_screenactive;
2761 }
2762
2763 /* *********** show user pref window ****** */
2764
2765 static int userpref_show_invoke(bContext *C, wmOperator *unused, wmEvent *event)
2766 {
2767         ScrArea *sa;
2768         rcti rect;
2769         int sizex, sizey;
2770         
2771         sizex= 800;
2772         sizey= 480;
2773         
2774         /* some magic to calculate postition */
2775         rect.xmin= event->x + CTX_wm_window(C)->posx - sizex/2;
2776         rect.ymin= event->y + CTX_wm_window(C)->posy - sizey/2;
2777         rect.xmax= rect.xmin + sizex;
2778         rect.ymax= rect.ymin + sizey;
2779         
2780         /* changes context! */
2781         WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS);
2782         
2783         sa= CTX_wm_area(C);
2784         
2785         
2786         return OPERATOR_FINISHED;
2787 }
2788
2789
2790 static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
2791 {
2792         /* identifiers */
2793         ot->name= "Show/Hide User Preferences";
2794         ot->description= "Show/hide user preferences";
2795         ot->idname= "SCREEN_OT_userpref_show";
2796         
2797         /* api callbacks */
2798         ot->invoke= userpref_show_invoke;
2799         ot->poll= ED_operator_screenactive;
2800 }
2801
2802 /********************* new screen operator *********************/
2803
2804 static int screen_new_exec(bContext *C, wmOperator *op)
2805 {
2806         wmWindow *win= CTX_wm_window(C);
2807         bScreen *sc= CTX_wm_screen(C);
2808         
2809         sc= ED_screen_duplicate(win, sc);
2810         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENBROWSE, sc);
2811         
2812         return OPERATOR_FINISHED;
2813 }
2814
2815 void SCREEN_OT_new(wmOperatorType *ot)
2816 {
2817         /* identifiers */
2818         ot->name= "New Screen";
2819         ot->description= "Add a new screen";
2820         ot->idname= "SCREEN_OT_new";
2821         
2822         /* api callbacks */
2823         ot->exec= screen_new_exec;
2824         
2825         /* flags */
2826         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2827 }
2828
2829 /********************* delete screen operator *********************/
2830
2831 static int screen_delete_exec(bContext *C, wmOperator *op)
2832 {
2833         bScreen *sc= CTX_wm_screen(C);
2834         
2835         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENDELETE, sc);
2836         
2837         return OPERATOR_FINISHED;
2838 }
2839
2840 void SCREEN_OT_delete(wmOperatorType *ot)
2841 {
2842         /* identifiers */
2843         ot->name= "Delete Screen"; //was scene
2844         ot->description= "Delete active screen";
2845         ot->idname= "SCREEN_OT_delete";
2846         
2847         /* api callbacks */
2848         ot->exec= screen_delete_exec;
2849         
2850         /* flags */
2851         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2852 }
2853
2854 /********************* new scene operator *********************/
2855
2856 static int scene_new_exec(bContext *C, wmOperator *op)
2857 {
2858         Scene *newscene, *scene= CTX_data_scene(C);
2859         Main *bmain= CTX_data_main(C);
2860         int type= RNA_enum_get(op->ptr, "type");
2861         
2862         newscene= copy_scene(bmain, scene, type);
2863         
2864         /* these can't be handled in blenkernel curently, so do them here */
2865         if(type == SCE_COPY_LINK_DATA)
2866                 ED_object_single_users(bmain, newscene, 0);
2867         else if(type == SCE_COPY_FULL)
2868                 ED_object_single_users(bmain, newscene, 1);
2869         
2870         WM_event_add_notifier(C, NC_SCENE|ND_SCENEBROWSE, newscene);
2871         
2872         return OPERATOR_FINISHED;
2873 }
2874
2875 void SCENE_OT_new(wmOperatorType *ot)
2876 {
2877         static EnumPropertyItem type_items[]= {
2878                 {SCE_COPY_EMPTY, "EMPTY", 0, "Empty", "Add empty scene"},
2879                 {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene"},
2880                 {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene"},
2881                 {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene"},
2882                 {0, NULL, 0, NULL, NULL}};
2883         
2884         /* identifiers */
2885         ot->name= "New Scene";
2886         ot->description= "Add new scene by type";
2887         ot->idname= "SCENE_OT_new";
2888         
2889         /* api callbacks */
2890         ot->exec= scene_new_exec;
2891         ot->invoke= WM_menu_invoke;
2892         
2893         /* flags */
2894         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2895         
2896         /* properties */
2897         ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
2898 }
2899
2900 /********************* delete scene operator *********************/
2901
2902 static int scene_delete_exec(bContext *C, wmOperator *op)
2903 {
2904         Scene *scene= CTX_data_scene(C);
2905         
2906         WM_event_add_notifier(C, NC_SCENE|NA_REMOVED, scene);
2907         
2908         return OPERATOR_FINISHED;
2909 }
2910
2911 void SCENE_OT_delete(wmOperatorType *ot)
2912 {
2913         /* identifiers */
2914         ot->name= "Delete Scene";
2915         ot->description= "Delete active scene";
2916         ot->idname= "SCENE_OT_delete";
2917         
2918         /* api callbacks */
2919         ot->exec= scene_delete_exec;
2920         
2921         /* flags */
2922         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2923 }
2924
2925 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
2926
2927 /* called in spacetypes.c */
2928 void ED_operatortypes_screen(void)
2929 {
2930         /* generic UI stuff */
2931         WM_operatortype_append(SCREEN_OT_actionzone);
2932         WM_operatortype_append(SCREEN_OT_repeat_last);
2933         WM_operatortype_append(SCREEN_OT_repeat_history);
2934         WM_operatortype_append(SCREEN_OT_redo_last);
2935         
2936         /* screen tools */
2937         WM_operatortype_append(SCREEN_OT_area_move);
2938         WM_operatortype_append(SCREEN_OT_area_split);
2939         WM_operatortype_append(SCREEN_OT_area_join);
2940         WM_operatortype_append(SCREEN_OT_area_dupli);
2941         WM_operatortype_append(SCREEN_OT_area_swap);
2942         WM_operatortype_append(SCREEN_OT_region_quadview);
2943         WM_operatortype_append(SCREEN_OT_region_scale);
2944         WM_operatortype_append(SCREEN_OT_region_flip);
2945         WM_operatortype_append(SCREEN_OT_header_flip);
2946         WM_operatortype_append(SCREEN_OT_header_toolbox);
2947         WM_operatortype_append(SCREEN_OT_screen_set);
2948         WM_operatortype_append(SCREEN_OT_screen_full_area);
2949         WM_operatortype_append(SCREEN_OT_back_to_previous);
2950         WM_operatortype_append(SCREEN_OT_screenshot);
2951         WM_operatortype_append(SCREEN_OT_screencast);
2952         WM_operatortype_append(SCREEN_OT_userpref_show);
2953         
2954         /*frame changes*/
2955         WM_operatortype_append(SCREEN_OT_frame_offset);
2956         WM_operatortype_append(SCREEN_OT_frame_jump);
2957         WM_operatortype_append(SCREEN_OT_keyframe_jump);
2958         
2959         WM_operatortype_append(SCREEN_OT_animation_step);
2960         WM_operatortype_append(SCREEN_OT_animation_play);
2961         WM_operatortype_append(SCREEN_OT_animation_cancel);
2962         
2963         /* new/delete */
2964         WM_operatortype_append(SCREEN_OT_new);
2965         WM_operatortype_append(SCREEN_OT_delete);
2966         WM_operatortype_append(SCENE_OT_new);
2967         WM_operatortype_append(SCENE_OT_delete);
2968         
2969         /* tools shared by more space types */
2970         WM_operatortype_append(ED_OT_undo);
2971         WM_operatortype_append(ED_OT_redo);     
2972         
2973 }
2974
2975 static void keymap_modal_set(wmKeyConfig *keyconf)
2976 {
2977         static EnumPropertyItem modal_items[] = {
2978                 {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
2979                 {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
2980                 {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""},
2981                 {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""},
2982                 {0, NULL, 0, NULL, NULL}};
2983         wmKeyMap *keymap;
2984         
2985         /* Standard Modal keymap ------------------------------------------------ */
2986         keymap= WM_modalkeymap_add(keyconf, "Standard Modal Map", modal_items);
2987         
2988         WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, KM_MODAL_CANCEL);
2989         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KM_MODAL_APPLY);
2990         WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
2991         WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
2992         
2993         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10);
2994         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF);
2995         
2996         WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
2997         
2998 }
2999
3000 /* called in spacetypes.c */
3001 void ED_keymap_screen(wmKeyConfig *keyconf)
3002 {
3003         wmKeyMap *keymap;
3004         //wmKeyMapItem *kmi;
3005         
3006         /* Screen Editing ------------------------------------------------ */
3007         keymap= WM_keymap_find(keyconf, "Screen Editing", 0, 0);
3008         
3009         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
3010         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
3011         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "modifier", 2);
3012         
3013         /* screen tools */
3014         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
3015         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
3016         WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
3017         WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_CTRL, 0);
3018         WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
3019         /* area move after action zones */
3020         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
3021         
3022         /* Header Editing ------------------------------------------------ */
3023         keymap= WM_keymap_find(keyconf, "Header", 0, 0);
3024         
3025         WM_keymap_add_item(keymap, "SCREEN_OT_header_toolbox", RIGHTMOUSE, KM_PRESS, 0, 0);
3026         
3027         /* Screen General ------------------------------------------------ */
3028         keymap= WM_keymap_find(keyconf, "Screen", 0, 0);
3029         
3030         /* standard timers */
3031         WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
3032         
3033         
3034         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
3035         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
3036         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
3037         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
3038         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_SHIFT, 0);
3039         WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
3040         WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
3041         
3042         /* tests */
3043         WM_keymap_add_item(keymap, "SCREEN_OT_region_quadview", QKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
3044         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
3045         WM_keymap_add_item(keymap, "SCREEN_OT_repeat_last", RKEY, KM_PRESS, KM_SHIFT, 0);
3046         WM_keymap_verify_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
3047         WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
3048         WM_keymap_verify_item(keymap, "SCRIPT_OT_reload", F8KEY, KM_PRESS, 0, 0);
3049         
3050         /* files */
3051         WM_keymap_add_item(keymap, "FILE_OT_execute", RETKEY, KM_PRESS, 0, 0);
3052         WM_keymap_add_item(keymap, "FILE_OT_execute", PADENTER, KM_PRESS, 0, 0);
3053         WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
3054         
3055         /* undo */
3056 #ifdef __APPLE__
3057         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
3058         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
3059 #endif
3060         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
3061         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
3062         
3063         
3064         /* render */
3065         WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, 0, 0);
3066         RNA_boolean_set(WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, KM_CTRL, 0)->ptr, "animation", 1);
3067         WM_keymap_add_item(keymap, "RENDER_OT_view_cancel", ESCKEY, KM_PRESS, 0, 0);
3068         WM_keymap_add_item(keymap, "RENDER_OT_view_show", F11KEY, KM_PRESS, 0, 0);
3069         WM_keymap_add_item(keymap, "RENDER_OT_play_rendered_anim", F11KEY, KM_PRESS, KM_CTRL, 0);
3070         
3071         /* user prefs */
3072 #ifdef __APPLE__
3073         WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", COMMAKEY, KM_PRESS, KM_OSKEY, 0);
3074 #endif
3075         WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", UKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
3076         
3077         
3078         /* Anim Playback ------------------------------------------------ */
3079         keymap= WM_keymap_find(keyconf, "Frames", 0, 0);
3080         
3081         /* frame offsets */
3082         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
3083         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
3084         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
3085         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
3086         
3087         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "delta", 1);
3088         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", WHEELUPMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "delta", -1);
3089         
3090         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", UPARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 1);
3091         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 0);
3092         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 1);
3093         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 0);
3094         
3095         WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", PAGEUPKEY, KM_PRESS, KM_CTRL, 0);
3096         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", PAGEDOWNKEY, KM_PRESS, KM_CTRL, 0)->ptr, "next", 0);
3097         
3098         /* play (forward and backwards) */
3099         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
3100         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT|KM_SHIFT, 0)->ptr, "reverse", 1);
3101         WM_keymap_add_item(keymap, "SCREEN_OT_animation_cancel", ESCKEY, KM_PRESS, 0, 0);
3102         
3103         /* Alternative keys for animation and sequencer playing */
3104 #if 0 // XXX: disabled for restoring later... bad implementation
3105         keymap= WM_keymap_find(keyconf, "Frames", 0, 0);
3106         kmi = WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", RIGHTARROWKEY, KM_PRESS, KM_ALT, 0);
3107                 RNA_boolean_set(kmi->ptr, "cycle_speed", 1);
3108         
3109         kmi = WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", LEFTARROWKEY, KM_PRESS, KM_ALT, 0);
3110                 RNA_boolean_set(kmi->ptr, "reverse", 1);
3111                 RNA_boolean_set(kmi->ptr, "cycle_speed", 1);
3112         
3113         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", DOWNARROWKEY, KM_PRESS, KM_ALT, 0);
3114 #endif
3115
3116         keymap_modal_set(keyconf);
3117 }
3118