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