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