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