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