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