Play Back Rendered Animation operator was left out of Screen->Render operator name...
[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                 
2405                 /* sync, don't sync, or follow scene setting */
2406                 if(sad->flag & ANIMPLAY_FLAG_SYNC) sync= 1;
2407                 else if(sad->flag & ANIMPLAY_FLAG_NO_SYNC) sync= 0;
2408                 else sync= (scene->flag & SCE_FRAME_DROP);
2409                 
2410                 if((scene->audio.flag & AUDIO_SYNC) && !(sad->flag & ANIMPLAY_FLAG_REVERSE))
2411                 {
2412                         scene->r.cfra = floor(sound_sync_scene(scene) * FPS);
2413                 }
2414                 else
2415                 {
2416                         if(sync) {
2417                                 int step = floor(wt->duration * FPS);
2418                                 /* skip frames */
2419                                 if(sad->flag & ANIMPLAY_FLAG_REVERSE)
2420                                         scene->r.cfra -= step;
2421                                 else
2422                                         scene->r.cfra += step;
2423                                 wt->duration -= ((float)step)/FPS;
2424                         }
2425                         else {
2426                                 /* one frame +/- */
2427                                 if(sad->flag & ANIMPLAY_FLAG_REVERSE)
2428                                         scene->r.cfra--;
2429                                 else
2430                                         scene->r.cfra++;
2431                         }
2432                 }
2433                 
2434                 /* reset 'jumped' flag before checking if we need to jump... */
2435                 sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
2436                 
2437                 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
2438                         /* jump back to end? */
2439                         if (PRVRANGEON) {
2440                                 if (scene->r.cfra < scene->r.psfra) {
2441                                         scene->r.cfra= scene->r.pefra;
2442                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2443                                 }
2444                         }
2445                         else {
2446                                 if (scene->r.cfra < scene->r.sfra) {
2447                                         scene->r.cfra= scene->r.efra;
2448                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2449                                 }
2450                         }
2451                 }
2452                 else {
2453                         /* jump back to start? */
2454                         if (PRVRANGEON) {
2455                                 if (scene->r.cfra > scene->r.pefra) {
2456                                         scene->r.cfra= scene->r.psfra;
2457                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2458                                 }
2459                         }
2460                         else {
2461                                 if (scene->r.cfra > scene->r.efra) {
2462                                         scene->r.cfra= scene->r.sfra;
2463                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2464                                 }
2465                         }
2466                 }
2467                 
2468                 if(sad->flag & ANIMPLAY_FLAG_JUMPED)
2469                         sound_seek_scene(C);
2470                 
2471                 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2472                 ED_update_for_newframe(C, 1);
2473                 
2474                 for(sa= screen->areabase.first; sa; sa= sa->next) {
2475                         ARegion *ar;
2476                         for(ar= sa->regionbase.first; ar; ar= ar->next) {
2477                                 if(ar==sad->ar)
2478                                         ED_region_tag_redraw(ar);
2479                                 else
2480                                         if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2481                                                 ED_region_tag_redraw(ar);
2482                         }
2483                 }
2484                 
2485                 /* update frame rate info too 
2486                  * NOTE: this may not be accurate enough, since we might need this after modifiers/etc. 
2487                  * have been calculated instead of just before updates have been done?
2488                  */
2489                 ED_refresh_viewport_fps(C);
2490                 
2491                 /* recalculate the timestep for the timer now that we've finished calculating this,
2492                  * since the frames-per-second value may have been changed
2493                  */
2494                 // TODO: this may make evaluation a bit slower if the value doesn't change... any way to avoid this?
2495                 wt->timestep= (1.0/FPS);
2496                 
2497                 return OPERATOR_FINISHED;
2498         }
2499         return OPERATOR_PASS_THROUGH;
2500 }
2501
2502 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2503 {
2504         /* identifiers */
2505         ot->name= "Animation Step";
2506         ot->description= "Step through animation by position";
2507         ot->idname= "SCREEN_OT_animation_step";
2508         
2509         /* api callbacks */
2510         ot->invoke= screen_animation_step;
2511         
2512         ot->poll= ED_operator_screenactive;
2513         
2514 }
2515
2516 /* ****************** anim player, starts or ends timer ***************** */
2517
2518 /* toggle operator */
2519 int ED_screen_animation_play(bContext *C, int sync, int mode)
2520 {
2521         bScreen *screen= CTX_wm_screen(C);
2522         struct Scene* scene = CTX_data_scene(C);
2523
2524         if(screen->animtimer) {
2525                 /* stop playback now */
2526                 ED_screen_animation_timer(C, 0, 0, 0);
2527                 sound_stop_scene(scene);
2528         }
2529         else {
2530                 ScrArea *sa= CTX_wm_area(C);
2531
2532                 if(mode == 1) // XXX only play audio forwards!?
2533                         sound_play_scene(scene);
2534
2535                 /* timeline gets special treatment since it has it's own menu for determining redraws */
2536                 if ((sa) && (sa->spacetype == SPACE_TIME)) {
2537                         SpaceTime *stime= (SpaceTime *)sa->spacedata.first;
2538
2539                         ED_screen_animation_timer(C, stime->redraws, sync, mode);
2540
2541                         /* update region if TIME_REGION was set, to leftmost 3d window */
2542                         ED_screen_animation_timer_update(screen, stime->redraws);
2543                 }
2544                 else {
2545                         int redraws = TIME_REGION|TIME_ALL_3D_WIN;
2546
2547                         /* XXX - would like a better way to deal with this situation - Campbell */
2548                         if((!sa) || (sa->spacetype == SPACE_SEQ)) {
2549                                 redraws |= TIME_SEQ;
2550                         }
2551
2552                         ED_screen_animation_timer(C, redraws, sync, mode);
2553
2554                         if(screen->animtimer) {
2555                                 wmTimer *wt= screen->animtimer;
2556                                 ScreenAnimData *sad= wt->customdata;
2557
2558                                 sad->ar= CTX_wm_region(C);
2559                         }
2560                 }
2561         }
2562
2563         return OPERATOR_FINISHED;
2564 }
2565
2566 static int screen_animation_play_invoke(bContext *C, wmOperator *op, wmEvent *event)
2567 {
2568         int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2569         int sync= -1;
2570
2571         if(RNA_property_is_set(op->ptr, "sync"))
2572                 sync= (RNA_boolean_get(op->ptr, "sync"));
2573
2574         return ED_screen_animation_play(C, sync, mode);
2575 }
2576
2577 static void SCREEN_OT_animation_play(wmOperatorType *ot)
2578 {
2579         /* identifiers */
2580         ot->name= "Play Animation";
2581         ot->description= "Play animation";
2582         ot->idname= "SCREEN_OT_animation_play";
2583         
2584         /* api callbacks */
2585         ot->invoke= screen_animation_play_invoke;
2586         
2587         ot->poll= ED_operator_screenactive;
2588         
2589         RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2590         RNA_def_boolean(ot->srna, "sync", 0, "Sync", "Drop frames to maintain framerate");
2591 }
2592
2593 static int screen_animation_cancel(bContext *C, wmOperator *op, wmEvent *event)
2594 {
2595         bScreen *screen= CTX_wm_screen(C);
2596         
2597         if(screen->animtimer) {
2598                 ScreenAnimData *sad= screen->animtimer->customdata;
2599                 Scene *scene= CTX_data_scene(C);
2600                 
2601                 /* reset current frame before stopping, and just send a notifier to deal with the rest 
2602                  * (since playback still needs to be stopped)
2603                  */
2604                 scene->r.cfra= sad->sfra;
2605                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2606                 
2607                 /* call the other "toggling" operator to clean up now */
2608                 return screen_animation_play_invoke(C, op, event);
2609         }
2610         
2611         return OPERATOR_PASS_THROUGH;
2612 }
2613
2614 static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
2615 {
2616         /* identifiers */
2617         ot->name= "Cancel Animation";
2618         ot->description= "Cancel animation, returning to the original frame";
2619         ot->idname= "SCREEN_OT_animation_cancel";
2620         
2621         /* api callbacks */
2622         ot->invoke= screen_animation_cancel;
2623         
2624         ot->poll= ED_operator_screenactive;
2625 }
2626
2627 /* ************** border select operator (template) ***************************** */
2628
2629 /* operator state vars used: (added by default WM callbacks)   
2630  xmin, ymin     
2631  xmax, ymax     
2632  
2633  customdata: the wmGesture pointer
2634  
2635  callbacks:
2636  
2637  exec() has to be filled in by user
2638  
2639  invoke() default WM function
2640  adds modal handler
2641  
2642  modal()        default WM function 
2643  accept modal events while doing it, calls exec(), handles ESC and border drawing
2644  
2645  poll() has to be filled in by user for context
2646  */
2647 #if 0
2648 static int border_select_do(bContext *C, wmOperator *op)
2649 {
2650         int event_type= RNA_int_get(op->ptr, "event_type");
2651         
2652         if(event_type==LEFTMOUSE)
2653                 printf("border select do select\n");
2654         else if(event_type==RIGHTMOUSE)
2655                 printf("border select deselect\n");
2656         else 
2657                 printf("border select do something\n");
2658         
2659         return 1;
2660 }
2661
2662 static void SCREEN_OT_border_select(wmOperatorType *ot)
2663 {
2664         /* identifiers */
2665         ot->name= "Border select";
2666         ot->idname= "SCREEN_OT_border_select";
2667         
2668         /* api callbacks */
2669         ot->exec= border_select_do;
2670         ot->invoke= WM_border_select_invoke;
2671         ot->modal= WM_border_select_modal;
2672         
2673         ot->poll= ED_operator_areaactive;
2674         
2675         /* rna */
2676         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2677         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2678         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2679         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2680         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2681         
2682 }
2683 #endif
2684
2685 /* *********************** generic fullscreen 'back' button *************** */
2686
2687
2688 static int fullscreen_back_exec(bContext *C, wmOperator *op)
2689 {
2690         bScreen *screen = CTX_wm_screen(C);
2691         ScrArea *sa=NULL;
2692         
2693         /* search current screen for 'fullscreen' areas */
2694         for (sa=screen->areabase.first; sa; sa=sa->next) {
2695                 if (sa->full) break;
2696         }
2697         if (!sa) {
2698                 BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found.");
2699                 return OPERATOR_CANCELLED;
2700         }
2701         
2702         ED_screen_full_restore(C, sa);
2703         
2704         return OPERATOR_FINISHED;
2705 }
2706
2707 static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
2708 {
2709         /* identifiers */
2710         ot->name= "Back to Previous Screen";
2711         ot->description= "Revert back to the original screen layout, before fullscreen area overlay";
2712         ot->idname= "SCREEN_OT_back_to_previous";
2713         
2714         /* api callbacks */
2715         ot->exec= fullscreen_back_exec;
2716         ot->poll= ED_operator_screenactive;
2717 }
2718
2719 /* *********** show user pref window ****** */
2720
2721 static int userpref_show_invoke(bContext *C, wmOperator *unused, wmEvent *event)
2722 {
2723         ScrArea *sa;
2724         rcti rect;
2725         int sizex, sizey;
2726         
2727         sizex= 800;
2728         sizey= 480;
2729         
2730         /* some magic to calculate postition */
2731         rect.xmin= event->x + CTX_wm_window(C)->posx - sizex/2;
2732         rect.ymin= event->y + CTX_wm_window(C)->posy - sizey/2;
2733         rect.xmax= rect.xmin + sizex;
2734         rect.ymax= rect.ymin + sizey;
2735         
2736         /* changes context! */
2737         WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS);
2738         
2739         sa= CTX_wm_area(C);
2740         
2741         
2742         return OPERATOR_FINISHED;
2743 }
2744
2745
2746 static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
2747 {
2748         /* identifiers */
2749         ot->name= "Show/Hide User Preferences";
2750         ot->description= "Show/hide user preferences";
2751         ot->idname= "SCREEN_OT_userpref_show";
2752         
2753         /* api callbacks */
2754         ot->invoke= userpref_show_invoke;
2755         ot->poll= ED_operator_screenactive;
2756 }
2757
2758 /********************* new screen operator *********************/
2759
2760 static int screen_new_exec(bContext *C, wmOperator *op)
2761 {
2762         wmWindow *win= CTX_wm_window(C);
2763         bScreen *sc= CTX_wm_screen(C);
2764         
2765         sc= ED_screen_duplicate(win, sc);
2766         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENBROWSE, sc);
2767         
2768         return OPERATOR_FINISHED;
2769 }
2770
2771 void SCREEN_OT_new(wmOperatorType *ot)
2772 {
2773         /* identifiers */
2774         ot->name= "New Screen";
2775         ot->description= "Add a new screen";
2776         ot->idname= "SCREEN_OT_new";
2777         
2778         /* api callbacks */
2779         ot->exec= screen_new_exec;
2780         
2781         /* flags */
2782         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2783 }
2784
2785 /********************* delete screen operator *********************/
2786
2787 static int screen_delete_exec(bContext *C, wmOperator *op)
2788 {
2789         bScreen *sc= CTX_wm_screen(C);
2790         
2791         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENDELETE, sc);
2792         
2793         return OPERATOR_FINISHED;
2794 }
2795
2796 void SCREEN_OT_delete(wmOperatorType *ot)
2797 {
2798         /* identifiers */
2799         ot->name= "Delete Screen"; //was scene
2800         ot->description= "Delete active screen";
2801         ot->idname= "SCREEN_OT_delete";
2802         
2803         /* api callbacks */
2804         ot->exec= screen_delete_exec;
2805         
2806         /* flags */
2807         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2808 }
2809
2810 /********************* new scene operator *********************/
2811
2812 static int scene_new_exec(bContext *C, wmOperator *op)
2813 {
2814         Scene *newscene, *scene= CTX_data_scene(C);
2815         Main *bmain= CTX_data_main(C);
2816         int type= RNA_enum_get(op->ptr, "type");
2817         
2818         newscene= copy_scene(bmain, scene, type);
2819         
2820         /* these can't be handled in blenkernel curently, so do them here */
2821         if(type == SCE_COPY_LINK_DATA)
2822                 ED_object_single_users(newscene, 0);
2823         else if(type == SCE_COPY_FULL)
2824                 ED_object_single_users(newscene, 1);
2825         
2826         WM_event_add_notifier(C, NC_SCENE|ND_SCENEBROWSE, newscene);
2827         
2828         return OPERATOR_FINISHED;
2829 }
2830
2831 void SCENE_OT_new(wmOperatorType *ot)
2832 {
2833         static EnumPropertyItem type_items[]= {
2834                 {SCE_COPY_EMPTY, "EMPTY", 0, "Empty", "Add empty scene"},
2835                 {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene"},
2836                 {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene"},
2837                 {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene"},
2838                 {0, NULL, 0, NULL, NULL}};
2839         
2840         /* identifiers */
2841         ot->name= "New Scene";
2842         ot->description= "Add new scene by type";
2843         ot->idname= "SCENE_OT_new";
2844         
2845         /* api callbacks */
2846         ot->exec= scene_new_exec;
2847         ot->invoke= WM_menu_invoke;
2848         
2849         /* flags */
2850         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2851         
2852         /* properties */
2853         ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
2854 }
2855
2856 /********************* delete scene operator *********************/
2857
2858 static int scene_delete_exec(bContext *C, wmOperator *op)
2859 {
2860         Scene *scene= CTX_data_scene(C);
2861         
2862         WM_event_add_notifier(C, NC_SCENE|NA_REMOVED, scene);
2863         
2864         return OPERATOR_FINISHED;
2865 }
2866
2867 void SCENE_OT_delete(wmOperatorType *ot)
2868 {
2869         /* identifiers */
2870         ot->name= "Delete Scene";
2871         ot->description= "Delete active scene";
2872         ot->idname= "SCENE_OT_delete";
2873         
2874         /* api callbacks */
2875         ot->exec= scene_delete_exec;
2876         
2877         /* flags */
2878         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2879 }
2880
2881 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
2882
2883 /* called in spacetypes.c */
2884 void ED_operatortypes_screen(void)
2885 {
2886         /* generic UI stuff */
2887         WM_operatortype_append(SCREEN_OT_actionzone);
2888         WM_operatortype_append(SCREEN_OT_repeat_last);
2889         WM_operatortype_append(SCREEN_OT_repeat_history);
2890         WM_operatortype_append(SCREEN_OT_redo_last);
2891         
2892         /* screen tools */
2893         WM_operatortype_append(SCREEN_OT_area_move);
2894         WM_operatortype_append(SCREEN_OT_area_split);
2895         WM_operatortype_append(SCREEN_OT_area_join);
2896         WM_operatortype_append(SCREEN_OT_area_dupli);
2897         WM_operatortype_append(SCREEN_OT_area_swap);
2898         WM_operatortype_append(SCREEN_OT_region_quadview);
2899         WM_operatortype_append(SCREEN_OT_region_scale);
2900         WM_operatortype_append(SCREEN_OT_region_flip);
2901         WM_operatortype_append(SCREEN_OT_header_flip);
2902         WM_operatortype_append(SCREEN_OT_header_toolbox);
2903         WM_operatortype_append(SCREEN_OT_screen_set);
2904         WM_operatortype_append(SCREEN_OT_screen_full_area);
2905         WM_operatortype_append(SCREEN_OT_back_to_previous);
2906         WM_operatortype_append(SCREEN_OT_screenshot);
2907         WM_operatortype_append(SCREEN_OT_screencast);
2908         WM_operatortype_append(SCREEN_OT_userpref_show);
2909         
2910         /*frame changes*/
2911         WM_operatortype_append(SCREEN_OT_frame_offset);
2912         WM_operatortype_append(SCREEN_OT_frame_jump);
2913         WM_operatortype_append(SCREEN_OT_keyframe_jump);
2914         
2915         WM_operatortype_append(SCREEN_OT_animation_step);
2916         WM_operatortype_append(SCREEN_OT_animation_play);
2917         WM_operatortype_append(SCREEN_OT_animation_cancel);
2918         
2919         /* new/delete */
2920         WM_operatortype_append(SCREEN_OT_new);
2921         WM_operatortype_append(SCREEN_OT_delete);
2922         WM_operatortype_append(SCENE_OT_new);
2923         WM_operatortype_append(SCENE_OT_delete);
2924         
2925         /* tools shared by more space types */
2926         WM_operatortype_append(ED_OT_undo);
2927         WM_operatortype_append(ED_OT_redo);     
2928         
2929 }
2930
2931 static void keymap_modal_set(wmKeyConfig *keyconf)
2932 {
2933         static EnumPropertyItem modal_items[] = {
2934                 {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
2935                 {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
2936                 {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""},
2937                 {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""},
2938                 {0, NULL, 0, NULL, NULL}};
2939         wmKeyMap *keymap;
2940         
2941         /* Standard Modal keymap ------------------------------------------------ */
2942         keymap= WM_modalkeymap_add(keyconf, "Standard Modal Map", modal_items);
2943         
2944         WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, KM_MODAL_CANCEL);
2945         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KM_MODAL_APPLY);
2946         WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
2947         WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
2948         
2949         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10);
2950         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF);
2951         
2952         WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
2953         
2954 }
2955
2956 /* called in spacetypes.c */
2957 void ED_keymap_screen(wmKeyConfig *keyconf)
2958 {
2959         wmKeyMap *keymap;
2960         
2961         /* Screen Editing ------------------------------------------------ */
2962         keymap= WM_keymap_find(keyconf, "Screen Editing", 0, 0);
2963         
2964         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
2965         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
2966         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "modifier", 2);
2967         
2968         /* screen tools */
2969         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
2970         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
2971         WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
2972         WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_CTRL, 0);
2973         WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
2974         /* area move after action zones */
2975         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
2976         
2977         /* Header Editing ------------------------------------------------ */
2978         keymap= WM_keymap_find(keyconf, "Header", 0, 0);
2979         
2980         WM_keymap_add_item(keymap, "SCREEN_OT_header_toolbox", RIGHTMOUSE, KM_PRESS, 0, 0);
2981         
2982         /* Screen General ------------------------------------------------ */
2983         keymap= WM_keymap_find(keyconf, "Screen", 0, 0);
2984         
2985         /* standard timers */
2986         WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
2987         
2988         
2989         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
2990         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
2991         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
2992         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
2993         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_SHIFT, 0);
2994         WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
2995         WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
2996         
2997         /* tests */
2998         WM_keymap_add_item(keymap, "SCREEN_OT_region_quadview", QKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
2999         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
3000         WM_keymap_add_item(keymap, "SCREEN_OT_repeat_last", RKEY, KM_PRESS, KM_SHIFT, 0);
3001         WM_keymap_verify_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
3002         WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
3003         WM_keymap_verify_item(keymap, "WM_OT_reload_scripts", F8KEY, KM_PRESS, 0, 0);
3004         
3005         /* files */
3006         WM_keymap_add_item(keymap, "FILE_OT_execute", RETKEY, KM_PRESS, 0, 0);
3007         WM_keymap_add_item(keymap, "FILE_OT_execute", PADENTER, KM_PRESS, 0, 0);
3008         WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
3009         
3010         /* undo */
3011 #ifdef __APPLE__
3012         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
3013         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
3014 #endif
3015         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
3016         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
3017         
3018         
3019         /* render */
3020         WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, 0, 0);
3021         RNA_boolean_set(WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, KM_CTRL, 0)->ptr, "animation", 1);
3022         WM_keymap_add_item(keymap, "RENDER_OT_view_cancel", ESCKEY, KM_PRESS, 0, 0);
3023         WM_keymap_add_item(keymap, "RENDER_OT_view_show", F11KEY, KM_PRESS, 0, 0);
3024         WM_keymap_add_item(keymap, "RENDER_OT_play_rendered_anim", F11KEY, KM_PRESS, KM_CTRL, 0);
3025         
3026         /* user prefs */
3027 #ifdef __APPLE__
3028         WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", COMMAKEY, KM_PRESS, KM_OSKEY, 0);
3029 #endif
3030         WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", UKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
3031         
3032         
3033         /* Anim Playback ------------------------------------------------ */
3034         keymap= WM_keymap_find(keyconf, "Frames", 0, 0);
3035         
3036         /* frame offsets */
3037         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
3038         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
3039         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
3040         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
3041         
3042         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "delta", 1);
3043         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", WHEELUPMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "delta", -1);
3044         
3045         WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0);
3046         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 1);
3047         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 0);
3048         
3049         WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", PAGEUPKEY, KM_PRESS, KM_CTRL, 0);
3050         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", PAGEDOWNKEY, KM_PRESS, KM_CTRL, 0)->ptr, "next", 0);
3051         
3052         /* play (forward and backwards) */
3053         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
3054         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", KKEY, KM_PRESS, 0, LKEY);
3055         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT|KM_SHIFT, 0)->ptr, "reverse", 1);
3056         WM_keymap_add_item(keymap, "SCREEN_OT_animation_cancel", ESCKEY, KM_PRESS, 0, 0);
3057         
3058         keymap_modal_set(keyconf);
3059 }
3060