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