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