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