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