Fix [#22111] Quad View panes have wrong view when switching between Global/Local...
[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 (ar == scalear)
1330                         continue;
1331                 
1332                 if (scalear->alignment == RGN_ALIGN_TOP && ar->alignment == RGN_ALIGN_BOTTOM)
1333                         dist -= ar->winy;
1334                 else if (scalear->alignment == RGN_ALIGN_BOTTOM && ar->alignment == RGN_ALIGN_TOP)
1335                         dist -= ar->winy;
1336                 else if (scalear->alignment == RGN_ALIGN_LEFT && ar->alignment == RGN_ALIGN_RIGHT)
1337                         dist -= ar->winx;
1338                 else if (scalear->alignment == RGN_ALIGN_RIGHT && ar->alignment == RGN_ALIGN_LEFT)
1339                         dist -= ar->winx;
1340                 
1341                 /* case of regions in regions, like operator properties panel */
1342                 /* these can sit on top of other regions such as headers, so account for this */
1343                 else if (edge == 'b' && scalear->alignment & RGN_ALIGN_TOP && ar->alignment == RGN_ALIGN_TOP && ar->regiontype == RGN_TYPE_HEADER)
1344                         dist -= ar->winy;
1345                 else if (edge == 't' && scalear->alignment & RGN_ALIGN_BOTTOM && ar->alignment == RGN_ALIGN_BOTTOM && ar->regiontype == RGN_TYPE_HEADER)
1346                         dist -= ar->winy;
1347         }
1348
1349         return dist;
1350 }
1351
1352 static int region_scale_invoke(bContext *C, wmOperator *op, wmEvent *event)
1353 {
1354         sActionzoneData *sad= event->customdata;
1355         AZone *az;
1356         
1357         if(event->type!=EVT_ACTIONZONE_REGION) {
1358                 BKE_report(op->reports, RPT_ERROR, "Can only scale region size from an action zone");   
1359                 return OPERATOR_CANCELLED;
1360         }
1361         
1362         az = sad->az;
1363         
1364         if(az->ar) {
1365                 RegionMoveData *rmd= MEM_callocN(sizeof(RegionMoveData), "RegionMoveData");
1366                 int maxsize;
1367                 
1368                 op->customdata= rmd;
1369                 
1370                 rmd->az = az;
1371                 rmd->ar= az->ar;
1372                 rmd->sa = sad->sa1;
1373                 rmd->edge= az->edge;
1374                 rmd->origx= event->x;
1375                 rmd->origy= event->y;
1376                 rmd->maxsize = area_max_regionsize(rmd->sa, rmd->ar, rmd->edge);
1377                 
1378                 /* if not set we do now, otherwise it uses type */
1379                 if(rmd->ar->sizex==0) 
1380                         rmd->ar->sizex= rmd->ar->type->prefsizex;
1381                 if(rmd->ar->sizey==0) 
1382                         rmd->ar->sizey= rmd->ar->type->prefsizey;
1383                 
1384                 /* now copy to regionmovedata */
1385                 if(rmd->edge=='l' || rmd->edge=='r') {
1386                         rmd->origval= rmd->ar->sizex;
1387                 } else {
1388                         rmd->origval= rmd->ar->sizey;
1389                 }
1390                 
1391                 /* limit headers to standard height for now */
1392                 if (rmd->ar->regiontype == RGN_TYPE_HEADER)
1393                         maxsize = rmd->ar->type->prefsizey;
1394                 else
1395                         maxsize = 1000;
1396                 
1397                 CLAMP(rmd->maxsize, 0, maxsize);
1398                 
1399                 /* add temp handler */
1400                 WM_event_add_modal_handler(C, op);
1401                 
1402                 return OPERATOR_RUNNING_MODAL;
1403         }
1404         
1405         return OPERATOR_FINISHED;
1406 }
1407
1408 static int region_scale_modal(bContext *C, wmOperator *op, wmEvent *event)
1409 {
1410         RegionMoveData *rmd= op->customdata;
1411         int delta;
1412         
1413         /* execute the events */
1414         switch(event->type) {
1415                 case MOUSEMOVE:
1416                         
1417                         if(rmd->edge=='l' || rmd->edge=='r') {
1418                                 delta= event->x - rmd->origx;
1419                                 if(rmd->edge=='l') delta= -delta;
1420                                 
1421                                 rmd->ar->sizex= rmd->origval + delta;
1422                                 CLAMP(rmd->ar->sizex, 0, rmd->maxsize);
1423                                 
1424                                 if(rmd->ar->sizex < 24) {
1425                                         rmd->ar->sizex= rmd->origval;
1426                                         if(!(rmd->ar->flag & RGN_FLAG_HIDDEN))
1427                                                 ED_region_toggle_hidden(C, rmd->ar);
1428                                 }
1429                                 else if(rmd->ar->flag & RGN_FLAG_HIDDEN)
1430                                         ED_region_toggle_hidden(C, rmd->ar);
1431                         }
1432                         else {
1433                                 delta= event->y - rmd->origy;
1434                                 if(rmd->edge=='b') delta= -delta;
1435                                 
1436                                 rmd->ar->sizey= rmd->origval + delta;
1437                                 CLAMP(rmd->ar->sizey, 0, rmd->maxsize);
1438                                 
1439                                 if(rmd->ar->sizey < 24) {
1440                                         rmd->ar->sizey= rmd->origval;
1441                                         if(!(rmd->ar->flag & RGN_FLAG_HIDDEN))
1442                                                 ED_region_toggle_hidden(C, rmd->ar);
1443                                 }
1444                                 else if(rmd->ar->flag & RGN_FLAG_HIDDEN)
1445                                         ED_region_toggle_hidden(C, rmd->ar);
1446                         }
1447 #ifdef WM_FAST_DRAW
1448                         ED_area_tag_redraw(rmd->sa);
1449 #endif
1450                         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1451                         
1452                         break;
1453                         
1454                 case LEFTMOUSE:
1455                         if(event->val==KM_RELEASE) {
1456                                 
1457                                 if(ABS(event->x - rmd->origx) < 2 && ABS(event->y - rmd->origy) < 2) {
1458                                         if(rmd->ar->flag & RGN_FLAG_HIDDEN) {
1459                                                 ED_region_toggle_hidden(C, rmd->ar);
1460 #ifdef WM_FAST_DRAW
1461                                                 ED_area_tag_redraw(rmd->sa);
1462 #endif
1463                                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1464                                         }
1465                                 }
1466                                 MEM_freeN(op->customdata);
1467                                 op->customdata = NULL;
1468                                 
1469                                 return OPERATOR_FINISHED;
1470                         }
1471                         break;
1472                         
1473                 case ESCKEY:
1474                         ;
1475         }
1476         
1477         return OPERATOR_RUNNING_MODAL;
1478 }
1479
1480
1481 static void SCREEN_OT_region_scale(wmOperatorType *ot)
1482 {
1483         /* identifiers */
1484         ot->name= "Scale Region Size";
1485         ot->description= "Scale selected area";
1486         ot->idname= "SCREEN_OT_region_scale";
1487         
1488         ot->invoke= region_scale_invoke;
1489         ot->modal= region_scale_modal;
1490         
1491         ot->poll= ED_operator_areaactive;
1492         
1493         ot->flag= OPTYPE_BLOCKING;
1494 }
1495
1496
1497 /* ************** frame change operator ***************************** */
1498
1499 /* function to be called outside UI context, or for redo */
1500 static int frame_offset_exec(bContext *C, wmOperator *op)
1501 {
1502         int delta;
1503         
1504         delta = RNA_int_get(op->ptr, "delta");
1505
1506         CTX_data_scene(C)->r.cfra += delta;
1507         
1508         sound_seek_scene(C);
1509
1510         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1511         
1512         return OPERATOR_FINISHED;
1513 }
1514
1515 static void SCREEN_OT_frame_offset(wmOperatorType *ot)
1516 {
1517         ot->name = "Frame Offset";
1518         ot->idname = "SCREEN_OT_frame_offset";
1519         
1520         ot->exec= frame_offset_exec;
1521         
1522         ot->poll= ED_operator_screenactive;
1523         ot->flag= 0;
1524         
1525         /* rna */
1526         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1527 }
1528
1529
1530 /* function to be called outside UI context, or for redo */
1531 static int frame_jump_exec(bContext *C, wmOperator *op)
1532 {
1533         Scene *scene= CTX_data_scene(C);
1534         
1535         if (RNA_boolean_get(op->ptr, "end"))
1536                 CFRA= PEFRA;
1537         else
1538                 CFRA= PSFRA;
1539         
1540         sound_seek_scene(C);
1541
1542         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
1543         
1544         return OPERATOR_FINISHED;
1545 }
1546
1547 static void SCREEN_OT_frame_jump(wmOperatorType *ot)
1548 {
1549         ot->name = "Jump to Endpoint";
1550         ot->description= "Jump to first/last frame in frame range";
1551         ot->idname = "SCREEN_OT_frame_jump";
1552         
1553         ot->exec= frame_jump_exec;
1554         
1555         ot->poll= ED_operator_screenactive;
1556         ot->flag= 0;
1557         
1558         /* rna */
1559         RNA_def_boolean(ot->srna, "end", 0, "Last Frame", "Jump to the last frame of the frame range.");
1560 }
1561
1562
1563 /* ************** jump to keyframe operator ***************************** */
1564
1565 /* function to be called outside UI context, or for redo */
1566 static int keyframe_jump_exec(bContext *C, wmOperator *op)
1567 {
1568         Scene *scene= CTX_data_scene(C);
1569         Object *ob= CTX_data_active_object(C);
1570         DLRBT_Tree keys;
1571         ActKeyColumn *ak;
1572         float cfra= (scene)? (float)(CFRA) : 0.0f;
1573         short next= RNA_boolean_get(op->ptr, "next");
1574         short done = 0;
1575         
1576         /* sanity checks */
1577         if (scene == NULL)
1578                 return OPERATOR_CANCELLED;
1579         
1580         /* init binarytree-list for getting keyframes */
1581         BLI_dlrbTree_init(&keys);
1582         
1583         /* populate tree with keyframe nodes */
1584         if (scene && scene->adt)
1585                 scene_to_keylist(NULL, scene, &keys, NULL);
1586         if (ob && ob->adt)
1587                 ob_to_keylist(NULL, ob, &keys, NULL);
1588         
1589         /* build linked-list for searching */
1590         BLI_dlrbTree_linkedlist_sync(&keys);
1591         
1592         /* find matching keyframe in the right direction */
1593         do {
1594                 if (next)
1595                         ak= (ActKeyColumn *)BLI_dlrbTree_search_next(&keys, compare_ak_cfraPtr, &cfra);
1596                 else
1597                         ak= (ActKeyColumn *)BLI_dlrbTree_search_prev(&keys, compare_ak_cfraPtr, &cfra);
1598                 
1599                 if (ak) {
1600                         if (CFRA != (int)ak->cfra) {
1601                                 /* this changes the frame, so set the frame and we're done */
1602                                 CFRA= (int)ak->cfra;
1603                                 done = 1;
1604                         }
1605                         else {
1606                                 /* make this the new starting point for the search */
1607                                 cfra = ak->cfra;
1608                         }
1609                 }
1610         } while ((ak != NULL) && (done == 0));
1611         
1612         /* any success? */
1613         if (done == 0)
1614                 BKE_report(op->reports, RPT_INFO, "No more keyframes to jump to in this direction");
1615         
1616         /* free temp stuff */
1617         BLI_dlrbTree_free(&keys);
1618         
1619         sound_seek_scene(C);
1620
1621         WM_event_add_notifier(C, NC_SCENE|ND_FRAME, CTX_data_scene(C));
1622         
1623         return OPERATOR_FINISHED;
1624 }
1625
1626 static void SCREEN_OT_keyframe_jump(wmOperatorType *ot)
1627 {
1628         ot->name = "Jump to Keyframe";
1629         ot->description= "Jump to previous/next keyframe";
1630         ot->idname = "SCREEN_OT_keyframe_jump";
1631         
1632         ot->exec= keyframe_jump_exec;
1633         
1634         ot->poll= ED_operator_screenactive;
1635         ot->flag= 0;
1636         
1637         /* rna */
1638         RNA_def_boolean(ot->srna, "next", 1, "Next Keyframe", "");
1639 }
1640
1641 /* ************** switch screen operator ***************************** */
1642
1643
1644 /* function to be called outside UI context, or for redo */
1645 static int screen_set_exec(bContext *C, wmOperator *op)
1646 {
1647         bScreen *screen= CTX_wm_screen(C);
1648         ScrArea *sa= CTX_wm_area(C);
1649         int tot= BLI_countlist(&CTX_data_main(C)->screen);
1650         int delta= RNA_int_get(op->ptr, "delta");
1651         
1652         /* return to previous state before switching screens */
1653         if(sa && sa->full)
1654                 ED_screen_full_restore(C, sa);
1655         
1656         if(delta==1) {
1657                 while(tot--) {
1658                         screen= screen->id.next;
1659                         if(screen==NULL) screen= CTX_data_main(C)->screen.first;
1660                         if(screen->winid==0 && screen->full==0)
1661                                 break;
1662                 }
1663         }
1664         else if(delta== -1) {
1665                 while(tot--) {
1666                         screen= screen->id.prev;
1667                         if(screen==NULL) screen= CTX_data_main(C)->screen.last;
1668                         if(screen->winid==0 && screen->full==0)
1669                                 break;
1670                 }
1671         }
1672         else {
1673                 screen= NULL;
1674         }
1675         
1676         if(screen) {
1677                 ED_screen_set(C, screen);
1678                 return OPERATOR_FINISHED;
1679         }
1680         return OPERATOR_CANCELLED;
1681 }
1682
1683 static void SCREEN_OT_screen_set(wmOperatorType *ot)
1684 {
1685         ot->name = "Set Screen";
1686         ot->description= "Cycle through available screens";
1687         ot->idname = "SCREEN_OT_screen_set";
1688         
1689         ot->exec= screen_set_exec;
1690         ot->poll= ED_operator_screenactive;
1691         
1692         /* rna */
1693         RNA_def_int(ot->srna, "delta", 0, INT_MIN, INT_MAX, "Delta", "", INT_MIN, INT_MAX);
1694 }
1695
1696 /* ************** screen full-area operator ***************************** */
1697
1698
1699 /* function to be called outside UI context, or for redo */
1700 static int screen_full_area_exec(bContext *C, wmOperator *op)
1701 {
1702         ED_screen_full_toggle(C, CTX_wm_window(C), CTX_wm_area(C));
1703         return OPERATOR_FINISHED;
1704 }
1705
1706 static void SCREEN_OT_screen_full_area(wmOperatorType *ot)
1707 {
1708         ot->name = "Toggle Full Screen";
1709         ot->description= "Toggle display selected area as fullscreen";
1710         ot->idname = "SCREEN_OT_screen_full_area";
1711         
1712         ot->exec= screen_full_area_exec;
1713         ot->poll= ED_operator_areaactive;
1714         ot->flag= 0;
1715         
1716 }
1717
1718
1719
1720 /* ************** join area operator ********************************************** */
1721
1722 /* operator state vars used:  
1723  x1, y1     mouse coord in first area, which will disappear
1724  x2, y2     mouse coord in 2nd area, which will become joined
1725  
1726  functions:
1727  
1728  init()   find edge based on state vars 
1729  test if the edge divides two areas, 
1730  store active and nonactive area,
1731  
1732  apply()  do the actual join
1733  
1734  exit() cleanup, send notifier
1735  
1736  callbacks:
1737  
1738  exec() calls init, apply, exit 
1739  
1740  invoke() sets mouse coords in x,y
1741  call init()
1742  add modal handler
1743  
1744  modal()        accept modal events while doing it
1745  call apply() with active window and nonactive window
1746  call exit() and remove handler when LMB confirm
1747  
1748  */
1749
1750 typedef struct sAreaJoinData
1751         {
1752                 ScrArea *sa1;   /* first area to be considered */
1753                 ScrArea *sa2;   /* second area to be considered */
1754                 ScrArea *scr;   /* designed for removal */
1755                 
1756         } sAreaJoinData;
1757
1758
1759 /* validate selection inside screen, set variables OK */
1760 /* return 0: init failed */
1761 /* XXX todo: find edge based on (x,y) and set other area? */
1762 static int area_join_init(bContext *C, wmOperator *op)
1763 {
1764         ScrArea *sa1, *sa2;
1765         sAreaJoinData* jd= NULL;
1766         int x1, y1;
1767         int x2, y2;
1768         
1769         /* required properties, make negative to get return 0 if not set by caller */
1770         x1= RNA_int_get(op->ptr, "x1");
1771         y1= RNA_int_get(op->ptr, "y1");
1772         x2= RNA_int_get(op->ptr, "x2");
1773         y2= RNA_int_get(op->ptr, "y2");
1774         
1775         sa1 = screen_areahascursor(CTX_wm_screen(C), x1, y1);
1776         sa2 = screen_areahascursor(CTX_wm_screen(C), x2, y2);
1777         if(sa1==NULL || sa2==NULL || sa1==sa2)
1778                 return 0;
1779         
1780         jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_area_join");
1781         
1782         jd->sa1 = sa1;
1783         jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1784         jd->sa2 = sa2;
1785         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1786         
1787         op->customdata= jd;
1788         
1789         return 1;
1790 }
1791
1792 /* apply the join of the areas (space types) */
1793 static int area_join_apply(bContext *C, wmOperator *op)
1794 {
1795         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1796         if (!jd) return 0;
1797         
1798         if(!screen_area_join(C, CTX_wm_screen(C), jd->sa1, jd->sa2)){
1799                 return 0;
1800         }
1801         if (CTX_wm_area(C) == jd->sa2) {
1802                 CTX_wm_area_set(C, NULL);
1803                 CTX_wm_region_set(C, NULL);
1804         }
1805         
1806         return 1;
1807 }
1808
1809 /* finish operation */
1810 static void area_join_exit(bContext *C, wmOperator *op)
1811 {
1812         if (op->customdata) {
1813                 MEM_freeN(op->customdata);
1814                 op->customdata = NULL;
1815         }
1816         
1817         /* this makes sure aligned edges will result in aligned grabbing */
1818         removedouble_scredges(CTX_wm_screen(C));
1819         removenotused_scredges(CTX_wm_screen(C));
1820         removenotused_scrverts(CTX_wm_screen(C));
1821 }
1822
1823 static int area_join_exec(bContext *C, wmOperator *op)
1824 {
1825         if(!area_join_init(C, op)) 
1826                 return OPERATOR_CANCELLED;
1827         
1828         area_join_apply(C, op);
1829         area_join_exit(C, op);
1830         
1831         return OPERATOR_FINISHED;
1832 }
1833
1834 /* interaction callback */
1835 static int area_join_invoke(bContext *C, wmOperator *op, wmEvent *event)
1836 {
1837         
1838         if(event->type==EVT_ACTIONZONE_AREA) {
1839                 sActionzoneData *sad= event->customdata;
1840                 
1841                 if(sad->modifier>0) {
1842                         return OPERATOR_PASS_THROUGH;
1843                 }
1844                 
1845                 /* verify *sad itself */
1846                 if(sad==NULL || sad->sa1==NULL || sad->sa2==NULL)
1847                         return OPERATOR_PASS_THROUGH;
1848                 
1849                 /* is this our *sad? if areas equal it should be passed on */
1850                 if(sad->sa1==sad->sa2)
1851                         return OPERATOR_PASS_THROUGH;
1852                 
1853                 /* prepare operator state vars */
1854                 RNA_int_set(op->ptr, "x1", sad->x);
1855                 RNA_int_set(op->ptr, "y1", sad->y);
1856                 RNA_int_set(op->ptr, "x2", event->x);
1857                 RNA_int_set(op->ptr, "y2", event->y);
1858                 
1859                 if(!area_join_init(C, op)) 
1860                         return OPERATOR_PASS_THROUGH;
1861                 
1862                 /* add temp handler */
1863                 WM_event_add_modal_handler(C, op);
1864                 
1865                 return OPERATOR_RUNNING_MODAL;
1866         }
1867         
1868         return OPERATOR_PASS_THROUGH;
1869 }
1870
1871 static int area_join_cancel(bContext *C, wmOperator *op)
1872 {
1873         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1874         
1875         if (jd->sa1) {
1876                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1877                 jd->sa1->flag &= ~AREA_FLAG_DRAWJOINTO;
1878         }
1879         if (jd->sa2) {
1880                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINFROM;
1881                 jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1882         }
1883         
1884         WM_event_add_notifier(C, NC_WINDOW, NULL);
1885         
1886         area_join_exit(C, op);
1887         
1888         return OPERATOR_CANCELLED;
1889 }
1890
1891 /* modal callback while selecting area (space) that will be removed */
1892 static int area_join_modal(bContext *C, wmOperator *op, wmEvent *event)
1893 {
1894         bScreen *sc= CTX_wm_screen(C);
1895         sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
1896         
1897         /* execute the events */
1898         switch(event->type) {
1899                         
1900                 case MOUSEMOVE: 
1901                 {
1902                         ScrArea *sa = screen_areahascursor(sc, event->x, event->y);
1903                         int dir;
1904                         
1905                         if (sa) {                                       
1906                                 if (jd->sa1 != sa) {
1907                                         dir = area_getorientation(sc, jd->sa1, sa);
1908                                         if (dir >= 0) {
1909                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1910                                                 jd->sa2 = sa;
1911                                                 jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1912                                         } 
1913                                         else {
1914                                                 /* we are not bordering on the previously selected area 
1915                                                  we check if area has common border with the one marked for removal
1916                                                  in this case we can swap areas.
1917                                                  */
1918                                                 dir = area_getorientation(sc, sa, jd->sa2);
1919                                                 if (dir >= 0) {
1920                                                         if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1921                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1922                                                         jd->sa1 = jd->sa2;
1923                                                         jd->sa2 = sa;
1924                                                         if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1925                                                         if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1926                                                 } 
1927                                                 else {
1928                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1929                                                         jd->sa2 = NULL;
1930                                                 }
1931                                         }
1932                                         WM_event_add_notifier(C, NC_WINDOW, NULL);
1933                                 } 
1934                                 else {
1935                                         /* we are back in the area previously selected for keeping 
1936                                          * we swap the areas if possible to allow user to choose */
1937                                         if (jd->sa2 != NULL) {
1938                                                 if (jd->sa1) jd->sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
1939                                                 if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1940                                                 jd->sa1 = jd->sa2;
1941                                                 jd->sa2 = sa;
1942                                                 if (jd->sa1) jd->sa1->flag |= AREA_FLAG_DRAWJOINFROM;
1943                                                 if (jd->sa2) jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1944                                                 dir = area_getorientation(sc, jd->sa1, jd->sa2);
1945                                                 if (dir < 0) {
1946                                                         printf("oops, didn't expect that!\n");
1947                                                 }
1948                                         } 
1949                                         else {
1950                                                 dir = area_getorientation(sc, jd->sa1, sa);
1951                                                 if (dir >= 0) {
1952                                                         if (jd->sa2) jd->sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
1953                                                         jd->sa2 = sa;
1954                                                         jd->sa2->flag |= AREA_FLAG_DRAWJOINTO;
1955                                                 }
1956                                         }
1957                                         WM_event_add_notifier(C, NC_WINDOW, NULL);
1958                                 }
1959                         }
1960                 }
1961                         break;
1962                 case LEFTMOUSE:
1963                         if(event->val==KM_RELEASE) {
1964 #ifdef WM_FAST_DRAW
1965                                 ED_area_tag_redraw(jd->sa1);
1966                                 ED_area_tag_redraw(jd->sa2);
1967 #endif
1968                                 area_join_apply(C, op);
1969                                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
1970                                 area_join_exit(C, op);
1971                                 return OPERATOR_FINISHED;
1972                         }
1973                         break;
1974                         
1975                 case RIGHTMOUSE:
1976                 case ESCKEY:
1977                         return area_join_cancel(C, op);
1978         }
1979         
1980         return OPERATOR_RUNNING_MODAL;
1981 }
1982
1983 /* Operator for joining two areas (space types) */
1984 static void SCREEN_OT_area_join(wmOperatorType *ot)
1985 {
1986         /* identifiers */
1987         ot->name= "Join area";
1988         ot->description= "Join selected areas into new window";
1989         ot->idname= "SCREEN_OT_area_join";
1990         
1991         /* api callbacks */
1992         ot->exec= area_join_exec;
1993         ot->invoke= area_join_invoke;
1994         ot->modal= area_join_modal;
1995         ot->poll= ED_operator_areaactive;
1996         
1997         ot->flag= OPTYPE_BLOCKING;
1998         
1999         /* rna */
2000         RNA_def_int(ot->srna, "x1", -100, INT_MIN, INT_MAX, "X 1", "", INT_MIN, INT_MAX);
2001         RNA_def_int(ot->srna, "y1", -100, INT_MIN, INT_MAX, "Y 1", "", INT_MIN, INT_MAX);
2002         RNA_def_int(ot->srna, "x2", -100, INT_MIN, INT_MAX, "X 2", "", INT_MIN, INT_MAX);
2003         RNA_def_int(ot->srna, "y2", -100, INT_MIN, INT_MAX, "Y 2", "", INT_MIN, INT_MAX);
2004 }
2005
2006 /* ************** repeat last operator ***************************** */
2007
2008 static int repeat_last_exec(bContext *C, wmOperator *op)
2009 {
2010         wmOperator *lastop= CTX_wm_manager(C)->operators.last;
2011         
2012         if(lastop)
2013                 WM_operator_repeat(C, lastop);
2014         
2015         return OPERATOR_CANCELLED;
2016 }
2017
2018 static void SCREEN_OT_repeat_last(wmOperatorType *ot)
2019 {
2020         /* identifiers */
2021         ot->name= "Repeat Last";
2022         ot->description= "Repeat last action";
2023         ot->idname= "SCREEN_OT_repeat_last";
2024         
2025         /* api callbacks */
2026         ot->exec= repeat_last_exec;
2027         
2028         ot->poll= ED_operator_screenactive;
2029         
2030 }
2031
2032 static int repeat_history_invoke(bContext *C, wmOperator *op, wmEvent *event)
2033 {
2034         wmWindowManager *wm= CTX_wm_manager(C);
2035         wmOperator *lastop;
2036         uiPopupMenu *pup;
2037         uiLayout *layout;
2038         int items, i;
2039         
2040         items= BLI_countlist(&wm->operators);
2041         if(items==0)
2042                 return OPERATOR_CANCELLED;
2043         
2044         pup= uiPupMenuBegin(C, op->type->name, 0);
2045         layout= uiPupMenuLayout(pup);
2046         
2047         for (i=items-1, lastop= wm->operators.last; lastop; lastop= lastop->prev, i--)
2048                 uiItemIntO(layout, lastop->type->name, 0, op->type->idname, "index", i);
2049         
2050         uiPupMenuEnd(C, pup);
2051         
2052         return OPERATOR_CANCELLED;
2053 }
2054
2055 static int repeat_history_exec(bContext *C, wmOperator *op)
2056 {
2057         wmWindowManager *wm= CTX_wm_manager(C);
2058         
2059         op= BLI_findlink(&wm->operators, RNA_int_get(op->ptr, "index"));
2060         if(op) {
2061                 /* let's put it as last operator in list */
2062                 BLI_remlink(&wm->operators, op);
2063                 BLI_addtail(&wm->operators, op);
2064                 
2065                 WM_operator_repeat(C, op);
2066         }
2067         
2068         return OPERATOR_FINISHED;
2069 }
2070
2071 static void SCREEN_OT_repeat_history(wmOperatorType *ot)
2072 {
2073         /* identifiers */
2074         ot->name= "Repeat History";
2075         ot->description= "Display menu for previous actions performed";
2076         ot->idname= "SCREEN_OT_repeat_history";
2077         
2078         /* api callbacks */
2079         ot->invoke= repeat_history_invoke;
2080         ot->exec= repeat_history_exec;
2081         
2082         ot->poll= ED_operator_screenactive;
2083         
2084         RNA_def_int(ot->srna, "index", 0, 0, INT_MAX, "Index", "", 0, 1000);
2085 }
2086
2087 /* ********************** redo operator ***************************** */
2088
2089 static int redo_last_invoke(bContext *C, wmOperator *op, wmEvent *event)
2090 {
2091         wmWindowManager *wm= CTX_wm_manager(C);
2092         wmOperator *lastop;
2093         
2094         /* only for operators that are registered and did an undo push */
2095         for(lastop= wm->operators.last; lastop; lastop= lastop->prev)
2096                 if((lastop->type->flag & OPTYPE_REGISTER) && (lastop->type->flag & OPTYPE_UNDO))
2097                         break;
2098         
2099         if(lastop)
2100                 WM_operator_redo_popup(C, lastop);
2101         
2102         return OPERATOR_CANCELLED;
2103 }
2104
2105 static void SCREEN_OT_redo_last(wmOperatorType *ot)
2106 {
2107         /* identifiers */
2108         ot->name= "Redo Last";
2109         ot->description= "Display menu for last action performed";
2110         ot->idname= "SCREEN_OT_redo_last";
2111         
2112         /* api callbacks */
2113         ot->invoke= redo_last_invoke;
2114         
2115         ot->poll= ED_operator_screenactive;
2116 }
2117
2118 /* ************** region four-split operator ***************************** */
2119
2120 /* insert a region in the area region list */
2121 static int region_quadview_exec(bContext *C, wmOperator *op)
2122 {
2123         ARegion *ar= CTX_wm_region(C);
2124         
2125         /* some rules... */
2126         if(ar->regiontype!=RGN_TYPE_WINDOW)
2127                 BKE_report(op->reports, RPT_ERROR, "Only window region can be 4-splitted");
2128         else if(ar->alignment==RGN_ALIGN_QSPLIT) {
2129                 ScrArea *sa= CTX_wm_area(C);
2130                 ARegion *arn;
2131                 
2132                 /* keep current region */
2133                 ar->alignment= 0;
2134                 
2135                 if(sa->spacetype==SPACE_VIEW3D) {
2136                         RegionView3D *rv3d= ar->regiondata;
2137                         rv3d->viewlock= 0;
2138                         rv3d->rflag &= ~RV3D_CLIPPING;
2139                 }
2140                 
2141                 for(ar= sa->regionbase.first; ar; ar= arn) {
2142                         arn= ar->next;
2143                         if(ar->alignment==RGN_ALIGN_QSPLIT) {
2144                                 ED_region_exit(C, ar);
2145                                 BKE_area_region_free(sa->type, ar);
2146                                 BLI_remlink(&sa->regionbase, ar);
2147                                 MEM_freeN(ar);
2148                         }
2149                 }
2150 #ifdef WM_FAST_DRAW
2151                 ED_area_tag_redraw(sa);
2152 #endif
2153                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2154         }
2155         else if(ar->next)
2156                 BKE_report(op->reports, RPT_ERROR, "Only last region can be 4-splitted");
2157         else {
2158                 ScrArea *sa= CTX_wm_area(C);
2159                 ARegion *newar;
2160                 int count;
2161                 
2162                 ar->alignment= RGN_ALIGN_QSPLIT;
2163                 
2164                 for(count=0; count<3; count++) {
2165                         newar= BKE_area_region_copy(sa->type, ar);
2166                         BLI_addtail(&sa->regionbase, newar);
2167                 }
2168                 
2169                 /* lock views and set them */
2170                 if(sa->spacetype==SPACE_VIEW3D) {
2171                         RegionView3D *rv3d;
2172                         
2173                         rv3d= ar->regiondata;
2174                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_FRONT; rv3d->persp= RV3D_ORTHO;
2175                         if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2176                         
2177                         ar= ar->next;
2178                         rv3d= ar->regiondata;
2179                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_TOP; rv3d->persp= RV3D_ORTHO;
2180                         if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2181                         
2182                         ar= ar->next;
2183                         rv3d= ar->regiondata;
2184                         rv3d->viewlock= RV3D_LOCKED; rv3d->view= RV3D_VIEW_RIGHT; rv3d->persp= RV3D_ORTHO;
2185                         if (rv3d->localvd) { rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2186                         
2187                         ar= ar->next;
2188                         rv3d= ar->regiondata;
2189                         rv3d->view= RV3D_VIEW_CAMERA; rv3d->persp= RV3D_CAMOB;
2190                         if (rv3d->localvd) {rv3d->localvd->view = rv3d->view; rv3d->localvd->persp = rv3d->persp; }
2191                 }
2192                 
2193 #ifdef WM_FAST_DRAW
2194                 ED_area_tag_redraw(sa);
2195 #endif
2196                 WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2197         }
2198         
2199         
2200         return OPERATOR_FINISHED;
2201 }
2202
2203 static void SCREEN_OT_region_quadview(wmOperatorType *ot)
2204 {
2205         /* identifiers */
2206         ot->name= "Toggle Quad View";
2207         ot->description= "Split selected area into camera, front, right & top views";
2208         ot->idname= "SCREEN_OT_region_quadview";
2209         
2210         /* api callbacks */
2211         //      ot->invoke= WM_operator_confirm;
2212         ot->exec= region_quadview_exec;
2213         ot->poll= ED_operator_areaactive;
2214         ot->flag= 0;
2215 }
2216
2217
2218
2219 /* ************** region flip operator ***************************** */
2220
2221 /* flip a region alignment */
2222 static int region_flip_exec(bContext *C, wmOperator *op)
2223 {
2224         ARegion *ar= CTX_wm_region(C);
2225         
2226         if (!ar)
2227                 return OPERATOR_CANCELLED;
2228         
2229         if(ar->alignment==RGN_ALIGN_TOP)
2230                 ar->alignment= RGN_ALIGN_BOTTOM;
2231         else if(ar->alignment==RGN_ALIGN_BOTTOM)
2232                 ar->alignment= RGN_ALIGN_TOP;
2233         else if(ar->alignment==RGN_ALIGN_LEFT)
2234                 ar->alignment= RGN_ALIGN_RIGHT;
2235         else if(ar->alignment==RGN_ALIGN_RIGHT)
2236                 ar->alignment= RGN_ALIGN_LEFT;
2237         
2238 #ifdef WM_FAST_DRAW
2239                 ED_area_tag_redraw(CTX_wm_area(C));
2240 #endif
2241         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2242         
2243         return OPERATOR_FINISHED;
2244 }
2245
2246
2247 static void SCREEN_OT_region_flip(wmOperatorType *ot)
2248 {
2249         /* identifiers */
2250         ot->name= "Flip Region";
2251         ot->idname= "SCREEN_OT_region_flip";
2252         
2253         /* api callbacks */
2254         ot->exec= region_flip_exec;
2255         ot->poll= ED_operator_areaactive;
2256         ot->flag= 0;
2257 }
2258
2259 /* ************** header flip operator ***************************** */
2260
2261 /* flip a header region alignment */
2262 static int header_flip_exec(bContext *C, wmOperator *op)
2263 {
2264         ARegion *ar= CTX_wm_region(C);
2265         
2266         /* find the header region 
2267          *      - try context first, but upon failing, search all regions in area...
2268          */
2269         if((ar == NULL) || (ar->regiontype != RGN_TYPE_HEADER)) {
2270                 ScrArea *sa= CTX_wm_area(C);
2271                 
2272                 /* loop over all regions until a matching one is found */
2273                 for (ar= sa->regionbase.first; ar; ar= ar->next) {
2274                         if(ar->regiontype == RGN_TYPE_HEADER)
2275                                 break;
2276                 }
2277                 
2278                 /* don't do anything if no region */
2279                 if(ar == NULL)
2280                         return OPERATOR_CANCELLED;
2281         }       
2282         
2283         /* copied from SCREEN_OT_region_flip */
2284         if(ar->alignment==RGN_ALIGN_TOP)
2285                 ar->alignment= RGN_ALIGN_BOTTOM;
2286         else if(ar->alignment==RGN_ALIGN_BOTTOM)
2287                 ar->alignment= RGN_ALIGN_TOP;
2288         else if(ar->alignment==RGN_ALIGN_LEFT)
2289                 ar->alignment= RGN_ALIGN_RIGHT;
2290         else if(ar->alignment==RGN_ALIGN_RIGHT)
2291                 ar->alignment= RGN_ALIGN_LEFT;
2292         
2293 #ifdef WM_FAST_DRAW
2294         ED_area_tag_redraw(CTX_wm_area(C));
2295 #endif
2296
2297         WM_event_add_notifier(C, NC_SCREEN|NA_EDITED, NULL);
2298         
2299         return OPERATOR_FINISHED;
2300 }
2301
2302
2303 static void SCREEN_OT_header_flip(wmOperatorType *ot)
2304 {
2305         /* identifiers */
2306         ot->name= "Flip Header Region";
2307         ot->idname= "SCREEN_OT_header_flip";
2308         
2309         /* api callbacks */
2310         ot->exec= header_flip_exec;
2311         
2312         ot->poll= ED_operator_areaactive;
2313         ot->flag= 0;
2314 }
2315
2316 /* ************** header tools operator ***************************** */
2317
2318 static int header_toolbox_invoke(bContext *C, wmOperator *op, wmEvent *event)
2319 {
2320         ScrArea *sa= CTX_wm_area(C);
2321         ARegion *ar= CTX_wm_region(C);
2322         uiPopupMenu *pup;
2323         uiLayout *layout;
2324         
2325         pup= uiPupMenuBegin(C, "Header", 0);
2326         layout= uiPupMenuLayout(pup);
2327         
2328         // XXX SCREEN_OT_region_flip doesn't work - gets wrong context for active region, so added custom operator
2329         if (ar->alignment == RGN_ALIGN_TOP)
2330                 uiItemO(layout, "Flip to Bottom", 0, "SCREEN_OT_header_flip");  
2331         else
2332                 uiItemO(layout, "Flip to Top", 0, "SCREEN_OT_header_flip");
2333         
2334         uiItemS(layout);
2335         
2336         /* file browser should be fullscreen all the time, but other regions can be maximised/restored... */
2337         if (sa->spacetype != SPACE_FILE) {
2338                 if (sa->full) 
2339                         uiItemO(layout, "Tile Area", 0, "SCREEN_OT_screen_full_area");
2340                 else
2341                         uiItemO(layout, "Maximize Area", 0, "SCREEN_OT_screen_full_area");
2342         }
2343         
2344         uiPupMenuEnd(C, pup);
2345         
2346         return OPERATOR_CANCELLED;
2347 }
2348
2349 void SCREEN_OT_header_toolbox(wmOperatorType *ot)
2350 {
2351         /* identifiers */
2352         ot->name= "Header Toolbox";
2353         ot->description="Display header region toolbox";
2354         ot->idname= "SCREEN_OT_header_toolbox";
2355         
2356         /* api callbacks */
2357         ot->invoke= header_toolbox_invoke;
2358 }
2359
2360 /* ****************** anim player, with timer ***************** */
2361
2362 static int match_region_with_redraws(int spacetype, int regiontype, int redraws)
2363 {
2364         if(regiontype==RGN_TYPE_WINDOW) {
2365                 
2366                 switch (spacetype) {
2367                         case SPACE_VIEW3D:
2368                                 if(redraws & TIME_ALL_3D_WIN)
2369                                         return 1;
2370                                 break;
2371                         case SPACE_IPO:
2372                         case SPACE_ACTION:
2373                         case SPACE_NLA:
2374                                 if(redraws & TIME_ALL_ANIM_WIN)
2375                                         return 1;
2376                                 break;
2377                         case SPACE_TIME:
2378                                 /* if only 1 window or 3d windows, we do timeline too */
2379                                 if(redraws & (TIME_ALL_ANIM_WIN|TIME_REGION|TIME_ALL_3D_WIN))
2380                                         return 1;
2381                                 break;
2382                         case SPACE_BUTS:
2383                                 if(redraws & TIME_ALL_BUTS_WIN)
2384                                         return 1;
2385                                 break;
2386                         case SPACE_SEQ:
2387                                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2388                                         return 1;
2389                                 break;
2390                         case SPACE_NODE:
2391                                 if(redraws & (TIME_NODES))
2392                                         return 1;
2393                                 break;
2394                         case SPACE_IMAGE:
2395                                 if(redraws & TIME_ALL_IMAGE_WIN)
2396                                         return 1;
2397                                 break;
2398                                 
2399                 }
2400         }
2401         else if(regiontype==RGN_TYPE_UI) {
2402                 if(redraws & TIME_ALL_BUTS_WIN)
2403                         return 1;
2404         }
2405         else if(regiontype==RGN_TYPE_HEADER) {
2406                 if(spacetype==SPACE_TIME)
2407                         return 1;
2408         }
2409         else if (regiontype==RGN_TYPE_PREVIEW) {
2410                 switch (spacetype) {
2411                         case SPACE_SEQ:
2412                                 if(redraws & (TIME_SEQ|TIME_ALL_ANIM_WIN))
2413                                         return 1;
2414                                 break;
2415                 }
2416         }
2417         return 0;
2418 }
2419
2420 static int screen_animation_step(bContext *C, wmOperator *op, wmEvent *event)
2421 {
2422         bScreen *screen= CTX_wm_screen(C);
2423
2424         if(screen->animtimer && screen->animtimer==event->customdata) {
2425                 Scene *scene= CTX_data_scene(C);
2426                 wmTimer *wt= screen->animtimer;
2427                 ScreenAnimData *sad= wt->customdata;
2428                 ScrArea *sa;
2429                 int sync;
2430                 float time;
2431
2432                 /* sync, don't sync, or follow scene setting */
2433                 if(sad->flag & ANIMPLAY_FLAG_SYNC) sync= 1;
2434                 else if(sad->flag & ANIMPLAY_FLAG_NO_SYNC) sync= 0;
2435                 else sync= (scene->flag & SCE_FRAME_DROP);
2436                 
2437                 if((scene->audio.flag & AUDIO_SYNC) && !(sad->flag & ANIMPLAY_FLAG_REVERSE) && finite(time = sound_sync_scene(scene)))
2438                         scene->r.cfra = floor(time * FPS);
2439                 else
2440                 {
2441                         if(sync) {
2442                                 int step = floor(wt->duration * FPS);
2443                                 /* skip frames */
2444                                 if(sad->flag & ANIMPLAY_FLAG_REVERSE)
2445                                         scene->r.cfra -= step;
2446                                 else
2447                                         scene->r.cfra += step;
2448                                 wt->duration -= ((float)step)/FPS;
2449                         }
2450                         else {
2451                                 /* one frame +/- */
2452                                 if(sad->flag & ANIMPLAY_FLAG_REVERSE)
2453                                         scene->r.cfra--;
2454                                 else
2455                                         scene->r.cfra++;
2456                         }
2457                 }
2458                 
2459                 /* reset 'jumped' flag before checking if we need to jump... */
2460                 sad->flag &= ~ANIMPLAY_FLAG_JUMPED;
2461                 
2462                 if (sad->flag & ANIMPLAY_FLAG_REVERSE) {
2463                         /* jump back to end? */
2464                         if (PRVRANGEON) {
2465                                 if (scene->r.cfra < scene->r.psfra) {
2466                                         scene->r.cfra= scene->r.pefra;
2467                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2468                                 }
2469                         }
2470                         else {
2471                                 if (scene->r.cfra < scene->r.sfra) {
2472                                         scene->r.cfra= scene->r.efra;
2473                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2474                                 }
2475                         }
2476                 }
2477                 else {
2478                         /* jump back to start? */
2479                         if (PRVRANGEON) {
2480                                 if (scene->r.cfra > scene->r.pefra) {
2481                                         scene->r.cfra= scene->r.psfra;
2482                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2483                                 }
2484                         }
2485                         else {
2486                                 if (scene->r.cfra > scene->r.efra) {
2487                                         scene->r.cfra= scene->r.sfra;
2488                                         sad->flag |= ANIMPLAY_FLAG_JUMPED;
2489                                 }
2490                         }
2491                 }
2492                 
2493                 if(sad->flag & ANIMPLAY_FLAG_JUMPED)
2494                         sound_seek_scene(C);
2495                 
2496                 /* since we follow drawflags, we can't send notifier but tag regions ourselves */
2497                 ED_update_for_newframe(C, 1);
2498                 
2499                 for(sa= screen->areabase.first; sa; sa= sa->next) {
2500                         ARegion *ar;
2501                         for(ar= sa->regionbase.first; ar; ar= ar->next) {
2502                                 if(ar==sad->ar)
2503                                         ED_region_tag_redraw(ar);
2504                                 else
2505                                         if(match_region_with_redraws(sa->spacetype, ar->regiontype, sad->redraws))
2506                                                 ED_region_tag_redraw(ar);
2507                         }
2508                 }
2509                 
2510                 /* update frame rate info too 
2511                  * NOTE: this may not be accurate enough, since we might need this after modifiers/etc. 
2512                  * have been calculated instead of just before updates have been done?
2513                  */
2514                 ED_refresh_viewport_fps(C);
2515                 
2516                 /* recalculate the timestep for the timer now that we've finished calculating this,
2517                  * since the frames-per-second value may have been changed
2518                  */
2519                 // TODO: this may make evaluation a bit slower if the value doesn't change... any way to avoid this?
2520                 wt->timestep= (1.0/FPS);
2521                 
2522                 return OPERATOR_FINISHED;
2523         }
2524         return OPERATOR_PASS_THROUGH;
2525 }
2526
2527 static void SCREEN_OT_animation_step(wmOperatorType *ot)
2528 {
2529         /* identifiers */
2530         ot->name= "Animation Step";
2531         ot->description= "Step through animation by position";
2532         ot->idname= "SCREEN_OT_animation_step";
2533         
2534         /* api callbacks */
2535         ot->invoke= screen_animation_step;
2536         
2537         ot->poll= ED_operator_screenactive;
2538         
2539 }
2540
2541 /* ****************** anim player, starts or ends timer ***************** */
2542
2543 /* toggle operator */
2544 int ED_screen_animation_play(bContext *C, int sync, int mode)
2545 {
2546         bScreen *screen= CTX_wm_screen(C);
2547         struct Scene* scene = CTX_data_scene(C);
2548
2549         if(screen->animtimer) {
2550                 /* stop playback now */
2551                 ED_screen_animation_timer(C, 0, 0, 0);
2552                 sound_stop_scene(scene);
2553         }
2554         else {
2555                 ScrArea *sa= CTX_wm_area(C);
2556
2557                 if(mode == 1) // XXX only play audio forwards!?
2558                         sound_play_scene(scene);
2559
2560                 /* timeline gets special treatment since it has it's own menu for determining redraws */
2561                 if ((sa) && (sa->spacetype == SPACE_TIME)) {
2562                         SpaceTime *stime= (SpaceTime *)sa->spacedata.first;
2563
2564                         ED_screen_animation_timer(C, stime->redraws, sync, mode);
2565
2566                         /* update region if TIME_REGION was set, to leftmost 3d window */
2567                         ED_screen_animation_timer_update(screen, stime->redraws);
2568                 }
2569                 else {
2570                         int redraws = TIME_REGION|TIME_ALL_3D_WIN;
2571
2572                         /* XXX - would like a better way to deal with this situation - Campbell */
2573                         if((!sa) || (sa->spacetype == SPACE_SEQ)) {
2574                                 redraws |= TIME_SEQ;
2575                         }
2576
2577                         ED_screen_animation_timer(C, redraws, sync, mode);
2578
2579                         if(screen->animtimer) {
2580                                 wmTimer *wt= screen->animtimer;
2581                                 ScreenAnimData *sad= wt->customdata;
2582
2583                                 sad->ar= CTX_wm_region(C);
2584                         }
2585                 }
2586         }
2587
2588         return OPERATOR_FINISHED;
2589 }
2590
2591 static int screen_animation_play_exec(bContext *C, wmOperator *op)
2592 {
2593         int mode= (RNA_boolean_get(op->ptr, "reverse")) ? -1 : 1;
2594         int sync= -1;
2595
2596         if(RNA_property_is_set(op->ptr, "sync"))
2597                 sync= (RNA_boolean_get(op->ptr, "sync"));
2598
2599         return ED_screen_animation_play(C, sync, mode);
2600 }
2601
2602 static void SCREEN_OT_animation_play(wmOperatorType *ot)
2603 {
2604         /* identifiers */
2605         ot->name= "Play Animation";
2606         ot->description= "Play animation";
2607         ot->idname= "SCREEN_OT_animation_play";
2608         
2609         /* api callbacks */
2610         ot->exec= screen_animation_play_exec;
2611         
2612         ot->poll= ED_operator_screenactive;
2613         
2614         RNA_def_boolean(ot->srna, "reverse", 0, "Play in Reverse", "Animation is played backwards");
2615         RNA_def_boolean(ot->srna, "sync", 0, "Sync", "Drop frames to maintain framerate");
2616 }
2617
2618 static int screen_animation_cancel_exec(bContext *C, wmOperator *op)
2619 {
2620         bScreen *screen= CTX_wm_screen(C);
2621         
2622         if(screen->animtimer) {
2623                 ScreenAnimData *sad= screen->animtimer->customdata;
2624                 Scene *scene= CTX_data_scene(C);
2625                 
2626                 /* reset current frame before stopping, and just send a notifier to deal with the rest 
2627                  * (since playback still needs to be stopped)
2628                  */
2629                 scene->r.cfra= sad->sfra;
2630                 WM_event_add_notifier(C, NC_SCENE|ND_FRAME, scene);
2631                 
2632                 /* call the other "toggling" operator to clean up now */
2633                 ED_screen_animation_play(C, 0, 0);
2634         }
2635
2636         return OPERATOR_PASS_THROUGH;
2637 }
2638
2639 static void SCREEN_OT_animation_cancel(wmOperatorType *ot)
2640 {
2641         /* identifiers */
2642         ot->name= "Cancel Animation";
2643         ot->description= "Cancel animation, returning to the original frame";
2644         ot->idname= "SCREEN_OT_animation_cancel";
2645         
2646         /* api callbacks */
2647         ot->exec= screen_animation_cancel_exec;
2648         
2649         ot->poll= ED_operator_screenactive;
2650 }
2651
2652 /* ************** border select operator (template) ***************************** */
2653
2654 /* operator state vars used: (added by default WM callbacks)   
2655  xmin, ymin     
2656  xmax, ymax     
2657  
2658  customdata: the wmGesture pointer
2659  
2660  callbacks:
2661  
2662  exec() has to be filled in by user
2663  
2664  invoke() default WM function
2665  adds modal handler
2666  
2667  modal()        default WM function 
2668  accept modal events while doing it, calls exec(), handles ESC and border drawing
2669  
2670  poll() has to be filled in by user for context
2671  */
2672 #if 0
2673 static int border_select_do(bContext *C, wmOperator *op)
2674 {
2675         int event_type= RNA_int_get(op->ptr, "event_type");
2676         
2677         if(event_type==LEFTMOUSE)
2678                 printf("border select do select\n");
2679         else if(event_type==RIGHTMOUSE)
2680                 printf("border select deselect\n");
2681         else 
2682                 printf("border select do something\n");
2683         
2684         return 1;
2685 }
2686
2687 static void SCREEN_OT_border_select(wmOperatorType *ot)
2688 {
2689         /* identifiers */
2690         ot->name= "Border select";
2691         ot->idname= "SCREEN_OT_border_select";
2692         
2693         /* api callbacks */
2694         ot->exec= border_select_do;
2695         ot->invoke= WM_border_select_invoke;
2696         ot->modal= WM_border_select_modal;
2697         
2698         ot->poll= ED_operator_areaactive;
2699         
2700         /* rna */
2701         RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
2702         RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
2703         RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
2704         RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
2705         RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
2706         
2707 }
2708 #endif
2709
2710 /* *********************** generic fullscreen 'back' button *************** */
2711
2712
2713 static int fullscreen_back_exec(bContext *C, wmOperator *op)
2714 {
2715         bScreen *screen = CTX_wm_screen(C);
2716         ScrArea *sa=NULL;
2717         
2718         /* search current screen for 'fullscreen' areas */
2719         for (sa=screen->areabase.first; sa; sa=sa->next) {
2720                 if (sa->full) break;
2721         }
2722         if (!sa) {
2723                 BKE_report(op->reports, RPT_ERROR, "No fullscreen areas were found.");
2724                 return OPERATOR_CANCELLED;
2725         }
2726         
2727         ED_screen_full_restore(C, sa);
2728         
2729         return OPERATOR_FINISHED;
2730 }
2731
2732 static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot)
2733 {
2734         /* identifiers */
2735         ot->name= "Back to Previous Screen";
2736         ot->description= "Revert back to the original screen layout, before fullscreen area overlay";
2737         ot->idname= "SCREEN_OT_back_to_previous";
2738         
2739         /* api callbacks */
2740         ot->exec= fullscreen_back_exec;
2741         ot->poll= ED_operator_screenactive;
2742 }
2743
2744 /* *********** show user pref window ****** */
2745
2746 static int userpref_show_invoke(bContext *C, wmOperator *unused, wmEvent *event)
2747 {
2748         ScrArea *sa;
2749         rcti rect;
2750         int sizex, sizey;
2751         
2752         sizex= 800;
2753         sizey= 480;
2754         
2755         /* some magic to calculate postition */
2756         rect.xmin= event->x + CTX_wm_window(C)->posx - sizex/2;
2757         rect.ymin= event->y + CTX_wm_window(C)->posy - sizey/2;
2758         rect.xmax= rect.xmin + sizex;
2759         rect.ymax= rect.ymin + sizey;
2760         
2761         /* changes context! */
2762         WM_window_open_temp(C, &rect, WM_WINDOW_USERPREFS);
2763         
2764         sa= CTX_wm_area(C);
2765         
2766         
2767         return OPERATOR_FINISHED;
2768 }
2769
2770
2771 static void SCREEN_OT_userpref_show(struct wmOperatorType *ot)
2772 {
2773         /* identifiers */
2774         ot->name= "Show/Hide User Preferences";
2775         ot->description= "Show/hide user preferences";
2776         ot->idname= "SCREEN_OT_userpref_show";
2777         
2778         /* api callbacks */
2779         ot->invoke= userpref_show_invoke;
2780         ot->poll= ED_operator_screenactive;
2781 }
2782
2783 /********************* new screen operator *********************/
2784
2785 static int screen_new_exec(bContext *C, wmOperator *op)
2786 {
2787         wmWindow *win= CTX_wm_window(C);
2788         bScreen *sc= CTX_wm_screen(C);
2789         
2790         sc= ED_screen_duplicate(win, sc);
2791         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENBROWSE, sc);
2792         
2793         return OPERATOR_FINISHED;
2794 }
2795
2796 void SCREEN_OT_new(wmOperatorType *ot)
2797 {
2798         /* identifiers */
2799         ot->name= "New Screen";
2800         ot->description= "Add a new screen";
2801         ot->idname= "SCREEN_OT_new";
2802         
2803         /* api callbacks */
2804         ot->exec= screen_new_exec;
2805         
2806         /* flags */
2807         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2808 }
2809
2810 /********************* delete screen operator *********************/
2811
2812 static int screen_delete_exec(bContext *C, wmOperator *op)
2813 {
2814         bScreen *sc= CTX_wm_screen(C);
2815         
2816         WM_event_add_notifier(C, NC_SCREEN|ND_SCREENDELETE, sc);
2817         
2818         return OPERATOR_FINISHED;
2819 }
2820
2821 void SCREEN_OT_delete(wmOperatorType *ot)
2822 {
2823         /* identifiers */
2824         ot->name= "Delete Screen"; //was scene
2825         ot->description= "Delete active screen";
2826         ot->idname= "SCREEN_OT_delete";
2827         
2828         /* api callbacks */
2829         ot->exec= screen_delete_exec;
2830         
2831         /* flags */
2832         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2833 }
2834
2835 /********************* new scene operator *********************/
2836
2837 static int scene_new_exec(bContext *C, wmOperator *op)
2838 {
2839         Scene *newscene, *scene= CTX_data_scene(C);
2840         Main *bmain= CTX_data_main(C);
2841         int type= RNA_enum_get(op->ptr, "type");
2842         
2843         newscene= copy_scene(bmain, scene, type);
2844         
2845         /* these can't be handled in blenkernel curently, so do them here */
2846         if(type == SCE_COPY_LINK_DATA)
2847                 ED_object_single_users(newscene, 0);
2848         else if(type == SCE_COPY_FULL)
2849                 ED_object_single_users(newscene, 1);
2850         
2851         WM_event_add_notifier(C, NC_SCENE|ND_SCENEBROWSE, newscene);
2852         
2853         return OPERATOR_FINISHED;
2854 }
2855
2856 void SCENE_OT_new(wmOperatorType *ot)
2857 {
2858         static EnumPropertyItem type_items[]= {
2859                 {SCE_COPY_EMPTY, "EMPTY", 0, "Empty", "Add empty scene"},
2860                 {SCE_COPY_LINK_OB, "LINK_OBJECTS", 0, "Link Objects", "Link to the objects from the current scene"},
2861                 {SCE_COPY_LINK_DATA, "LINK_OBJECT_DATA", 0, "Link Object Data", "Copy objects linked to data from the current scene"},
2862                 {SCE_COPY_FULL, "FULL_COPY", 0, "Full Copy", "Make a full copy of the current scene"},
2863                 {0, NULL, 0, NULL, NULL}};
2864         
2865         /* identifiers */
2866         ot->name= "New Scene";
2867         ot->description= "Add new scene by type";
2868         ot->idname= "SCENE_OT_new";
2869         
2870         /* api callbacks */
2871         ot->exec= scene_new_exec;
2872         ot->invoke= WM_menu_invoke;
2873         
2874         /* flags */
2875         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2876         
2877         /* properties */
2878         ot->prop= RNA_def_enum(ot->srna, "type", type_items, 0, "Type", "");
2879 }
2880
2881 /********************* delete scene operator *********************/
2882
2883 static int scene_delete_exec(bContext *C, wmOperator *op)
2884 {
2885         Scene *scene= CTX_data_scene(C);
2886         
2887         WM_event_add_notifier(C, NC_SCENE|NA_REMOVED, scene);
2888         
2889         return OPERATOR_FINISHED;
2890 }
2891
2892 void SCENE_OT_delete(wmOperatorType *ot)
2893 {
2894         /* identifiers */
2895         ot->name= "Delete Scene";
2896         ot->description= "Delete active scene";
2897         ot->idname= "SCENE_OT_delete";
2898         
2899         /* api callbacks */
2900         ot->exec= scene_delete_exec;
2901         
2902         /* flags */
2903         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2904 }
2905
2906 /* ****************  Assigning operatortypes to global list, adding handlers **************** */
2907
2908 /* called in spacetypes.c */
2909 void ED_operatortypes_screen(void)
2910 {
2911         /* generic UI stuff */
2912         WM_operatortype_append(SCREEN_OT_actionzone);
2913         WM_operatortype_append(SCREEN_OT_repeat_last);
2914         WM_operatortype_append(SCREEN_OT_repeat_history);
2915         WM_operatortype_append(SCREEN_OT_redo_last);
2916         
2917         /* screen tools */
2918         WM_operatortype_append(SCREEN_OT_area_move);
2919         WM_operatortype_append(SCREEN_OT_area_split);
2920         WM_operatortype_append(SCREEN_OT_area_join);
2921         WM_operatortype_append(SCREEN_OT_area_dupli);
2922         WM_operatortype_append(SCREEN_OT_area_swap);
2923         WM_operatortype_append(SCREEN_OT_region_quadview);
2924         WM_operatortype_append(SCREEN_OT_region_scale);
2925         WM_operatortype_append(SCREEN_OT_region_flip);
2926         WM_operatortype_append(SCREEN_OT_header_flip);
2927         WM_operatortype_append(SCREEN_OT_header_toolbox);
2928         WM_operatortype_append(SCREEN_OT_screen_set);
2929         WM_operatortype_append(SCREEN_OT_screen_full_area);
2930         WM_operatortype_append(SCREEN_OT_back_to_previous);
2931         WM_operatortype_append(SCREEN_OT_screenshot);
2932         WM_operatortype_append(SCREEN_OT_screencast);
2933         WM_operatortype_append(SCREEN_OT_userpref_show);
2934         
2935         /*frame changes*/
2936         WM_operatortype_append(SCREEN_OT_frame_offset);
2937         WM_operatortype_append(SCREEN_OT_frame_jump);
2938         WM_operatortype_append(SCREEN_OT_keyframe_jump);
2939         
2940         WM_operatortype_append(SCREEN_OT_animation_step);
2941         WM_operatortype_append(SCREEN_OT_animation_play);
2942         WM_operatortype_append(SCREEN_OT_animation_cancel);
2943         
2944         /* new/delete */
2945         WM_operatortype_append(SCREEN_OT_new);
2946         WM_operatortype_append(SCREEN_OT_delete);
2947         WM_operatortype_append(SCENE_OT_new);
2948         WM_operatortype_append(SCENE_OT_delete);
2949         
2950         /* tools shared by more space types */
2951         WM_operatortype_append(ED_OT_undo);
2952         WM_operatortype_append(ED_OT_redo);     
2953         
2954 }
2955
2956 static void keymap_modal_set(wmKeyConfig *keyconf)
2957 {
2958         static EnumPropertyItem modal_items[] = {
2959                 {KM_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
2960                 {KM_MODAL_APPLY, "APPLY", 0, "Apply", ""},
2961                 {KM_MODAL_STEP10, "STEP10", 0, "Steps on", ""},
2962                 {KM_MODAL_STEP10_OFF, "STEP10_OFF", 0, "Steps off", ""},
2963                 {0, NULL, 0, NULL, NULL}};
2964         wmKeyMap *keymap;
2965         
2966         /* Standard Modal keymap ------------------------------------------------ */
2967         keymap= WM_modalkeymap_add(keyconf, "Standard Modal Map", modal_items);
2968         
2969         WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, KM_MODAL_CANCEL);
2970         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, KM_MODAL_APPLY);
2971         WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
2972         WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, KM_MODAL_APPLY);
2973         
2974         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_PRESS, KM_ANY, 0, KM_MODAL_STEP10);
2975         WM_modalkeymap_add_item(keymap, LEFTCTRLKEY, KM_RELEASE, KM_ANY, 0, KM_MODAL_STEP10_OFF);
2976         
2977         WM_modalkeymap_assign(keymap, "SCREEN_OT_area_move");
2978         
2979 }
2980
2981 /* called in spacetypes.c */
2982 void ED_keymap_screen(wmKeyConfig *keyconf)
2983 {
2984         wmKeyMap *keymap;
2985         
2986         /* Screen Editing ------------------------------------------------ */
2987         keymap= WM_keymap_find(keyconf, "Screen Editing", 0, 0);
2988         
2989         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, 0, 0)->ptr, "modifier", 0);
2990         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "modifier", 1);
2991         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_actionzone", LEFTMOUSE, KM_PRESS, KM_CTRL, 0)->ptr, "modifier", 2);
2992         
2993         /* screen tools */
2994         WM_keymap_verify_item(keymap, "SCREEN_OT_area_split", EVT_ACTIONZONE_AREA, 0, 0, 0);
2995         WM_keymap_verify_item(keymap, "SCREEN_OT_area_join", EVT_ACTIONZONE_AREA, 0, 0, 0);
2996         WM_keymap_verify_item(keymap, "SCREEN_OT_area_dupli", EVT_ACTIONZONE_AREA, 0, KM_SHIFT, 0);
2997         WM_keymap_verify_item(keymap, "SCREEN_OT_area_swap", EVT_ACTIONZONE_AREA, 0, KM_CTRL, 0);
2998         WM_keymap_verify_item(keymap, "SCREEN_OT_region_scale", EVT_ACTIONZONE_REGION, 0, 0, 0);
2999         /* area move after action zones */
3000         WM_keymap_verify_item(keymap, "SCREEN_OT_area_move", LEFTMOUSE, KM_PRESS, 0, 0);
3001         
3002         /* Header Editing ------------------------------------------------ */
3003         keymap= WM_keymap_find(keyconf, "Header", 0, 0);
3004         
3005         WM_keymap_add_item(keymap, "SCREEN_OT_header_toolbox", RIGHTMOUSE, KM_PRESS, 0, 0);
3006         
3007         /* Screen General ------------------------------------------------ */
3008         keymap= WM_keymap_find(keyconf, "Screen", 0, 0);
3009         
3010         /* standard timers */
3011         WM_keymap_add_item(keymap, "SCREEN_OT_animation_step", TIMER0, KM_ANY, KM_ANY, 0);
3012         
3013         
3014         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", RIGHTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", 1);
3015         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_screen_set", LEFTARROWKEY, KM_PRESS, KM_CTRL, 0)->ptr, "delta", -1);
3016         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", UPARROWKEY, KM_PRESS, KM_CTRL, 0);
3017         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", DOWNARROWKEY, KM_PRESS, KM_CTRL, 0);
3018         WM_keymap_add_item(keymap, "SCREEN_OT_screen_full_area", SPACEKEY, KM_PRESS, KM_SHIFT, 0);
3019         WM_keymap_add_item(keymap, "SCREEN_OT_screenshot", F3KEY, KM_PRESS, KM_CTRL, 0);
3020         WM_keymap_add_item(keymap, "SCREEN_OT_screencast", F3KEY, KM_PRESS, KM_ALT, 0);
3021         
3022         /* tests */
3023         WM_keymap_add_item(keymap, "SCREEN_OT_region_quadview", QKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
3024         WM_keymap_verify_item(keymap, "SCREEN_OT_repeat_history", F3KEY, KM_PRESS, 0, 0);
3025         WM_keymap_add_item(keymap, "SCREEN_OT_repeat_last", RKEY, KM_PRESS, KM_SHIFT, 0);
3026         WM_keymap_verify_item(keymap, "SCREEN_OT_region_flip", F5KEY, KM_PRESS, 0, 0);
3027         WM_keymap_verify_item(keymap, "SCREEN_OT_redo_last", F6KEY, KM_PRESS, 0, 0);
3028         WM_keymap_verify_item(keymap, "SCRIPT_OT_reload", F8KEY, KM_PRESS, 0, 0);
3029         
3030         /* files */
3031         WM_keymap_add_item(keymap, "FILE_OT_execute", RETKEY, KM_PRESS, 0, 0);
3032         WM_keymap_add_item(keymap, "FILE_OT_execute", PADENTER, KM_PRESS, 0, 0);
3033         WM_keymap_add_item(keymap, "FILE_OT_cancel", ESCKEY, KM_PRESS, 0, 0);
3034         
3035         /* undo */
3036 #ifdef __APPLE__
3037         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_OSKEY, 0);
3038         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_OSKEY, 0);
3039 #endif
3040         WM_keymap_add_item(keymap, "ED_OT_undo", ZKEY, KM_PRESS, KM_CTRL, 0);
3041         WM_keymap_add_item(keymap, "ED_OT_redo", ZKEY, KM_PRESS, KM_SHIFT|KM_CTRL, 0);
3042         
3043         
3044         /* render */
3045         WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, 0, 0);
3046         RNA_boolean_set(WM_keymap_add_item(keymap, "RENDER_OT_render", F12KEY, KM_PRESS, KM_CTRL, 0)->ptr, "animation", 1);
3047         WM_keymap_add_item(keymap, "RENDER_OT_view_cancel", ESCKEY, KM_PRESS, 0, 0);
3048         WM_keymap_add_item(keymap, "RENDER_OT_view_show", F11KEY, KM_PRESS, 0, 0);
3049         WM_keymap_add_item(keymap, "RENDER_OT_play_rendered_anim", F11KEY, KM_PRESS, KM_CTRL, 0);
3050         
3051         /* user prefs */
3052 #ifdef __APPLE__
3053         WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", COMMAKEY, KM_PRESS, KM_OSKEY, 0);
3054 #endif
3055         WM_keymap_add_item(keymap, "SCREEN_OT_userpref_show", UKEY, KM_PRESS, KM_CTRL|KM_ALT, 0);
3056         
3057         
3058         /* Anim Playback ------------------------------------------------ */
3059         keymap= WM_keymap_find(keyconf, "Frames", 0, 0);
3060         
3061         /* frame offsets */
3062         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", UPARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 10);
3063         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", DOWNARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -10);
3064         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", LEFTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", -1);
3065         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", RIGHTARROWKEY, KM_PRESS, 0, 0)->ptr, "delta", 1);
3066         
3067         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", WHEELDOWNMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "delta", 1);
3068         RNA_int_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_offset", WHEELUPMOUSE, KM_PRESS, KM_ALT, 0)->ptr, "delta", -1);
3069         
3070         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", UPARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 1);
3071         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", DOWNARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 0);
3072         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", RIGHTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 1);
3073         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_frame_jump", LEFTARROWKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "end", 0);
3074         
3075         WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", PAGEUPKEY, KM_PRESS, KM_CTRL, 0);
3076         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_keyframe_jump", PAGEDOWNKEY, KM_PRESS, KM_CTRL, 0)->ptr, "next", 0);
3077         
3078         /* play (forward and backwards) */
3079         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT, 0);
3080         WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", KKEY, KM_PRESS, 0, LKEY);
3081         RNA_boolean_set(WM_keymap_add_item(keymap, "SCREEN_OT_animation_play", AKEY, KM_PRESS, KM_ALT|KM_SHIFT, 0)->ptr, "reverse", 1);
3082         WM_keymap_add_item(keymap, "SCREEN_OT_animation_cancel", ESCKEY, KM_PRESS, 0, 0);
3083         
3084         keymap_modal_set(keyconf);
3085 }
3086