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