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