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