svn merge ^/trunk/blender -r41226:41227 .
[blender.git] / source / blender / editors / screen / screen_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 /** \file blender/editors/screen/screen_ops.c
26  *  \ingroup edscr
27  */
28
29
30 #include <math.h>
31 #include <string.h>
32
33 #include "MEM_guardedalloc.h"
34
35 #include "BLI_math.h"
36 #include "BLI_blenlib.h"
37 #include "BLI_editVert.h"
38 #include "BLI_dlrbTree.h"
39 #include "BLI_utildefines.h"
40
41 #include "DNA_armature_types.h"
42 #include "DNA_lattice_types.h"
43 #include "DNA_object_types.h"
44 #include "DNA_curve_types.h"
45 #include "DNA_scene_types.h"
46 #include "DNA_meta_types.h"
47
48 #include "BKE_context.h"
49 #include "BKE_customdata.h"
50 #include "BKE_global.h"
51 #include "BKE_main.h"
52 #include "BKE_mesh.h"
53 #include "BKE_object.h"
54 #include "BKE_report.h"
55 #include "BKE_scene.h"
56 #include "BKE_screen.h"
57 #include "BKE_tessmesh.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_btmesh;
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= object_pose_armature_get(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
365         return ED_space_image_show_uvedit(sima, obedit);
366 }
367
368 int ED_operator_uvmap(bContext *C)
369 {
370         Object *obedit= CTX_data_edit_object(C);
371         BMEditMesh *em= NULL;
372         
373         if(obedit && obedit->type==OB_MESH)
374                 em= ((Mesh *)obedit->data)->edit_btmesh;
375         
376         if(em && (em->bm->totface))
377                 return 1;
378         
379         return 0;
380 }
381
382 int ED_operator_editsurfcurve(bContext *C)
383 {
384         Object *obedit= CTX_data_edit_object(C);
385         if(obedit && ELEM(obedit->type, OB_CURVE, OB_SURF))
386                 return NULL != ((Curve *)obedit->data)->editnurb;
387         return 0;
388 }
389
390 int ED_operator_editsurfcurve_region_view3d(bContext *C)
391 {
392         if(ED_operator_editsurfcurve(C) && CTX_wm_region_view3d(C))
393                 return 1;
394
395         CTX_wm_operator_poll_msg_set(C, "expected a view3d region & editcurve");
396         return 0;
397 }
398
399 int ED_operator_editcurve(bContext *C)
400 {
401         Object *obedit= CTX_data_edit_object(C);
402         if(obedit && obedit->type==OB_CURVE)
403                 return NULL != ((Curve *)obedit->data)->editnurb;
404         return 0;
405 }
406
407 int ED_operator_editsurf(bContext *C)
408 {
409         Object *obedit= CTX_data_edit_object(C);
410         if(obedit && obedit->type==OB_SURF)
411                 return NULL != ((Curve *)obedit->data)->editnurb;
412         return 0;
413 }
414
415 int ED_operator_editfont(bContext *C)
416 {
417         Object *obedit= CTX_data_edit_object(C);
418         if(obedit && obedit->type==OB_FONT)
419                 return NULL != ((Curve *)obedit->data)->editfont;
420         return 0;
421 }
422
423 int ED_operator_editlattice(bContext *C)
424 {
425         Object *obedit= CTX_data_edit_object(C);
426         if(obedit && obedit->type==OB_LATTICE)
427                 return NULL != ((Lattice *)obedit->data)->editlatt;
428         return 0;
429 }
430
431 int ED_operator_editmball(bContext *C)
432 {
433         Object *obedit= CTX_data_edit_object(C);
434         if(obedit && obedit->type==OB_MBALL)
435                 return NULL != ((MetaBall *)obedit->data)->editelems;
436         return 0;
437 }
438
439 /* *************************** action zone operator ************************** */
440
441 /* operator state vars used:  
442  none
443  
444  functions:
445  
446  apply() set actionzone event
447  
448  exit() free customdata
449  
450  callbacks:
451  
452  exec() never used
453  
454  invoke() check if in zone  
455  add customdata, put mouseco and area in it
456  add modal handler
457  
458  modal()        accept modal events while doing it
459  call apply() with gesture info, active window, nonactive window
460  call exit() and remove handler when LMB confirm
461  
462  */
463
464 typedef struct sActionzoneData {
465         ScrArea *sa1, *sa2;
466         AZone *az;
467         int x, y, gesture_dir, modifier;
468 } sActionzoneData;
469
470 /* used by other operators too */
471 static ScrArea *screen_areahascursor(bScreen *scr, int x, int y)
472 {
473         ScrArea *sa= NULL;
474         sa= scr->areabase.first;
475         while(sa) {
476                 if(BLI_in_rcti(&sa->totrct, x, y)) break;
477                 sa= sa->next;
478         }
479         
480         return sa;
481 }
482
483 /* quick poll to save operators to be created and handled */
484 static int actionzone_area_poll(bContext *C)
485 {
486         wmWindow *win= CTX_wm_window(C);
487         ScrArea *sa= CTX_wm_area(C);
488         
489         if(sa && win) {
490                 AZone *az;
491                 int x= win->eventstate->x;
492                 int y= win->eventstate->y;
493                 
494                 for(az= sa->actionzones.first; az; az= az->next)
495                         if(BLI_in_rcti(&az->rect, x, y))
496                                 return 1;
497         }       
498         return 0;
499 }
500
501 AZone *is_in_area_actionzone(ScrArea *sa, int x, int y)
502 {
503         AZone *az= NULL;
504         
505         for(az= sa->actionzones.first; az; az= az->next) {
506                 if(BLI_in_rcti(&az->rect, x, y)) {
507                         if(az->type == AZONE_AREA) {
508                                 /* no triangle intersect but a hotspot circle based on corner */
509                                 int radius= (x-az->x1)*(x-az->x1) + (y-az->y1)*(y-az->y1);
510                                 
511                                 if(radius <= AZONESPOT*AZONESPOT)
512                                         break;
513                         }
514                         else if(az->type == AZONE_REGION) {
515                                 break;
516                         }
517                 }
518         }
519         
520         return az;
521 }
522
523
524 static void actionzone_exit(wmOperator *op)
525 {
526         if(op->customdata)
527                 MEM_freeN(op->customdata);
528         op->customdata= NULL;
529 }
530
531 /* send EVT_ACTIONZONE event */
532 static void actionzone_apply(bContext *C, wmOperator *op, int type)
533 {
534         wmEvent event;
535         wmWindow *win= CTX_wm_window(C);
536         sActionzoneData *sad= op->customdata;
537         
538         sad->modifier= RNA_int_get(op->ptr, "modifier");
539         
540         event= *(win->eventstate);      /* XXX huh huh? make api call */
541         if(type==AZONE_AREA)
542                 event.type= EVT_ACTIONZONE_AREA;
543         else
544                 event.type= EVT_ACTIONZONE_REGION;
545         event.customdata= op->customdata;
546         event.customdatafree= TRUE;
547         op->customdata= NULL;
548         
549         wm_event_add(win, &event);
550 }
551
552 static int actionzone_invoke(bContext *C, wmOperator *op, wmEvent *event)
553 {
554         AZone *az= is_in_area_actionzone(CTX_wm_area(C), event->x, event->y);
555         sActionzoneData *sad;
556         
557         /* quick escape */
558         if(az==NULL)
559                 return OPERATOR_PASS_THROUGH;
560         
561         /* ok we do the actionzone */
562         sad= op->customdata= MEM_callocN(sizeof(sActionzoneData), "sActionzoneData");
563         sad->sa1= CTX_wm_area(C);
564         sad->az= az;
565         sad->x= event->x; sad->y= event->y;
566         
567         /* region azone directly reacts on mouse clicks */
568         if(sad->az->type==AZONE_REGION) {
569                 actionzone_apply(C, op, AZONE_REGION);
570                 actionzone_exit(op);
571                 return OPERATOR_FINISHED;
572         }
573         else {
574                 /* add modal handler */
575                 WM_event_add_modal_handler(C, op);
576                 
577                 return OPERATOR_RUNNING_MODAL;
578         }
579 }
580
581
582 static int actionzone_modal(bContext *C, wmOperator *op, wmEvent *event)
583 {
584         sActionzoneData *sad= op->customdata;
585         int deltax, deltay;
586         int mindelta= sad->az->type==AZONE_REGION?1:12;
587         
588         switch(event->type) {
589                 case MOUSEMOVE:
590                         /* calculate gesture direction */
591                         deltax= (event->x - sad->x);
592                         deltay= (event->y - sad->y);
593                         
594                         if(deltay > ABS(deltax))
595                                 sad->gesture_dir= 'n';
596                         else if(deltax > ABS(deltay))
597                                 sad->gesture_dir= 'e';
598                         else if(deltay < -ABS(deltax))
599                                 sad->gesture_dir= 's';
600                         else
601                                 sad->gesture_dir= 'w';
602                         
603                         /* gesture is large enough? */
604                         if(ABS(deltax) > mindelta || ABS(deltay) > mindelta) {
605                                 
606                                 /* second area, for join */
607                                 sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
608                                 /* apply sends event */
609                                 actionzone_apply(C, op, sad->az->type);
610                                 actionzone_exit(op);
611                                 
612                                 return OPERATOR_FINISHED;
613                         }
614                         break;
615                 case ESCKEY:
616                         actionzone_exit(op);
617                         return OPERATOR_CANCELLED;
618                 case LEFTMOUSE:                         
619                         actionzone_exit(op);
620                         return OPERATOR_CANCELLED;
621                         
622         }
623         
624         return OPERATOR_RUNNING_MODAL;
625 }
626
627 static int actionzone_cancel(bContext *UNUSED(C), wmOperator *op)
628 {
629         actionzone_exit(op);
630
631         return OPERATOR_CANCELLED;
632 }
633
634 static void SCREEN_OT_actionzone(wmOperatorType *ot)
635 {
636         /* identifiers */
637         ot->name= "Handle area action zones";
638         ot->description= "Handle area action zones for mouse actions/gestures";
639         ot->idname= "SCREEN_OT_actionzone";
640         
641         ot->invoke= actionzone_invoke;
642         ot->modal= actionzone_modal;
643         ot->poll= actionzone_area_poll;
644         ot->cancel= actionzone_cancel;
645         
646         ot->flag= OPTYPE_BLOCKING;
647         
648         RNA_def_int(ot->srna, "modifier", 0, 0, 2, "Modifier", "Modifier state", 0, 2);
649 }
650
651 /* ************** swap area operator *********************************** */
652
653 /* operator state vars used:  
654  sa1            start area
655  sa2            area to swap with
656  
657  functions:
658  
659  init()   set custom data for operator, based on actionzone event custom data
660  
661  cancel()       cancel the operator
662  
663  exit() cleanup, send notifier
664  
665  callbacks:
666  
667  invoke() gets called on shift+lmb drag in actionzone
668  call init(), add handler
669  
670  modal()  accept modal events while doing it
671  
672  */
673
674 typedef struct sAreaSwapData {
675         ScrArea *sa1, *sa2;
676 } sAreaSwapData;
677
678 static int area_swap_init(wmOperator *op, wmEvent *event)
679 {
680         sAreaSwapData *sd= NULL;
681         sActionzoneData *sad= event->customdata;
682         
683         if(sad==NULL || sad->sa1==NULL)
684                 return 0;
685         
686         sd= MEM_callocN(sizeof(sAreaSwapData), "sAreaSwapData");
687         sd->sa1= sad->sa1;
688         sd->sa2= sad->sa2;
689         op->customdata= sd;
690         
691         return 1;
692 }
693
694
695 static void area_swap_exit(bContext *C, wmOperator *op)
696 {
697         WM_cursor_restore(CTX_wm_window(C));
698         if(op->customdata)
699                 MEM_freeN(op->customdata);
700         op->customdata= NULL;
701 }
702
703 static int area_swap_cancel(bContext *C, wmOperator *op)
704 {
705         area_swap_exit(C, op);
706         return OPERATOR_CANCELLED;
707 }
708
709 static int area_swap_invoke(bContext *C, wmOperator *op, wmEvent *event)
710 {
711         
712         if(!area_swap_init(op, event))
713                 return OPERATOR_PASS_THROUGH;
714         
715         /* add modal handler */
716         WM_cursor_modal(CTX_wm_window(C), BC_SWAPAREA_CURSOR);
717         WM_event_add_modal_handler(C, op);
718         
719         return OPERATOR_RUNNING_MODAL;
720         
721 }
722
723 static int area_swap_modal(bContext *C, wmOperator *op, wmEvent *event)
724 {
725         sActionzoneData *sad= op->customdata;
726         
727         switch(event->type) {
728                 case MOUSEMOVE:
729                         /* second area, for join */
730                         sad->sa2= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);
731                         break;
732                 case LEFTMOUSE: /* release LMB */
733                         if(event->val==KM_RELEASE) {
734                                 if(!sad->sa2 || sad->sa1 == sad->sa2) {
735                                         
736                                         return area_swap_cancel(C, op);
737                                 }
738
739                                 ED_area_tag_redraw(sad->sa1);
740                                 ED_area_tag_redraw(sad->sa2);
741
742                                 ED_area_swapspace(C, sad->sa1, sad->sa2);
743                                 
744                                 area_swap_exit(C, op);
745                                 
746                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
747                                 
748                                 return OPERATOR_FINISHED;
749                         }
750                         break;
751                         
752                 case ESCKEY:
753                         return area_swap_cancel(C, op);
754         }
755         return OPERATOR_RUNNING_MODAL;
756 }
757
758 static void SCREEN_OT_area_swap(wmOperatorType *ot)
759 {
760         ot->name= "Swap areas";
761         ot->description= "Swap selected areas screen positions";
762         ot->idname= "SCREEN_OT_area_swap";
763         
764         ot->invoke= area_swap_invoke;
765         ot->modal= area_swap_modal;
766         ot->poll= ED_operator_areaactive;
767         ot->cancel= area_swap_cancel;
768         
769         ot->flag= OPTYPE_BLOCKING;
770 }
771
772 /* *********** Duplicate area as new window operator ****************** */
773
774 /* operator callback */
775 static int area_dupli_invoke(bContext *C, wmOperator *op, wmEvent *event)
776 {
777         wmWindow *newwin, *win;
778         bScreen *newsc, *sc;
779         ScrArea *sa;
780         rcti rect;
781         
782         win= CTX_wm_window(C);
783         sc= CTX_wm_screen(C);
784         sa= CTX_wm_area(C);
785         
786         /* XXX hrmf! */
787         if(event->type==EVT_ACTIONZONE_AREA) {
788                 sActionzoneData *sad= event->customdata;
789                 
790                 if(sad==NULL)
791                         return OPERATOR_PASS_THROUGH;
792                 
793                 sa= sad->sa1;
794         }
795         
796         /*  poll() checks area context, but we don't accept full-area windows */
797         if(sc->full != SCREENNORMAL) {
798                 if(event->type==EVT_ACTIONZONE_AREA)
799                         actionzone_exit(op);
800                 return OPERATOR_CANCELLED;
801         }
802         
803         /* adds window to WM */
804         rect= sa->totrct;
805         BLI_translate_rcti(&rect, win->posx, win->posy);
806         newwin= WM_window_open(C, &rect);
807         
808         /* allocs new screen and adds to newly created window, using window size */
809         newsc= ED_screen_add(newwin, CTX_data_scene(C), sc->id.name+2);
810         newwin->screen= newsc;
811         
812         /* copy area to new screen */
813         area_copy_data((ScrArea *)newsc->areabase.first, sa, 0);
814
815         ED_area_tag_redraw((ScrArea *)newsc->areabase.first);
816
817         /* screen, areas init */
818         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
819         
820         if(event->type==EVT_ACTIONZONE_AREA)
821                 actionzone_exit(op);
822         
823         return OPERATOR_FINISHED;
824 }
825
826 static void SCREEN_OT_area_dupli(wmOperatorType *ot)
827 {
828         ot->name= "Duplicate Area into New Window";
829         ot->description= "Duplicate selected area into new window";
830         ot->idname= "SCREEN_OT_area_dupli";
831         
832         ot->invoke= area_dupli_invoke;
833         ot->poll= ED_operator_areaactive;
834 }
835
836
837 /* ************** move area edge operator *********************************** */
838
839 /* operator state vars used:  
840  x, y                           mouse coord near edge
841  delta            movement of edge
842  
843  functions:
844  
845  init()   set default property values, find edge based on mouse coords, test
846  if the edge can be moved, select edges, calculate min and max movement
847  
848  apply()        apply delta on selection
849  
850  exit() cleanup, send notifier
851  
852  cancel() cancel moving
853  
854  callbacks:
855  
856  exec()   execute without any user interaction, based on properties
857  call init(), apply(), exit()
858  
859  invoke() gets called on mouse click near edge
860  call init(), add handler
861  
862  modal()  accept modal events while doing it
863  call apply() with delta motion
864  call exit() and remove handler
865  
866  */
867
868 typedef struct sAreaMoveData {
869         int bigger, smaller, origval, step;
870         char dir;
871 } sAreaMoveData;
872
873 /* helper call to move area-edge, sets limits */
874 static void area_move_set_limits(bScreen *sc, int dir, int *bigger, int *smaller)
875 {
876         ScrArea *sa;
877         int areaminy= ED_area_headersize()+1;
878         
879         /* we check all areas and test for free space with MINSIZE */
880         *bigger= *smaller= 100000;
881         
882         for(sa= sc->areabase.first; sa; sa= sa->next) {
883                 if(dir=='h') {
884                         int y1= sa->v2->vec.y - sa->v1->vec.y-areaminy;
885                         
886                         /* if top or down edge selected, test height */
887                         if(sa->v1->flag && sa->v4->flag)
888                                 *bigger= MIN2(*bigger, y1);
889                         else if(sa->v2->flag && sa->v3->flag)
890                                 *smaller= MIN2(*smaller, y1);
891                 }
892                 else {
893                         int x1= sa->v4->vec.x - sa->v1->vec.x-AREAMINX;
894                         
895                         /* if left or right edge selected, test width */
896                         if(sa->v1->flag && sa->v2->flag)
897                                 *bigger= MIN2(*bigger, x1);
898                         else if(sa->v3->flag && sa->v4->flag)
899                                 *smaller= MIN2(*smaller, x1);
900                 }
901         }
902 }
903
904 /* validate selection inside screen, set variables OK */
905 /* return 0: init failed */
906 static int area_move_init (bContext *C, wmOperator *op)
907 {
908         bScreen *sc= CTX_wm_screen(C);
909         ScrEdge *actedge;
910         sAreaMoveData *md;
911         int x, y;
912         
913         /* required properties */
914         x= RNA_int_get(op->ptr, "x");
915         y= RNA_int_get(op->ptr, "y");
916         
917         /* setup */
918         actedge= screen_find_active_scredge(sc, x, y);
919         if(actedge==NULL) return 0;
920         
921         md= MEM_callocN(sizeof(sAreaMoveData), "sAreaMoveData");
922         op->customdata= md;
923         
924         md->dir= scredge_is_horizontal(actedge)?'h':'v';
925         if(md->dir=='h') md->origval= actedge->v1->vec.y;
926         else md->origval= actedge->v1->vec.x;
927         
928         select_connected_scredge(sc, actedge);
929         /* now all vertices with 'flag==1' are the ones that can be moved. */
930         
931         area_move_set_limits(sc, md->dir, &md->bigger, &md->smaller);
932         
933         return 1;
934 }
935
936 /* moves selected screen edge amount of delta, used by split & move */
937 static void area_move_apply_do(bContext *C, int origval, int delta, int dir, int bigger, int smaller)
938 {
939         wmWindow *win= CTX_wm_window(C);
940         bScreen *sc= CTX_wm_screen(C);
941         ScrVert *v1;
942         ScrArea *sa;
943         int areaminy= ED_area_headersize()+1;
944         
945         delta= CLAMPIS(delta, -smaller, bigger);
946         
947         for (v1= sc->vertbase.first; v1; v1= v1->next) {
948                 if (v1->flag) {
949                         /* that way a nice AREAGRID  */
950                         if((dir=='v') && v1->vec.x>0 && v1->vec.x<win->sizex-1) {
951                                 v1->vec.x= origval + delta;
952                                 if(delta != bigger && delta != -smaller) v1->vec.x-= (v1->vec.x % AREAGRID);
953                         }
954                         if((dir=='h') && v1->vec.y>0 && v1->vec.y<win->sizey-1) {
955                                 v1->vec.y= origval + delta;
956                                 
957                                 v1->vec.y+= AREAGRID-1;
958                                 v1->vec.y-= (v1->vec.y % AREAGRID);
959                                 
960                                 /* prevent too small top header */
961                                 if(v1->vec.y > win->sizey-areaminy)
962                                         v1->vec.y= win->sizey-areaminy;
963                         }
964                 }
965         }
966
967         for(sa= sc->areabase.first; sa; sa= sa->next) {
968                 if(sa->v1->flag || sa->v2->flag || sa->v3->flag || sa->v4->flag)
969                         ED_area_tag_redraw(sa);
970         }
971
972         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL); /* redraw everything */
973 }
974
975 static void area_move_apply(bContext *C, wmOperator *op)
976 {
977         sAreaMoveData *md= op->customdata;
978         int delta;
979         
980         delta= RNA_int_get(op->ptr, "delta");
981         area_move_apply_do(C, md->origval, delta, md->dir, md->bigger, md->smaller);
982 }
983
984 static void area_move_exit(bContext *C, wmOperator *op)
985 {
986         if(op->customdata)
987                 MEM_freeN(op->customdata);
988         op->customdata= NULL;
989         
990         /* this makes sure aligned edges will result in aligned grabbing */
991         removedouble_scrverts(CTX_wm_screen(C));
992         removedouble_scredges(CTX_wm_screen(C));
993 }
994
995 static int area_move_exec(bContext *C, wmOperator *op)
996 {
997         if(!area_move_init(C, op))
998                 return OPERATOR_CANCELLED;
999         
1000         area_move_apply(C, op);
1001         area_move_exit(C, op);
1002         
1003         return OPERATOR_FINISHED;
1004 }
1005
1006 /* interaction callback */
1007 static int area_move_invoke(bContext *C, wmOperator *op, wmEvent *event)
1008 {
1009         RNA_int_set(op->ptr, "x", event->x);
1010         RNA_int_set(op->ptr, "y", event->y);
1011         
1012         if(!area_move_init(C, op)) 
1013                 return OPERATOR_PASS_THROUGH;
1014         
1015         /* add temp handler */
1016         WM_event_add_modal_handler(C, op);
1017         
1018         return OPERATOR_RUNNING_MODAL;
1019 }
1020
1021 static int area_move_cancel(bContext *C, wmOperator *op)
1022 {
1023         
1024         RNA_int_set(op->ptr, "delta", 0);
1025         area_move_apply(C, op);
1026         area_move_exit(C, op);
1027         
1028         return OPERATOR_CANCELLED;
1029 }
1030
1031 /* modal callback for while moving edges */
1032 static int area_move_modal(bContext *C, wmOperator *op, wmEvent *event)
1033 {
1034         sAreaMoveData *md= op->customdata;
1035         int delta, x, y;
1036         
1037         /* execute the events */
1038         switch(event->type) {
1039                 case MOUSEMOVE:
1040                         
1041                         x= RNA_int_get(op->ptr, "x");
1042                         y= RNA_int_get(op->ptr, "y");
1043                         
1044                         delta= (md->dir == 'v')? event->x - x: event->y - y;
1045                         if(md->step) delta= delta - (delta % md->step);
1046                         RNA_int_set(op->ptr, "delta", delta);
1047                         
1048                         area_move_apply(C, op);
1049                         break;
1050                         
1051                 case EVT_MODAL_MAP:
1052                         
1053                         switch (event->val) {
1054                                 case KM_MODAL_APPLY:
1055                                         area_move_exit(C, op);
1056                                         return OPERATOR_FINISHED;
1057                                         
1058                                 case KM_MODAL_CANCEL:
1059                                         return area_move_cancel(C, op);
1060                                         
1061                                 case KM_MODAL_STEP10:
1062                                         md->step= 10;
1063                                         break;
1064                                 case KM_MODAL_STEP10_OFF:
1065                                         md->step= 0;
1066                                         break;
1067                         }
1068         }
1069         
1070         return OPERATOR_RUNNING_MODAL;
1071 }
1072
1073 static void SCREEN_OT_area_move(wmOperatorType *ot)
1074 {
1075         /* identifiers */
1076         ot->name= "Move area edges";
1077         ot->description= "Move selected area edges";
1078         ot->idname= "SCREEN_OT_area_move";
1079         
1080         ot->exec= area_move_exec;
1081         ot->invoke= area_move_invoke;
1082         ot->cancel= area_move_cancel;
1083         ot->modal= area_move_modal;
1084         ot->poll= ED_operator_screen_mainwinactive; /* when mouse is over area-edge */
1085         
1086         ot->flag= OPTYPE_BLOCKING;
1087         
1088         /* rna */
1089         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
1090         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
1091         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1092 }
1093
1094 /* ************** split area operator *********************************** */
1095
1096 /* 
1097  operator state vars:  
1098  fac              spit point
1099  dir              direction 'v' or 'h'
1100  
1101  operator customdata:
1102  area                           pointer to (active) area
1103  x, y                   last used mouse pos
1104  (more, see below)
1105  
1106  functions:
1107  
1108  init()   set default property values, find area based on context
1109  
1110  apply()        split area based on state vars
1111  
1112  exit() cleanup, send notifier
1113  
1114  cancel() remove duplicated area
1115  
1116  callbacks:
1117  
1118  exec()   execute without any user interaction, based on state vars
1119  call init(), apply(), exit()
1120  
1121  invoke() gets called on mouse click in action-widget
1122  call init(), add modal handler
1123  call apply() with initial motion
1124  
1125  modal()  accept modal events while doing it
1126  call move-areas code with delta motion
1127  call exit() or cancel() and remove handler
1128  
1129  */
1130
1131 #define SPLIT_STARTED   1
1132 #define SPLIT_PROGRESS  2
1133
1134 typedef struct sAreaSplitData {
1135         int x, y;       /* last used mouse position */
1136         
1137         int origval;                    /* for move areas */
1138         int bigger, smaller;    /* constraints for moving new edge */
1139         int delta;                              /* delta move edge */
1140         int origmin, origsize;  /* to calculate fac, for property storage */
1141         int previewmode;                /* draw previewline, then split */
1142         
1143         ScrEdge *nedge;                 /* new edge */
1144         ScrArea *sarea;                 /* start area */
1145         ScrArea *narea;                 /* new area */
1146         
1147 } sAreaSplitData;
1148
1149 /* generic init, menu case, doesn't need active area */
1150 static int area_split_menu_init(bContext *C, wmOperator *op)
1151 {
1152         sAreaSplitData *sd;
1153         
1154         /* custom data */
1155         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
1156         op->customdata= sd;
1157         
1158         sd->sarea= CTX_wm_area(C);
1159         
1160         if(sd->sarea) {
1161                 int dir= RNA_enum_get(op->ptr, "direction");
1162
1163                 if(dir=='h')
1164                         sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H;
1165                 else
1166                         sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V;
1167         }
1168         return 1;
1169 }
1170
1171 /* generic init, no UI stuff here, assumes active area */
1172 static int area_split_init(bContext *C, wmOperator *op)
1173 {
1174         ScrArea *sa= CTX_wm_area(C);
1175         sAreaSplitData *sd;
1176         int areaminy= ED_area_headersize()+1;
1177         int dir;
1178         
1179         /* required context */
1180         if(sa==NULL) return 0;
1181         
1182         /* required properties */
1183         dir= RNA_enum_get(op->ptr, "direction");
1184         
1185         /* minimal size */
1186         if(dir=='v' && sa->winx < 2*AREAMINX) return 0;
1187         if(dir=='h' && sa->winy < 2*areaminy) return 0;
1188         
1189         /* custom data */
1190         sd= (sAreaSplitData*)MEM_callocN(sizeof (sAreaSplitData), "op_area_split");
1191         op->customdata= sd;
1192         
1193         sd->sarea= sa;
1194         sd->origsize= dir=='v' ? sa->winx:sa->winy;
1195         sd->origmin = dir=='v' ? sa->totrct.xmin:sa->totrct.ymin;
1196         
1197         return 1;
1198 }
1199
1200 /* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
1201 /* used with split operator */
1202 static ScrEdge *area_findsharededge(bScreen *screen, ScrArea *sa, ScrArea *sb)
1203 {
1204         ScrVert *sav1= sa->v1;
1205         ScrVert *sav2= sa->v2;
1206         ScrVert *sav3= sa->v3;
1207         ScrVert *sav4= sa->v4;
1208         ScrVert *sbv1= sb->v1;
1209         ScrVert *sbv2= sb->v2;
1210         ScrVert *sbv3= sb->v3;
1211         ScrVert *sbv4= sb->v4;
1212         
1213         if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
1214                 return screen_findedge(screen, sav1, sav2);
1215         }
1216         else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
1217                 return screen_findedge(screen, sav2, sav3);
1218         }
1219         else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
1220                 return screen_findedge(screen, sav3, sav4);
1221         }
1222         else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
1223                 return screen_findedge(screen, sav1, sav4);
1224         }
1225         
1226         return NULL;
1227 }
1228
1229
1230 /* do the split, return success */
1231 static int area_split_apply(bContext *C, wmOperator *op)
1232 {
1233         bScreen *sc= CTX_wm_screen(C);
1234         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1235         float fac;
1236         int dir;
1237         
1238         fac= RNA_float_get(op->ptr, "factor");
1239         dir= RNA_enum_get(op->ptr, "direction");
1240         
1241         sd->narea= area_split(sc, sd->sarea, dir, fac, 0); /* 0 = no merge */
1242         
1243         if(sd->narea) {
1244                 ScrVert *sv;
1245                 
1246                 sd->nedge= area_findsharededge(sc, sd->sarea, sd->narea);
1247                 
1248                 /* select newly created edge, prepare for moving edge */
1249                 for(sv= sc->vertbase.first; sv; sv= sv->next)
1250                         sv->flag = 0;
1251                 
1252                 sd->nedge->v1->flag= 1;
1253                 sd->nedge->v2->flag= 1;
1254                 
1255                 if(dir=='h') sd->origval= sd->nedge->v1->vec.y;
1256                 else sd->origval= sd->nedge->v1->vec.x;
1257
1258                 ED_area_tag_redraw(sd->sarea);
1259                 ED_area_tag_redraw(sd->narea);
1260
1261                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1262                 
1263                 return 1;
1264         }               
1265         
1266         return 0;
1267 }
1268
1269 static void area_split_exit(bContext *C, wmOperator *op)
1270 {
1271         if (op->customdata) {
1272                 sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1273                 if(sd->sarea) ED_area_tag_redraw(sd->sarea);
1274                 if(sd->narea) ED_area_tag_redraw(sd->narea);
1275
1276                 if(sd->sarea)
1277                         sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H|AREA_FLAG_DRAWSPLIT_V);
1278                 
1279                 MEM_freeN(op->customdata);
1280                 op->customdata = NULL;
1281         }
1282         
1283         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1284         
1285         /* this makes sure aligned edges will result in aligned grabbing */
1286         removedouble_scrverts(CTX_wm_screen(C));
1287         removedouble_scredges(CTX_wm_screen(C));
1288 }
1289
1290
1291 /* UI callback, adds new handler */
1292 static int area_split_invoke(bContext *C, wmOperator *op, wmEvent *event)
1293 {
1294         sAreaSplitData *sd;
1295         int dir;
1296         
1297         /* no full window splitting allowed */
1298         if(CTX_wm_screen(C)->full != SCREENNORMAL)
1299                 return OPERATOR_CANCELLED;
1300         
1301         if(event->type==EVT_ACTIONZONE_AREA) {
1302                 sActionzoneData *sad= event->customdata;
1303                 
1304                 if(sad->modifier>0) {
1305                         return OPERATOR_PASS_THROUGH;
1306                 }
1307                 
1308                 /* verify *sad itself */
1309                 if(sad==NULL || sad->sa1==NULL || sad->az==NULL)
1310                         return OPERATOR_PASS_THROUGH;
1311                 
1312                 /* is this our *sad? if areas not equal it should be passed on */
1313                 if(CTX_wm_area(C)!=sad->sa1 || sad->sa1!=sad->sa2)
1314                         return OPERATOR_PASS_THROUGH;
1315                 
1316                 /* prepare operator state vars */
1317                 if(sad->gesture_dir=='n' || sad->gesture_dir=='s') {
1318                         dir= 'h';
1319                         RNA_float_set(op->ptr, "factor", ((float)(event->x - sad->sa1->v1->vec.x)) / (float)sad->sa1->winx);
1320                 }
1321                 else {
1322                         dir= 'v';
1323                         RNA_float_set(op->ptr, "factor", ((float)(event->y - sad->sa1->v1->vec.y)) / (float)sad->sa1->winy);
1324                 }
1325                 RNA_enum_set(op->ptr, "direction", dir);
1326                 
1327                 /* general init, also non-UI case, adds customdata, sets area and defaults */
1328                 if(!area_split_init(C, op))
1329                         return OPERATOR_PASS_THROUGH;
1330                 
1331         }
1332         else {
1333                 ScrEdge *actedge;
1334                 int x, y;
1335                 
1336                 /* retrieve initial mouse coord, so we can find the active edge */
1337                 if(RNA_property_is_set(op->ptr, "mouse_x"))
1338                         x= RNA_int_get(op->ptr, "mouse_x");
1339                 else
1340                         x= event->x;
1341                 
1342                 if(RNA_property_is_set(op->ptr, "mouse_y"))
1343                         y= RNA_int_get(op->ptr, "mouse_y");
1344                 else
1345                         y= event->x;
1346                 
1347                 actedge= screen_find_active_scredge(CTX_wm_screen(C), x, y);
1348                 if(actedge==NULL) 
1349                         return OPERATOR_CANCELLED;
1350                 
1351                 dir= scredge_is_horizontal(actedge)?'v':'h';
1352                 
1353                 RNA_enum_set(op->ptr, "direction", dir);
1354                 
1355                 /* special case, adds customdata, sets defaults */
1356                 if(!area_split_menu_init(C, op))
1357                         return OPERATOR_CANCELLED;
1358                 
1359         }
1360         
1361         sd= (sAreaSplitData *)op->customdata;
1362         
1363         sd->x= event->x;
1364         sd->y= event->y;
1365         
1366         if(event->type==EVT_ACTIONZONE_AREA) {
1367                 
1368                 /* do the split */
1369                 if(area_split_apply(C, op)) {
1370                         area_move_set_limits(CTX_wm_screen(C), dir, &sd->bigger, &sd->smaller);
1371                         
1372                         /* add temp handler for edge move or cancel */
1373                         WM_event_add_modal_handler(C, op);
1374                         
1375                         return OPERATOR_RUNNING_MODAL;
1376                 }
1377         }
1378         else {
1379                 sd->previewmode= 1;
1380                 /* add temp handler for edge move or cancel */
1381                 WM_event_add_modal_handler(C, op);
1382                 
1383                 return OPERATOR_RUNNING_MODAL;
1384                 
1385         }
1386         
1387         return OPERATOR_PASS_THROUGH;
1388 }
1389
1390 /* function to be called outside UI context, or for redo */
1391 static int area_split_exec(bContext *C, wmOperator *op)
1392 {
1393         
1394         if(!area_split_init(C, op))
1395                 return OPERATOR_CANCELLED;
1396         
1397         area_split_apply(C, op);
1398         area_split_exit(C, op);
1399         
1400         return OPERATOR_FINISHED;
1401 }
1402
1403
1404 static int area_split_cancel(bContext *C, wmOperator *op)
1405 {
1406         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1407         
1408         if(sd->previewmode) {
1409         }
1410         else {
1411                 if (screen_area_join(C, CTX_wm_screen(C), sd->sarea, sd->narea)) {
1412                         if (CTX_wm_area(C) == sd->narea) {
1413                                 CTX_wm_area_set(C, NULL);
1414                                 CTX_wm_region_set(C, NULL);
1415                         }
1416                         sd->narea = NULL;
1417                 }
1418         }
1419         area_split_exit(C, op);
1420         
1421         return OPERATOR_CANCELLED;
1422 }
1423
1424 static int area_split_modal(bContext *C, wmOperator *op, wmEvent *event)
1425 {
1426         sAreaSplitData *sd= (sAreaSplitData *)op->customdata;
1427         float fac;
1428         int dir;
1429         
1430         /* execute the events */
1431         switch(event->type) {
1432                 case MOUSEMOVE:
1433                         dir= RNA_enum_get(op->ptr, "direction");
1434                         
1435                         sd->delta= (dir == 'v')? event->x - sd->origval: event->y - sd->origval;
1436                         if(sd->previewmode==0) 
1437                                 area_move_apply_do(C, sd->origval, sd->delta, dir, sd->bigger, sd->smaller);
1438                         else {
1439                                 if(sd->sarea) {
1440                                         sd->sarea->flag &= ~(AREA_FLAG_DRAWSPLIT_H|AREA_FLAG_DRAWSPLIT_V);
1441                                         ED_area_tag_redraw(sd->sarea);
1442                                 }
1443                                 sd->sarea= screen_areahascursor(CTX_wm_screen(C), event->x, event->y);  /* area context not set */
1444                                 
1445                                 if(sd->sarea) {
1446                                         ED_area_tag_redraw(sd->sarea);
1447                                         if (dir=='v') {
1448                                                 sd->origsize= sd->sarea->winx;
1449                                                 sd->origmin= sd->sarea->totrct.xmin;
1450                                                 sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_V;
1451                                         }
1452                                         else {
1453                                                 sd->origsize= sd->sarea->winy;
1454                                                 sd->origmin= sd->sarea->totrct.ymin;
1455                                                 sd->sarea->flag |= AREA_FLAG_DRAWSPLIT_H;
1456                                         }
1457                                 }
1458                                 
1459                                 CTX_wm_window(C)->screen->do_draw= 1;
1460
1461                         }
1462                         
1463                         fac= (dir == 'v') ? event->x-sd->origmin : event->y-sd->origmin;
1464                         RNA_float_set(op->ptr, "factor", fac / (float)sd->origsize);
1465                         
1466                         break;
1467                         
1468                 case LEFTMOUSE:
1469                         if(sd->previewmode) {
1470                                 area_split_apply(C, op);
1471                                 area_split_exit(C, op);
1472                                 return OPERATOR_FINISHED;
1473                         }
1474                         else {
1475                                 if(event->val==KM_RELEASE) { /* mouse up */
1476                                         area_split_exit(C, op);
1477                                         return OPERATOR_FINISHED;
1478                                 }
1479                         }
1480                         break;
1481                 case RIGHTMOUSE: /* cancel operation */
1482                 case ESCKEY:
1483                         return area_split_cancel(C, op);
1484         }
1485         
1486         return OPERATOR_RUNNING_MODAL;
1487 }
1488
1489 static EnumPropertyItem prop_direction_items[] = {
1490 {'h', "HORIZONTAL", 0, "Horizontal", ""},
1491 {'v', "VERTICAL", 0, "Vertical", ""},
1492 {0, NULL, 0, NULL, NULL}};
1493
1494 static void SCREEN_OT_area_split(wmOperatorType *ot)
1495 {
1496         ot->name = "Split area";
1497         ot->description= "Split selected area into new windows";
1498         ot->idname = "SCREEN_OT_area_split";
1499         
1500         ot->exec= area_split_exec;
1501         ot->invoke= area_split_invoke;
1502         ot->modal= area_split_modal;
1503         ot->cancel= area_split_cancel;
1504         
1505         ot->poll= screen_active_editable;
1506         ot->flag= OPTYPE_BLOCKING;
1507         
1508         /* rna */
1509         RNA_def_enum(ot->srna, "direction", prop_direction_items, 'h', "Direction", "");
1510         RNA_def_float(ot->srna, "factor", 0.5f, 0.0, 1.0, "Factor", "", 0.0, 1.0);
1511         RNA_def_int(ot->srna, "mouse_x", -100, INT_MIN, INT_MAX, "Mouse X", "", INT_MIN, INT_MAX);
1512         RNA_def_int(ot->srna, "mouse_y", -100, INT_MIN, INT_MAX, "Mouse Y", "", INT_MIN, INT_MAX);
1513 }
1514
1515
1516
1517 /* ************** scale region edge operator *********************************** */
1518
1519 typedef struct RegionMoveData {
1520         AZone *az;
1521         ARegion *ar;
1522         ScrArea *sa;
1523         int bigger, smaller, origval;
1524         int origx, origy;
1525         int maxsize;
1526         AZEdge edge;
1527         
1528 } RegionMoveData;
1529
1530
1531 static int area_max_regionsize(ScrArea *sa, ARegion *scalear, AZEdge edge)
1532 {
1533         ARegion *ar;
1534         int dist;
1535         
1536         if(edge==AE_RIGHT_TO_TOPLEFT || edge==AE_LEFT_TO_TOPRIGHT) {
1537                 dist = sa->totrct.xmax - sa->totrct.xmin;
1538         } else {        /* AE_BOTTOM_TO_TOPLEFT, AE_TOP_TO_BOTTOMRIGHT */
1539                 dist = sa->totrct.ymax - sa->totrct.ymin;
1540         }
1541         
1542         /* subtractwidth of regions on opposite side 
1543          * prevents dragging regions into other opposite regions */
1544         for (ar=sa->regionbase.first; ar; ar=ar->next) {
1545                 if (ar == scalear)
1546                         continue;
1547                 
1548                 if (scalear->alignment == RGN_ALIGN_TOP && ar->alignment == RGN_ALIGN_BOTTOM)
1549                         dist -= ar->winy;
1550                 else if (scalear->alignment == RGN_ALIGN_BOTTOM && ar->alignment == RGN_ALIGN_TOP)
1551                         dist -= ar->winy;
1552                 else if (scalear->alignment == RGN_ALIGN_LEFT && ar->alignment == RGN_ALIGN_RIGHT)
1553                         dist -= ar->winx;
1554                 else if (scalear->alignment == RGN_ALIGN_RIGHT && ar->alignment == RGN_ALIGN_LEFT)
1555                         dist -= ar->winx;
1556                 
1557                 /* case of regions in regions, like operator properties panel */
1558                 /* these can sit on top of other regions such as headers, so account for this */
1559                 else if (edge == AE_BOTTOM_TO_TOPLEFT && scalear->alignment & RGN_ALIGN_TOP && ar->alignment == RGN_ALIGN_TOP && ar->regiontype == RGN_TYPE_HEADER)
1560                         dist -= ar->winy;
1561                 else if (edge == AE_TOP_TO_BOTTOMRIGHT && scalear->alignment & RGN_ALIGN_BOTTOM && ar->alignment == RGN_ALIGN_BOTTOM && ar->regiontype == RGN_TYPE_HEADER)
1562                         dist -= ar->winy;
1563         }
1564
1565         return dist;
1566 }
1567
1568 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1569 {
1570         sActionzoneData *sad= event->customdata;
1571         AZone *az;
1572         
1573         if(event->type!=EVT_ACTIONZONE_REGION) {
1574                 BKE_report(op->reports, RPT_ERROR, "Can only scale region size from an action zone");   
1575                 return OPERATOR_CANCELLED;
1576         }
1577         
1578         az = sad->az;
1579         
1580         if(az->ar) {
1581                 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1582                 int maxsize;
1583                 
1584                 op->customdata= rmd;
1585                 
1586                 rmd->az = az;
1587                 rmd->ar= az->ar;
1588                 rmd->sa = sad->sa1;
1589                 rmd->edge= az->edge;
1590                 rmd->origx= event->x;
1591                 rmd->origy= event->y;
1592                 rmd->maxsize = area_max_regionsize(rmd->sa, rmd->ar, rmd->edge);
1593                 
1594                 /* if not set we do now, otherwise it uses type */
1595                 if(rmd->ar->sizex==0) 
1596                         rmd->ar->sizex= rmd->ar->type->prefsizex;
1597                 if(rmd->ar->sizey==0) 
1598                         rmd->ar->sizey= rmd->ar->type->prefsizey;
1599                 
1600                 /* now copy to regionmovedata */
1601                 if(rmd->edge==AE_LEFT_TO_TOPRIGHT || rmd->edge==AE_RIGHT_TO_TOPLEFT) {
1602                         rmd->origval= rmd->ar->sizex;
1603                 } else {
1604                         rmd->origval= rmd->ar->sizey;
1605                 }
1606                 
1607                 /* limit headers to standard height for now */
1608                 if (rmd->ar->regiontype == RGN_TYPE_HEADER)
1609                         maxsize = rmd->ar->type->prefsizey;
1610                 else
1611                         maxsize = 1000;
1612                 
1613                 CLAMP(rmd->maxsize, 0, maxsize);
1614                 
1615                 /* add temp handler */
1616                 WM_event_add_modal_handler(C, op);
1617                 
1618                 return OPERATOR_RUNNING_MODAL;
1619         }
1620         
1621         return OPERATOR_FINISHED;
1622 }
1623
1624 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1625 {
1626         RegionMoveData *rmd= op->customdata;
1627         int delta;
1628         
1629         /* execute the events */
1630         switch(event->type) {
1631                 case MOUSEMOVE:
1632                         
1633                         if(rmd->edge==AE_LEFT_TO_TOPRIGHT || rmd->edge==AE_RIGHT_TO_TOPLEFT) {
1634                                 delta= event->x - rmd->origx;
1635                                 if(rmd->edge==AE_LEFT_TO_TOPRIGHT) delta= -delta;
1636                                 
1637                                 rmd->ar->sizex= rmd->origval + delta;
1638                                 CLAMP(rmd->ar->sizex, 0, rmd->maxsize);
1639                                 
1640                                 if(rmd->ar->sizex < UI_UNIT_X) {
1641                                         rmd->ar->sizex= rmd->origval;
1642                                         if(!(rmd->ar->flag & RGN_FLAG_HIDDEN))
1643                                                 ED_region_toggle_hidden(C, rmd->ar);
1644                                 }
1645                                 else if(rmd->ar->flag & RGN_FLAG_HIDDEN)
1646                                         ED_region_toggle_hidden(C, rmd->ar);
1647                         }
1648                         else {
1649                                 int maxsize=0;
1650                                 delta= event->y - rmd->origy;
1651                                 if(rmd->edge==AE_BOTTOM_TO_TOPLEFT) delta= -delta;
1652                                 
1653                                 rmd->ar->sizey= rmd->origval + delta;
1654                                 CLAMP(rmd->ar->sizey, 0, rmd->maxsize);
1655
1656                                 if(rmd->ar->regiontype == RGN_TYPE_TOOL_PROPS) {
1657                                         /* this calculation seems overly verbose
1658                                          * can someone explain why this method is necessary? - campbell */
1659                                         maxsize = rmd->maxsize - ((rmd->sa->headertype==HEADERTOP)?UI_UNIT_Y*2:UI_UNIT_Y) - (UI_UNIT_Y/4);
1660                                 }
1661
1662                                 /* note, 'UI_UNIT_Y/4' means you need to drag the header almost
1663                                  * all the way down for it to become hidden, this is done
1664                                  * otherwise its too easy to do this by accident */
1665                                 if(rmd->ar->sizey < UI_UNIT_Y/4 || (maxsize > 0 && (rmd->ar->sizey > maxsize)) ) {
1666                                         rmd->ar->sizey= rmd->origval;
1667                                         if(!(rmd->ar->flag & RGN_FLAG_HIDDEN))
1668                                                 ED_region_toggle_hidden(C, rmd->ar);
1669                                 }
1670                                 else if(rmd->ar->flag & RGN_FLAG_HIDDEN)
1671                                         ED_region_toggle_hidden(C, rmd->ar);
1672                         }
1673                         ED_area_tag_redraw(rmd->sa);
1674                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1675                         
1676                         break;
1677                         
1678                 case LEFTMOUSE:
1679                         if(event->val==KM_RELEASE) {
1680                                 
1681                                 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1682                                         if(rmd->ar->flag & RGN_FLAG_HIDDEN) {
1683                                                 ED_region_toggle_hidden(C, rmd->ar);
1684                                                 ED_area_tag_redraw(rmd->sa);
1685                                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1686                                         }
1687                                 }
1688                                 MEM_freeN(op->customdata);
1689                                 op->customdata = NULL;
1690                                 
1691                                 return OPERATOR_FINISHED;
1692                         }
1693                         break;
1694                         
1695                 case ESCKEY:
1696                         ;
1697         }
1698         
1699         return OPERATOR_RUNNING_MODAL;
1700 }
1701
1702 static int region_scale_cancel(bContext *UNUSED(C), wmOperator *op)
1703 {
1704         MEM_freeN(op->customdata);
1705         op->customdata = NULL;
1706
1707         return OPERATOR_CANCELLED;
1708 }
1709
1710 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1711 {
1712         /* identifiers */
1713         ot->name= "Scale Region Size";
1714         ot->description= "Scale selected area";
1715         ot->idname= "SCREEN_OT_region_scale";
1716         
1717         ot->invoke= region_scale_invoke;
1718         ot->modal= region_scale_modal;
1719         ot->cancel= region_scale_cancel;
1720         
1721         ot->poll= ED_operator_areaactive;
1722         
1723         ot->flag= OPTYPE_BLOCKING;
1724 }
1725
1726
1727 /* ************** frame change operator ***************************** */
1728
1729 /* function to be called outside UI context, or for redo */
1730 static int frame_offset_exec(bContext *C, wmOperator *op)
1731 {
1732         Main *bmain= CTX_data_main(C);
1733         Scene *scene= CTX_data_scene(C);
1734         int delta;
1735         
1736         delta = RNA_int_get(op->ptr, "delta");
1737
1738         scene->r.cfra += delta;
1739         scene->r.subframe = 0.f;
1740         
1741         sound_seek_scene(bmain, scene);
1742
1743         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1744         
1745         return OPERATOR_FINISHED;
1746 }
1747
1748 static void SCREEN_OT_frame_offset(wmOperatorType *ot)
1749 {
1750         ot->name = "Frame Offset";
1751         ot->idname = "SCREEN_OT_frame_offset";
1752         
1753         ot->exec= frame_offset_exec;
1754         
1755         ot->poll= ED_operator_screenactive_norender;
1756         ot->flag= 0;
1757         
1758         /* rna */
1759         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1760 }
1761
1762
1763 /* function to be called outside UI context, or for redo */
1764 static int frame_jump_exec(bContext *C, wmOperator *op)
1765 {
1766         Main *bmain= CTX_data_main(C);
1767         Scene *scene= CTX_data_scene(C);
1768         wmTimer *animtimer= CTX_wm_screen(C)->animtimer;
1769
1770         /* Don't change CFRA directly if animtimer is running as this can cause
1771          * first/last frame not to be actually shown (bad since for example physics
1772          * simulations aren't reset properly).
1773          */
1774         if(animtimer) {
1775                 ScreenAnimData *sad = animtimer->customdata;
1776                 
1777                 sad->flag |= ANIMPLAY_FLAG_USE_NEXT_FRAME;
1778                 
1779                 if (RNA_boolean_get(op->ptr, "end"))
1780                         sad->nextfra= PEFRA;
1781                 else
1782                         sad->nextfra= PSFRA;
1783         }
1784         else {
1785                 if (RNA_boolean_get(op->ptr, "end"))
1786                         CFRA= PEFRA;
1787                 else
1788                         CFRA= PSFRA;
1789                 
1790                 sound_seek_scene(bmain, scene);
1791
1792                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1793         }
1794         
1795         return OPERATOR_FINISHED;
1796 }
1797
1798 static void SCREEN_OT_frame_jump(wmOperatorType *ot)
1799 {
1800         ot->name = "Jump to Endpoint";
1801         ot->description= "Jump to first/last frame in frame range";
1802         ot->idname = "SCREEN_OT_frame_jump";
1803         
1804         ot->exec= frame_jump_exec;
1805         
1806         ot->poll= ED_operator_screenactive_norender;
1807         ot->flag= OPTYPE_UNDO;
1808         
1809         /* rna */
1810         RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range");
1811 }
1812
1813
1814 /* ************** jump to keyframe operator ***************************** */
1815
1816 /* function to be called outside UI context, or for redo */
1817 static int keyframe_jump_exec(bContext *C, wmOperator *op)
1818 {
1819         Main *bmain= CTX_data_main(C);
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(bmain, scene);
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                 Main *bmain= CTX_data_main(C);
2801                 Scene *scene= CTX_data_scene(C);
2802                 wmTimer *wt= screen->animtimer;
2803                 ScreenAnimData *sad= wt->customdata;
2804                 ScrArea *sa;
2805                 int sync;
2806                 float time;
2807                 
2808                 /* sync, don't sync, or follow scene setting */
2809                 if (sad->flag & ANIMPLAY_FLAG_SYNC) sync= 1;
2810                 else if (sad->flag & ANIMPLAY_FLAG_NO_SYNC) sync= 0;
2811                 else sync= (scene->flag & SCE_FRAME_DROP);
2812                 
2813                 if((scene->audio.flag & AUDIO_SYNC) && !(sad->flag & ANIMPLAY_FLAG_REVERSE) && finite(time = sound_sync_scene(scene)))
2814                         scene->r.cfra = (double)time * FPS + 0.5;
2815                 else
2816                 {
2817                         if (sync) {
2818                                 int step = floor(wt->duration * FPS);
2819                                 /* skip frames */
2820                                 if (sad->flag & ANIMPLAY_FLAG_REVERSE)
2821                                         scene->r.cfra -= step;
2822                                 else
2823                                         scene->r.cfra += step;
2824                                 wt->duration -= ((double)step)/FPS;
2825                         }
2826                         else {
2827                                 /* one frame +/- */
2828                                 if (sad->flag & ANIMPLAY_FLAG_REVERSE)
2829                                         scene->r.cfra--;
2830                                 else
2831                                         scene->r.cfra++;
2832                         }
2833                 }
2834                 
2835                 /* reset 'jumped' flag before checking if we need to jump... */
2836                 sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
2837                 
2838                 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
2839                         /* jump back to end? */
2840                         if (PRVRANGEON) {
2841                                 if (scene->r.cfra < scene->r.psfra) {
2842                                         scene->r.cfra= scene->r.pefra;
2843                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2844                                 }
2845                         }
2846                         else {
2847                                 if (scene->r.cfra < scene->r.sfra) {
2848                                         scene->r.cfra= scene->r.efra;
2849                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2850                                 }
2851                         }
2852                 }
2853                 else {
2854                         /* jump back to start? */
2855                         if (PRVRANGEON) {
2856                                 if (scene->r.cfra > scene->r.pefra) {
2857                                         scene->r.cfra= scene->r.psfra;
2858                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2859                                 }
2860                         }
2861                         else {
2862                                 if (scene->r.cfra > scene->r.efra) {
2863                                         scene->r.cfra= scene->r.sfra;
2864                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2865                                 }
2866                         }
2867                 }
2868
2869                 /* next frame overriden by user action (pressed jump to first/last frame) */
2870                 if(sad->flag & ANIMPLAY_FLAG_USE_NEXT_FRAME) {
2871                         scene->r.cfra = sad->nextfra;
2872                         sad->flag &= ~ANIMPLAY_FLAG_USE_NEXT_FRAME;
2873                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2874                 }
2875                 
2876                 if (sad->flag & ANIMPLAY_FLAG_JUMPED)
2877                         sound_seek_scene(bmain, scene);
2878                 
2879                 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2880                 ED_update_for_newframe(CTX_data_main(C), scene, screen, 1);
2881                 
2882                 for (sa= screen->areabase.first; sa; sa= sa->next) {
2883                         ARegion *ar;
2884                         for (ar= sa->regionbase.first; ar; ar= ar->next) {
2885                                 if (ar==sad->ar)
2886                                         ED_region_tag_redraw(ar);
2887                                 else
2888                                         if (match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2889                                                 ED_region_tag_redraw(ar);
2890                         }
2891                         
2892                         if (match_area_with_refresh(sa->spacetype, sad->refresh))
2893                                 ED_area_tag_refresh(sa);
2894                 }
2895                 
2896                 /* update frame rate info too 
2897                  * NOTE: this may not be accurate enough, since we might need this after modifiers/etc. 
2898                  * have been calculated instead of just before updates have been done?
2899                  */
2900                 ED_refresh_viewport_fps(C);
2901                 
2902                 /* recalculate the timestep for the timer now that we've finished calculating this,
2903                  * since the frames-per-second value may have been changed
2904                  */
2905                 // TODO: this may make evaluation a bit slower if the value doesn't change... any way to avoid this?
2906                 wt->timestep= (1.0/FPS);
2907                 
2908                 return OPERATOR_FINISHED;
2909         }
2910         return OPERATOR_PASS_THROUGH;
2911 }
2912
2913 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2914 {
2915         /* identifiers */
2916         ot->name= "Animation Step";
2917         ot->description= "Step through animation by position";
2918         ot->idname= "SCREEN_OT_animation_step";
2919         
2920         /* api callbacks */
2921         ot->invoke= screen_animation_step;
2922         
2923         ot->poll= ED_operator_screenactive_norender;
2924         
2925 }
2926
2927 /* ****************** anim player, starts or ends timer ***************** */
2928
2929 /* toggle operator */
2930 int ED_screen_animation_play(bContext *C, int sync, int mode)
2931 {
2932         bScreen *screen= CTX_wm_screen(C);
2933         Scene *scene = CTX_data_scene(C);
2934
2935         if (screen->animtimer) {
2936                 /* stop playback now */
2937                 ED_screen_animation_timer(C, 0, 0, 0, 0);
2938                 sound_stop_scene(scene);
2939         }
2940         else {
2941                 int refresh= SPACE_TIME; /* these settings are currently only available from a menu in the TimeLine */
2942                 
2943                 if (mode == 1) // XXX only play audio forwards!?
2944                         sound_play_scene(scene);
2945                 
2946                 ED_screen_animation_timer(C, screen->redraws_flag, refresh, sync, mode);
2947                 
2948                 if (screen->animtimer) {
2949                         wmTimer *wt= screen->animtimer;
2950                         ScreenAnimData *sad= wt->customdata;
2951                         
2952                         sad->ar= CTX_wm_region(C);
2953                         }
2954         }
2955
2956         return OPERATOR_FINISHED;
2957 }
2958
2959 static int screen_animation_play_exec(bContext *C, wmOperator *op)
2960 {
2961         int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2962         int sync= -1;
2963         
2964         if (RNA_property_is_set(op->ptr, "sync"))
2965                 sync= (RNA_boolean_get(op->ptr, "sync"));
2966         
2967         return ED_screen_animation_play(C, sync, mode);
2968 }
2969
2970 static void SCREEN_OT_animation_play(wmOperatorType *ot)
2971 {
2972         /* identifiers */
2973         ot->name= "Play Animation";
2974         ot->description= "Play animation";
2975         ot->idname= "SCREEN_OT_animation_play";
2976         
2977         /* api callbacks */
2978         ot->exec= screen_animation_play_exec;
2979         
2980         ot->poll= ED_operator_screenactive_norender;
2981         
2982         RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2983         RNA_def_boolean(ot->srna, "sync", 0, "Sync", "Drop frames to maintain framerate");
2984 }
2985
2986 static int screen_animation_cancel_exec(bContext *C, wmOperator *op)
2987 {
2988         bScreen *screen= CTX_wm_screen(C);
2989
2990         if (screen->animtimer) {
2991                 if(RNA_boolean_get(op->ptr, "restore_frame")) {
2992                         ScreenAnimData *sad= screen->animtimer->customdata;
2993                         Scene *scene= CTX_data_scene(C);
2994
2995                         /* reset current frame before stopping, and just send a notifier to deal with the rest
2996                          * (since playback still needs to be stopped)
2997                          */
2998                         scene->r.cfra= sad->sfra;
2999
3000                         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
3001                 }
3002
3003                 /* call the other "toggling" operator to clean up now */
3004                 ED_screen_animation_play(C, 0, 0);
3005         }
3006
3007         return OPERATOR_PASS_THROUGH;
3008 }
3009
3010 static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
3011 {
3012         /* identifiers */
3013         ot->name= "Cancel Animation";
3014         ot->description= "Cancel animation, returning to the original frame";
3015         ot->idname= "SCREEN_OT_animation_cancel";
3016         
3017         /* api callbacks */
3018         ot->exec= screen_animation_cancel_exec;
3019         
3020         ot->poll= ED_operator_screenactive;
3021
3022         RNA_def_boolean(ot->srna, "restore_frame", TRUE, "Restore Frame", "Restore the frame when animation was initialized");
3023 }
3024
3025 /* ************** border select operator (template) ***************************** */
3026
3027 /* operator state vars used: (added by default WM callbacks)   
3028  xmin, ymin     
3029  xmax, ymax     
3030  
3031  customdata: the wmGesture pointer
3032  
3033  callbacks:
3034  
3035  exec() has to be filled in by user
3036  
3037  invoke() default WM function
3038  adds modal handler
3039  
3040  modal()        default WM function 
3041  accept modal events while doing it, calls exec(), handles ESC and border drawing
3042  
3043  poll() has to be filled in by user for context
3044  */
3045 #if 0
3046 static int border_select_do(bContext *C, wmOperator *op)
3047 {
3048         int event_type= RNA_int_get(op->ptr, "event_type");
3049         
3050         if(event_type==LEFTMOUSE)
3051                 printf("border select do select\n");
3052         else if(event_type==RIGHTMOUSE)
3053                 printf("border select deselect\n");
3054         else 
3055                 printf("border select do something\n");
3056         
3057         return 1;
3058 }
3059
3060 static void SCREEN_OT_border_select(wmOperatorType *ot)
3061 {
3062         /* identifiers */
3063         ot->name= "Border select";
3064         ot->idname= "SCREEN_OT_border_select";
3065         
3066         /* api callbacks */
3067         ot->exec= border_select_do;
3068         ot->invoke= WM_border_select_invoke;
3069         ot->modal= WM_border_select_modal;
3070         ot->cancel= WM_border_select_cancel;
3071         
3072         ot->poll= ED_operator_areaactive;
3073         
3074         /* rna */
3075         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
3076         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
3077         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
3078         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
3079         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
3080         
3081 }
3082 #endif
3083
3084 /* *********************** generic fullscreen 'back' button *************** */
3085
3086
3087 static int fullscreen_back_exec(bContext *C, wmOperator *op)
3088 {
3089         bScreen *screen = CTX_wm_screen(C);
3090         ScrArea *sa=NULL;
3091         
3092         /* search current screen for 'fullscreen' areas */
3093         for (sa=screen->areabase.first; sa; sa=sa->next) {
3094                 if (sa->full) break;
3095         }
3096         if (!sa) {
3097                 BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found");
3098                 return OPERATOR_CANCELLED;
3099         }
3100         
3101         ED_screen_full_restore(C, sa);
3102         
3103         return OPERATOR_FINISHED;
3104 }
3105
3106 static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
3107 {
3108         /* identifiers */
3109         ot->name= "Back to Previous Screen";
3110         ot->description= "Revert back to the original screen layout, before fullscreen area overlay";
3111         ot->idname= "SCREEN_OT_back_to_previous";
3112         
3113         /* api callbacks */
3114         ot->exec= fullscreen_back_exec;
3115         ot->poll= ED_operator_screenactive;
3116 }
3117
3118 /* *********** show user pref window ****** */
3119
3120 static int userpref_show_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
3121 {
3122         rcti rect;
3123         int sizex, sizey;
3124         
3125         sizex= 800;
3126         sizey= 480;
3127         
3128         /* some magic to calculate postition */
3129         rect.xmin= event->x + CTX_wm_window(C)->posx - sizex/2;
3130         rect.ymin= event->y + CTX_wm_window(C)->posy - sizey/2;
3131         rect.xmax= rect.xmin + sizex;
3132         rect.ymax= rect.ymin + sizey;
3133         
3134         /* changes context! */
3135         WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS);
3136         
3137         return OPERATOR_FINISHED;
3138 }
3139
3140
3141 static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
3142 {
3143         /* identifiers */
3144         ot->name= "Show/Hide User Preferences";
3145         ot->description= "Show/hide user preferences";
3146         ot->idname= "SCREEN_OT_userpref_show";
3147         
3148         /* api callbacks */
3149         ot->invoke= userpref_show_invoke;
3150         ot->poll= ED_operator_screenactive;
3151 }
3152
3153 /********************* new screen operator *********************/
3154
3155 static int screen_new_exec(bContext *C, wmOperator *UNUSED(op))
3156 {
3157         wmWindow *win= CTX_wm_window(C);
3158         bScreen *sc= CTX_wm_screen(C);
3159         
3160         sc= ED_screen_duplicate(win, sc);
3161         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENBROWSE, sc);
3162         
3163         return OPERATOR_FINISHED;
3164 }
3165
3166 static void SCREEN_OT_new(wmOperatorType *ot)
3167 {
3168         /* identifiers */
3169         ot->name= "New Screen";
3170         ot->description= "Add a new screen";
3171         ot->idname= "SCREEN_OT_new";
3172         
3173         /* api callbacks */
3174         ot->exec= screen_new_exec;
3175         ot->poll= WM_operator_winactive;
3176         
3177         /* flags */
3178         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3179 }
3180
3181 /********************* delete screen operator *********************/
3182
3183 static int screen_delete_exec(bContext *C, wmOperator *UNUSED(op))
3184 {
3185         bScreen *sc= CTX_wm_screen(C);
3186         
3187         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENDELETE, sc);
3188         
3189         return OPERATOR_FINISHED;
3190 }
3191
3192 static void SCREEN_OT_delete(wmOperatorType *ot)
3193 {
3194         /* identifiers */
3195         ot->name= "Delete Screen"; //was scene
3196         ot->description= "Delete active screen";
3197         ot->idname= "SCREEN_OT_delete";
3198         
3199         /* api callbacks */
3200         ot->exec= screen_delete_exec;
3201         
3202         /* flags */
3203         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3204 }
3205
3206 /********************* new scene operator *********************/
3207
3208 static int scene_new_exec(bContext *C, wmOperator *op)
3209 {
3210         Scene *newscene, *scene= CTX_data_scene(C);
3211         bScreen *screen= CTX_wm_screen(C);
3212         Main *bmain= CTX_data_main(C);
3213         int type= RNA_enum_get(op->ptr, "type");
3214
3215         if(type == SCE_COPY_NEW) {
3216                 newscene= add_scene("Scene");
3217         }
3218         else { /* different kinds of copying */
3219                 newscene= copy_scene(scene, type);
3220
3221                 /* these can't be handled in blenkernel curently, so do them here */
3222                 if(type == SCE_COPY_LINK_DATA) {
3223                         ED_object_single_users(bmain, newscene, 0);
3224                 }
3225                 else if(type == SCE_COPY_FULL) {
3226                         ED_object_single_users(bmain, newscene, 1);
3227                 }
3228         }
3229         
3230         /* this notifier calls ED_screen_set_scene, doing a lot of UI stuff, not for inside event loops */
3231         WM_event_add_notifier(C, NC_SCENE|ND_SCENEBROWSE, newscene);
3232         
3233         if(screen)
3234                 screen->scene= newscene;
3235         
3236         return OPERATOR_FINISHED;
3237 }
3238
3239 static void SCENE_OT_new(wmOperatorType *ot)
3240 {
3241         static EnumPropertyItem type_items[]= {
3242                 {SCE_COPY_NEW, "NEW", 0, "New", "Add new scene"},
3243                 {SCE_COPY_EMPTY, "EMPTY", 0, "Copy Settings", "Make a copy without any objects"},
3244                 {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene"},
3245                 {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene"},
3246                 {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene"},
3247                 {0, NULL, 0, NULL, NULL}};
3248         
3249         /* identifiers */
3250         ot->name= "New Scene";
3251         ot->description= "Add new scene by type";
3252         ot->idname= "SCENE_OT_new";
3253         
3254         /* api callbacks */
3255         ot->exec= scene_new_exec;
3256         ot->invoke= WM_menu_invoke;
3257         
3258         /* flags */
3259         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3260         
3261         /* properties */
3262         ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
3263 }
3264
3265 /********************* delete scene operator *********************/
3266
3267 static int scene_delete_exec(bContext *C, wmOperator *UNUSED(op))
3268 {
3269         Scene *scene= CTX_data_scene(C);
3270         
3271         WM_event_add_notifier(C, NC_SCENE|NA_REMOVED, scene);
3272         
3273         return OPERATOR_FINISHED;
3274 }
3275
3276 static void SCENE_OT_delete(wmOperatorType *ot)
3277 {
3278         /* identifiers */
3279         ot->name= "Delete Scene";
3280         ot->description= "Delete active scene";
3281         ot->idname= "SCENE_OT_delete";
3282         
3283         /* api callbacks */
3284         ot->exec= scene_delete_exec;
3285         
3286         /* flags */
3287         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
3288 }
3289
3290 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
3291
3292
3293 /* called in spacetypes.c */
3294 void ED_operatortypes_screen(void)
3295 {
3296         /* generic UI stuff */
3297         WM_operatortype_append(SCREEN_OT_actionzone);
3298         WM_operatortype_append(SCREEN_OT_repeat_last);
3299         WM_operatortype_append(SCREEN_OT_repeat_history);
3300         WM_operatortype_append(SCREEN_OT_redo_last);
3301         
3302         /* screen tools */
3303         WM_operatortype_append(SCREEN_OT_area_move);
3304         WM_operatortype_append(SCREEN_OT_area_split);