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