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