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